Merge mozilla-central to mozilla-autoland. r=merge a=merge
authorTiberius Oros <toros@mozilla.com>
Wed, 06 Dec 2017 12:29:38 +0200
changeset 708664 96f4893daa0f040ad3bfa14df6378a0f8b8d971d
parent 708663 f3ea755aa8c49605a6805c4b8d1d78ae4297343b (current diff)
parent 708198 79d3e25106f8eb369dde6a47199547d131af8d3d (diff)
child 708665 bcd167f66a363105522ce3cc33bd42cf4d7c0574
push id92403
push userVYV03354@nifty.ne.jp
push dateWed, 06 Dec 2017 22:18:41 +0000
reviewersmerge, merge
milestone59.0a1
Merge mozilla-central to mozilla-autoland. r=merge a=merge
dom/base/Element.h
dom/u2f/U2FTransactionChild.cpp
dom/u2f/U2FTransactionChild.h
dom/u2f/U2FTransactionParent.cpp
dom/u2f/U2FTransactionParent.h
dom/webauthn/WebAuthnTransactionChildBase.cpp
dom/webauthn/WebAuthnTransactionChildBase.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -40,14 +40,14 @@ skip-if = buildapp == "mulet"
 [test_invalidationlist.html]
 [test_list.html]
 [test_map.html]
 [test_media.html]
 skip-if = buildapp == "mulet"
 [test_select.html]
 [test_tabbox.xul]
 [test_tabbrowser.xul]
-skip-if = os == 'linux' && debug # Bug 1389365
+skip-if = (os == 'linux' && debug) || (os == 'win' && ccov) # Bug 1389365 || bug 1423218
 [test_table.html]
 [test_tree.xul]
 [test_txtcntr.html]
 [test_txtctrl.html]
 [test_txtctrl.xul]
--- a/browser/components/shell/test/test_headless_screenshot.html
+++ b/browser/components/shell/test/test_headless_screenshot.html
@@ -8,16 +8,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 1378010</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
   Components.utils.import("resource://gre/modules/Services.jsm");
   Components.utils.import("resource://gre/modules/Subprocess.jsm");
   Components.utils.import("resource://gre/modules/osfile.jsm");
 
+  SimpleTest.requestLongerTimeout(2);
+
   const screenshotPath = OS.Path.join(OS.Constants.Path.tmpDir, "headless_test_screenshot.png");
 
   async function runFirefox(args) {
     const Ci = Components.interfaces;
     const XRE_EXECUTABLE_FILE = "XREExeF";
     const firefoxExe = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).path;
     const NS_APP_PREFS_50_FILE = "PrefF";
     const mochiPrefsFile = Services.dirsvc.get(NS_APP_PREFS_50_FILE, Ci.nsIFile);
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 2.0.173
+Current extension version is: 2.0.185
 
-Taken from upstream commit: fffd5cb8
+Taken from upstream commit: f2994736
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -1955,17 +1955,17 @@ function getDocument(src) {
     });
   }).catch(task._capability.reject);
   return task;
 }
 function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
   if (worker.destroyed) {
     return Promise.reject(new Error('Worker was destroyed'));
   }
-  let apiVersion = '2.0.173';
+  let apiVersion = '2.0.185';
   source.disableRange = (0, _dom_utils.getDefaultSetting)('disableRange');
   source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
   source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
@@ -3248,18 +3248,18 @@ var InternalRenderTask = function Intern
         }
       }
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.0.173';
-  exports.build = build = 'fffd5cb8';
+  exports.version = version = '2.0.185';
+  exports.build = build = 'f2994736';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -4622,18 +4622,18 @@ exports.SVGGraphics = SVGGraphics;
 
 /***/ }),
 /* 8 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.173';
-var pdfjsBuild = 'fffd5cb8';
+var pdfjsVersion = '2.0.185';
+var pdfjsBuild = 'f2994736';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(12);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(6);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(5);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(7);
 ;
@@ -7747,18 +7747,18 @@ var _svg = __w_pdfjs_require__(7);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 if (!_global_scope2.default.PDFJS) {
   _global_scope2.default.PDFJS = {};
 }
 var PDFJS = _global_scope2.default.PDFJS;
 {
-  PDFJS.version = '2.0.173';
-  PDFJS.build = 'fffd5cb8';
+  PDFJS.version = '2.0.185';
+  PDFJS.build = 'f2994736';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -20723,18 +20723,18 @@ exports.PostScriptCompiler = PostScriptC
 
 /***/ }),
 /* 18 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.173';
-var pdfjsBuild = 'fffd5cb8';
+var pdfjsVersion = '2.0.185';
+var pdfjsBuild = 'f2994736';
 var pdfjsCoreWorker = __w_pdfjs_require__(19);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 19 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -20919,17 +20919,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.0.173';
+    let workerVersion = '2.0.185';
     if (apiVersion !== null && apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
     var handler = new _util.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -90,17 +90,17 @@ Object.defineProperty(exports, "__esModu
 });
 exports.waitOnEventOrTimeout = exports.WaitOnType = exports.localized = exports.animationStarted = exports.normalizeWheelEventDelta = exports.binarySearchFirstItem = exports.watchScroll = exports.scrollIntoView = exports.getOutputScale = exports.approximateFraction = exports.roundToDivide = exports.getVisibleElements = exports.parseQueryString = exports.noContextMenuHandler = exports.getPDFFileNameFromURL = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.mozL10n = exports.RendererType = exports.PresentationModeState = exports.cloneObj = exports.isValidRotation = exports.VERTICAL_PADDING = exports.SCROLLBAR_PADDING = exports.MAX_AUTO_SCALE = exports.UNKNOWN_SCALE = exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_SCALE = exports.DEFAULT_SCALE_VALUE = exports.CSS_UNITS = undefined;
 
 var _pdfjsLib = __webpack_require__(1);
 
 const CSS_UNITS = 96.0 / 72.0;
 const DEFAULT_SCALE_VALUE = 'auto';
 const DEFAULT_SCALE = 1.0;
-const MIN_SCALE = 0.25;
+const MIN_SCALE = 0.10;
 const MAX_SCALE = 10.0;
 const UNKNOWN_SCALE = 0;
 const MAX_AUTO_SCALE = 1.25;
 const SCROLLBAR_PADDING = 40;
 const VERTICAL_PADDING = 5;
 const PresentationModeState = {
   UNKNOWN: 0,
   NORMAL: 1,
@@ -5294,16 +5294,19 @@ class PDFSidebarResizer {
   _addEventListeners() {
     if (!this.enabled) {
       return;
     }
     let _boundEvents = this._boundEvents;
     _boundEvents.mouseMove = this._mouseMove.bind(this);
     _boundEvents.mouseUp = this._mouseUp.bind(this);
     this.resizer.addEventListener('mousedown', evt => {
+      if (evt.button !== 0) {
+        return;
+      }
       this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS);
       window.addEventListener('mousemove', _boundEvents.mouseMove);
       window.addEventListener('mouseup', _boundEvents.mouseUp);
     });
     this.eventBus.on('sidebarviewchanged', evt => {
       this.sidebarOpen = !!(evt && evt.view);
     });
     this.eventBus.on('resize', evt => {
--- a/browser/locales/l10n-changesets.json
+++ b/browser/locales/l10n-changesets.json
@@ -1,1017 +1,1522 @@
 {
     "ach": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "af": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "an": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ar": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "as": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ast": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "az": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "be": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "bg": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "bn-BD": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "bn-IN": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "br": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "bs": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ca": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "cak": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "cs": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "cy": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "da": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "de": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "dsb": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "el": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "en-GB": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "en-ZA": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "eo": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "es-AR": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "es-CL": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "es-ES": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "es-MX": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "et": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "eu": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "fa": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ff": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "fi": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "fr": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "fy-NL": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ga-IE": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "gd": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "gl": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "gn": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "gu-IN": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "he": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "hi-IN": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "hr": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "hsb": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "hu": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "hy-AM": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ia": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "id": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "is": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "it": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ja": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ja-JP-mac": {
         "platforms": [
-            "macosx64"
+            "macosx64", 
+            "macosx64-devedition"
         ], 
         "revision": "default"
     }, 
     "ka": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "kab": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "kk": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "km": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "kn": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ko": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "lij": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "lo": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "lt": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ltg": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "lv": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "mai": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "mk": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ml": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "mr": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ms": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "my": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "nb-NO": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ne-NP": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "nl": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "nn-NO": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "oc": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "or": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "pa-IN": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "pl": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "pt-BR": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "pt-PT": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "rm": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ro": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ru": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "si": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "sk": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "sl": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "son": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "sq": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "sr": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "sv-SE": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ta": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "te": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "th": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "tl": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "tr": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "uk": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "ur": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "uz": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "vi": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "wo": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "xh": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "zh-CN": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }, 
     "zh-TW": {
         "platforms": [
             "linux", 
+            "linux-devedition", 
             "linux64", 
+            "linux64-devedition", 
             "macosx64", 
+            "macosx64-devedition", 
             "win32", 
-            "win64"
+            "win32-devedition", 
+            "win64", 
+            "win64-devedition"
         ], 
         "revision": "default"
     }
 }
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -50,13 +50,14 @@ mozilla.pth:testing/web-platform
 mozilla.pth:testing/web-platform/tests/tools/wptrunner
 mozilla.pth:testing/web-platform/tests/tools/wptserve
 mozilla.pth:testing/web-platform/tests/tools/six
 mozilla.pth:testing/xpcshell
 mozilla.pth:third_party/python/mock-1.0.0
 mozilla.pth:xpcom/typelib/xpt/tools
 mozilla.pth:tools/docs
 mozilla.pth:media/webrtc/trunk/tools/gyp/pylib
+mozilla.pth:third_party/python/cbor2
 mozilla.pth:third_party/python/pyasn1
 mozilla.pth:third_party/python/pyasn1-modules
 mozilla.pth:third_party/python/rsa
 mozilla.pth:third_party/python/PyECC
 optional:packages.txt:comm/build/virtualenv_packages.txt
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3437,21 +3437,50 @@ nsDocShell::MaybeCreateInitialClientSour
   if (!win) {
     return;
   }
 
   mInitialClientSource =
     ClientManager::CreateSource(ClientType::Window,
                                 win->EventTargetFor(TaskCategory::Other),
                                 principal);
+  if (NS_WARN_IF(!mInitialClientSource)) {
+    return;
+  }
 
   // Mark the initial client as execution ready, but owned by the docshell.
   // If the client is actually used this will cause ClientSource to force
   // the creation of the initial about:blank by calling nsDocShell::GetDocument().
   mInitialClientSource->DocShellExecutionReady(this);
+
+  // Next, check to see if the parent is controlled.
+  nsCOMPtr<nsIDocShell> parent = GetParentDocshell();
+  nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
+  nsPIDOMWindowInner* parentInner =
+    parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
+  if (!parentInner) {
+    return;
+  }
+
+  Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
+  if (controller.isNothing()) {
+    return;
+  }
+
+  // If the parent is controlled then propagate that controller to the
+  // initial about:blank client as well.  This will set the controller
+  // in the ClientManagerService in the parent.
+  RefPtr<ClientHandle> handle =
+    ClientManager::CreateHandle(mInitialClientSource->Info(),
+                                parentInner->EventTargetFor(TaskCategory::Other));
+  handle->Control(controller.ref());
+
+  // Also mark the ClientSource as controlled directly in case script
+  // immediately accesses navigator.serviceWorker.controller.
+  mInitialClientSource->SetController(controller.ref());
 }
 
 Maybe<ClientInfo>
 nsDocShell::GetInitialClientInfo() const
 {
   if (mInitialClientSource) {
     Maybe<ClientInfo> result;
     result.emplace(mInitialClientSource->Info());
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -82,20 +82,17 @@ public:
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   // WebIDL
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // XPCOM GetName() is OK
 
-  void GetValue(nsString& val, nsIPrincipal&)
-  {
-    GetValue(val);
-  }
+  // XPCOM GetValue() is OK
 
   void SetValue(const nsAString& aValue, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aRv);
 
   bool Specified() const;
 
   // XPCOM GetNamespaceURI() is OK
   // XPCOM GetPrefix() is OK
   // XPCOM GetLocalName() is OK
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1116,18 +1116,18 @@ public:
                                           ErrorResult& aError);
   already_AddRefed<Attr> RemoveAttributeNode(Attr& aOldAttr,
                                              ErrorResult& aError);
   Attr* GetAttributeNodeNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
   already_AddRefed<Attr> SetAttributeNodeNS(Attr& aNewAttr,
                                             ErrorResult& aError);
 
-  already_AddRefed<DOMRectList> GetClientRects();
-  already_AddRefed<DOMRect> GetBoundingClientRect();
+  MOZ_CAN_RUN_SCRIPT already_AddRefed<DOMRectList> GetClientRects();
+  MOZ_CAN_RUN_SCRIPT already_AddRefed<DOMRect> GetBoundingClientRect();
 
   // Shadow DOM v1
   already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
                                             ErrorResult& aError);
   ShadowRoot* GetShadowRootByMode() const;
   void SetSlot(const nsAString& aName, ErrorResult& aError);
   void GetSlot(nsAString& aName);
 
@@ -1140,70 +1140,70 @@ public:
     nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
     return slots ? slots->mShadowRoot.get() : nullptr;
   }
 
 private:
   void ScrollIntoView(const ScrollIntoViewOptions &aOptions);
 public:
   void ScrollIntoView(const BooleanOrScrollIntoViewOptions& aObject);
-  void Scroll(double aXScroll, double aYScroll);
-  void Scroll(const ScrollToOptions& aOptions);
-  void ScrollTo(double aXScroll, double aYScroll);
-  void ScrollTo(const ScrollToOptions& aOptions);
-  void ScrollBy(double aXScrollDif, double aYScrollDif);
-  void ScrollBy(const ScrollToOptions& aOptions);
+  MOZ_CAN_RUN_SCRIPT void Scroll(double aXScroll, double aYScroll);
+  MOZ_CAN_RUN_SCRIPT void Scroll(const ScrollToOptions& aOptions);
+  MOZ_CAN_RUN_SCRIPT void ScrollTo(double aXScroll, double aYScroll);
+  MOZ_CAN_RUN_SCRIPT void ScrollTo(const ScrollToOptions& aOptions);
+  MOZ_CAN_RUN_SCRIPT void ScrollBy(double aXScrollDif, double aYScrollDif);
+  MOZ_CAN_RUN_SCRIPT void ScrollBy(const ScrollToOptions& aOptions);
   /* Scrolls without flushing the layout.
    * aDx is the x offset, aDy the y offset in CSS pixels.
    * Returns true if we actually scrolled.
    */
-  bool ScrollByNoFlush(int32_t aDx, int32_t aDy);
-  int32_t ScrollTop();
-  void SetScrollTop(int32_t aScrollTop);
-  int32_t ScrollLeft();
-  void SetScrollLeft(int32_t aScrollLeft);
-  int32_t ScrollWidth();
-  int32_t ScrollHeight();
-  void MozScrollSnap();
-  int32_t ClientTop()
+  MOZ_CAN_RUN_SCRIPT bool ScrollByNoFlush(int32_t aDx, int32_t aDy);
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollTop();
+  MOZ_CAN_RUN_SCRIPT void SetScrollTop(int32_t aScrollTop);
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollLeft();
+  MOZ_CAN_RUN_SCRIPT void SetScrollLeft(int32_t aScrollLeft);
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollWidth();
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollHeight();
+  MOZ_CAN_RUN_SCRIPT void MozScrollSnap();
+  MOZ_CAN_RUN_SCRIPT int32_t ClientTop()
   {
     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().y);
   }
-  int32_t ClientLeft()
+  MOZ_CAN_RUN_SCRIPT int32_t ClientLeft()
   {
     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().x);
   }
-  int32_t ClientWidth()
+  MOZ_CAN_RUN_SCRIPT int32_t ClientWidth()
   {
     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().Width());
   }
-  int32_t ClientHeight()
+  MOZ_CAN_RUN_SCRIPT int32_t ClientHeight()
   {
     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().Height());
   }
-  int32_t ScrollTopMin()
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollTopMin()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     return sf ?
            nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().y) : 0;
   }
-  int32_t ScrollTopMax()
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollTopMax()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     return sf ?
            nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().YMost()) :
            0;
   }
-  int32_t ScrollLeftMin()
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollLeftMin()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     return sf ?
            nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().x) : 0;
   }
-  int32_t ScrollLeftMax()
+  MOZ_CAN_RUN_SCRIPT int32_t ScrollLeftMax()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     return sf ?
            nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().XMost()) :
            0;
   }
 
   void GetGridFragments(nsTArray<RefPtr<Grid>>& aResult);
@@ -1232,20 +1232,16 @@ public:
   // this element.
   void GetAnimations(const AnimationFilter& filter,
                      nsTArray<RefPtr<Animation>>& aAnimations);
   static void GetAnimationsUnsorted(Element* aElement,
                                     CSSPseudoElementType aPseudoType,
                                     nsTArray<RefPtr<Animation>>& aAnimations);
 
   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
-  void GetInnerHTML(nsAString& aInnerHTML, nsIPrincipal& aSubjectPrincipal)
-  {
-    GetInnerHTML(aInnerHTML);
-  }
   virtual void SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
   void GetOuterHTML(nsAString& aOuterHTML);
   void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
   void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
                           ErrorResult& aError);
 
   //----------------------------------------
 
@@ -1584,16 +1580,17 @@ protected:
    * Scroll to a new position using behavior evaluated from CSS and
    * a CSSOM-View DOM method ScrollOptions dictionary.  The scrolling may
    * be performed asynchronously or synchronously depending on the resolved
    * scroll-behavior.
    *
    * @param aScroll       Destination of scroll, in CSS pixels
    * @param aOptions      Dictionary of options to be evaluated
    */
+  MOZ_CAN_RUN_SCRIPT
   void Scroll(const CSSIntPoint& aScroll, const ScrollOptions& aOptions);
 
   /**
    * Convert an attribute string value to attribute type based on the type of
    * attribute.  Called by SetAttr().  Note that at the moment we only do this
    * for attributes in the null namespace (kNameSpaceID_None).
    *
    * @param aNamespaceID the namespace of the attribute to convert
@@ -1824,18 +1821,19 @@ private:
    * called if the NODE_MAY_HAVE_CLASS flag is set.
    */
   const nsAttrValue* DoGetClasses() const;
 
   /**
    * Get this element's client area rect in app units.
    * @return the frame's client area
    */
-  nsRect GetClientAreaRect();
+  MOZ_CAN_RUN_SCRIPT nsRect GetClientAreaRect();
 
+  MOZ_CAN_RUN_SCRIPT
   nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr,
                                      FlushType aFlushType = FlushType::Layout);
 
   // Data members
   EventStates mState;
   // Per-node data managed by Servo.
   //
   // There should not be data on nodes that are in the flattened tree, or
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -435,17 +435,16 @@ Location::GetHref(nsAString& aHref)
   }
 
   AppendUTF8toUTF16(uriString, aHref);
   return NS_OK;
 }
 
 void
 Location::SetHref(const nsAString& aHref,
-                  nsIPrincipal& aSubjectPrincipal,
                   ErrorResult& aRv)
 {
   JSContext *cx = nsContentUtils::GetCurrentJSContext();
   if (cx) {
     aRv = SetHrefWithContext(cx, aHref, false);
     return;
   }
 
--- a/dom/base/Location.h
+++ b/dom/base/Location.h
@@ -64,17 +64,16 @@ public:
       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
       return;
     }
 
     aError = GetHref(aHref);
   }
 
   void SetHref(const nsAString& aHref,
-               nsIPrincipal& aSubjectPrincipal,
                ErrorResult& aError);
 
   void GetOrigin(nsAString& aOrigin,
                  nsIPrincipal& aSubjectPrincipal,
                  ErrorResult& aError);
 
   void GetProtocol(nsAString& aProtocol,
                    nsIPrincipal& aSubjectPrincipal,
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -44,17 +44,16 @@
 #include "mozilla/dom/TCPSocket.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/VRDisplayEvent.h"
 #include "mozilla/dom/VRServiceTest.h"
 #include "mozilla/dom/workers/RuntimeService.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ClearOnShutdown.h"
-#include "mozilla/SSE.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsGlobalWindow.h"
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
@@ -717,22 +716,16 @@ Navigator::HardwareConcurrency()
   workers::RuntimeService* rts = workers::RuntimeService::GetOrCreateService();
   if (!rts) {
     return 1;
   }
 
   return rts->ClampedHardwareConcurrency();
 }
 
-bool
-Navigator::CpuHasSSE2()
-{
-  return mozilla::supports_sse2();
-}
-
 void
 Navigator::RefreshMIMEArray()
 {
   if (mMimeTypes) {
     mMimeTypes->Refresh();
   }
 }
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -166,17 +166,16 @@ public:
   // The XPCOM GetVendor is OK
   // The XPCOM GetVendorSub is OK
   // The XPCOM GetProductSub is OK
   bool CookieEnabled();
   void GetBuildID(nsAString& aBuildID, CallerType aCallerType,
                   ErrorResult& aRv) const;
   bool JavaEnabled(CallerType aCallerType, ErrorResult& aRv);
   uint64_t HardwareConcurrency();
-  bool CpuHasSSE2();
   bool TaintEnabled()
   {
     return false;
   }
   void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
   void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
 
   DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1785,26 +1785,66 @@ nsGlobalWindowInner::EnsureClientSource(
     }
   }
 
   // If we don't have a reserved client or an initial client, then create
   // one now.  This can happen in certain cases where we avoid preallocating
   // the client in the docshell.  This mainly occurs in situations where
   // the principal is not clearly inherited from the parent; e.g. sandboxed
   // iframes, window.open(), etc.
+  // TODO: We may not be marking initial about:blank documents created
+  //       this way as controlled by a service worker properly.  The
+  //       controller should be coming from the same place as the inheritted
+  //       principal.  We do this in docshell, but as mentioned we aren't
+  //       smart enough to handle all cases yet.  For example, a
+  //       window.open() with new URL should inherit the controller from
+  //       the opener, but we probably don't handle that yet.
   if (!mClientSource) {
     mClientSource = ClientManager::CreateSource(ClientType::Window,
                                                 EventTargetFor(TaskCategory::Other),
                                                 mDoc->NodePrincipal());
     if (NS_WARN_IF(!mClientSource)) {
       return NS_ERROR_FAILURE;
     }
     newClientSource = true;
   }
 
+  // The load may have started controlling the Client as well.  If
+  // so, mark it as controlled immediately here.  The actor may
+  // or may not have been notified by the parent side about being
+  // controlled yet.
+  if (loadInfo) {
+    const Maybe<ServiceWorkerDescriptor> controller = loadInfo->GetController();
+    if (controller.isSome()) {
+      mClientSource->SetController(controller.ref());
+    }
+
+    // We also have to handle the case where te initial about:blank is
+    // controlled due to inheritting the service worker from its parent,
+    // but the actual nsIChannel load is not covered by any service worker.
+    // In this case we want the final page to be uncontrolled.  There is
+    // an open spec issue about how exactly this should be handled, but for
+    // now we just force creation of a new ClientSource to clear the
+    // controller.
+    //
+    //  https://github.com/w3c/ServiceWorker/issues/1232
+    //
+    else if (mClientSource->GetController().isSome()) {
+      mClientSource.reset();
+      mClientSource =
+        ClientManager::CreateSource(ClientType::Window,
+                                    EventTargetFor(TaskCategory::Other),
+                                    mDoc->NodePrincipal());
+      if (NS_WARN_IF(!mClientSource)) {
+        return NS_ERROR_FAILURE;
+      }
+      newClientSource = true;
+    }
+  }
+
   // Its possible that we got a client just after being frozen in
   // the bfcache.  In that case freeze the client immediately.
   if (newClientSource && IsFrozen()) {
     mClientSource->Freeze();
   }
 
   return NS_OK;
 }
@@ -2277,16 +2317,22 @@ nsPIDOMWindowInner::SyncStateFromParentW
 }
 
 Maybe<ClientInfo>
 nsPIDOMWindowInner::GetClientInfo() const
 {
   return Move(nsGlobalWindowInner::Cast(this)->GetClientInfo());
 }
 
+Maybe<ServiceWorkerDescriptor>
+nsPIDOMWindowInner::GetController() const
+{
+  return Move(nsGlobalWindowInner::Cast(this)->GetController());
+}
+
 void
 nsGlobalWindowInner::UpdateTopInnerWindow()
 {
   if (IsTopInnerWindow() || !mTopInnerWindow) {
     return;
   }
 
   mTopInnerWindow->UpdateWebSocketCount(-(int32_t)mNumOfOpenWebSockets);
@@ -6113,16 +6159,27 @@ nsGlobalWindowInner::GetClientInfo() con
   MOZ_ASSERT(NS_IsMainThread());
   Maybe<ClientInfo> clientInfo;
   if (mClientSource) {
     clientInfo.emplace(mClientSource->Info());
   }
   return Move(clientInfo);
 }
 
+Maybe<ServiceWorkerDescriptor>
+nsGlobalWindowInner::GetController() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  Maybe<ServiceWorkerDescriptor> controller;
+  if (mClientSource) {
+    controller = mClientSource->GetController();
+  }
+  return Move(controller);
+}
+
 nsresult
 nsGlobalWindowInner::FireDelayedDOMEvents()
 {
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
   }
 
   // Fires an offline status event if the offline status has changed
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -344,16 +344,17 @@ public:
   void Resume();
   virtual bool IsSuspended() const override;
   void Freeze();
   void Thaw();
   virtual bool IsFrozen() const override;
   void SyncStateFromParentWindow();
 
   mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
+  mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
 
   virtual nsresult FireDelayedDOMEvents() override;
 
   virtual nsresult SetNewDocument(nsIDocument *aDocument,
                                   nsISupports *aState,
                                   bool aForceReuseInnerWindow) override;
 
   virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1336,22 +1336,16 @@ public:
   // a way to ask an element whether it's an HTMLShadowElement.
   virtual bool IsHTMLShadowElement() const { return false; }
 
   // Elements named <content> may or may not be HTMLContentElement.  This is a
   // way to ask an element whether it's an HTMLContentElement.
   virtual bool IsHTMLContentElement() const { return false; }
 
   void GetTextContent(nsAString& aTextContent,
-                      nsIPrincipal& aSubjectPrincipal,
-                      mozilla::OOMReporter& aError)
-  {
-    GetTextContentInternal(aTextContent, aError);
-  }
-  void GetTextContent(nsAString& aTextContent,
                       mozilla::OOMReporter& aError)
   {
     GetTextContentInternal(aTextContent, aError);
   }
   void SetTextContent(const nsAString& aTextContent,
                       nsIPrincipal& aSubjectPrincipal,
                       mozilla::ErrorResult& aError)
   {
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -46,16 +46,17 @@ namespace mozilla {
 class ThrottledEventQueue;
 namespace dom {
 class AudioContext;
 class ClientInfo;
 class DocGroup;
 class TabGroup;
 class Element;
 class Performance;
+class ServiceWorkerDescriptor;
 class ServiceWorkerRegistration;
 class Timeout;
 class TimeoutManager;
 class CustomElementRegistry;
 enum class CallerType : uint32_t;
 } // namespace dom
 } // namespace mozilla
 
@@ -321,16 +322,17 @@ public:
   // Increase/Decrease the number of open WebSockets.
   void UpdateWebSocketCount(int32_t aDelta);
 
   // Return true if there are any open WebSockets that could block
   // timeout-throttling.
   bool HasOpenWebSockets() const;
 
   mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
+  mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
 
   mozilla::dom::TabGroup* TabGroup();
 
   virtual nsPIDOMWindowOuter* GetPrivateRoot() = 0;
 
   virtual mozilla::dom::CustomElementRegistry* CustomElements() = 0;
 
   // XXX: This is called on inner windows
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7288,31 +7288,27 @@ def callerTypeGetterForDescriptor(descri
         systemCallerGetter = "nsContentUtils::IsSystemCaller"
     return "%s(cx) ? CallerType::System : CallerType::NonSystem" % systemCallerGetter
 
 class CGCallGenerator(CGThing):
     """
     A class to generate an actual call to a C++ object.  Assumes that the C++
     object is stored in a variable whose name is given by the |object| argument.
 
-    needsSubjectPrincipal is a boolean indicating whether the call should
-    receive the subject nsIPrincipal as argument.
-
     needsCallerType is a boolean indicating whether the call should receive
     a PrincipalType for the caller.
 
     isFallible is a boolean indicating whether the call should be fallible.
 
     resultVar: If the returnType is not void, then the result of the call is
     stored in a C++ variable named by resultVar. The caller is responsible for
     declaring the result variable. If the caller doesn't care about the result
     value, resultVar can be omitted.
     """
-    def __init__(self, isFallible, needsSubjectPrincipal, needsCallerType,
-                 isChromeOnly,
+    def __init__(self, isFallible, needsCallerType, isChromeOnly,
                  arguments, argsPre, returnType, extendedAttributes, descriptor,
                  nativeMethodName, static, object="self", argsPost=[],
                  resultVar=None):
         CGThing.__init__(self)
 
         result, resultOutParam, resultRooter, resultArgs, resultConversion = \
             getRetvalDeclarationForType(returnType, descriptor)
 
@@ -7364,16 +7360,17 @@ class CGCallGenerator(CGThing):
                 needResultDecl = True
                 resultVar = "result"
             if resultOutParam == "ref":
                 args.append(CGGeneric(resultVar))
             else:
                 assert resultOutParam == "ptr"
                 args.append(CGGeneric("&" + resultVar))
 
+        needsSubjectPrincipal = "needsSubjectPrincipal" in extendedAttributes
         if needsSubjectPrincipal:
             args.append(CGGeneric("subjectPrincipal"))
 
         if needsCallerType:
             if isChromeOnly:
                 args.append(CGGeneric("SystemCallerGuarantee()"))
             else:
                 args.append(CGGeneric(callerTypeGetterForDescriptor(descriptor)))
@@ -7881,17 +7878,16 @@ class CGPerSignatureCall(CGThing):
                                                                   idlNode.identifier.name))
             else:
                 cgThings.append(CGIterableMethodGenerator(descriptor,
                                                           idlNode.maplikeOrSetlikeOrIterable,
                                                           idlNode.identifier.name))
         else:
             cgThings.append(CGCallGenerator(
                 self.isFallible(),
-                idlNode.getExtendedAttribute('NeedsSubjectPrincipal'),
                 needsCallerType(idlNode),
                 isChromeOnly(idlNode),
                 self.getArguments(), argsPre, returnType,
                 self.extendedAttributes, descriptor,
                 nativeMethodName,
                 static, argsPost=argsPost, resultVar=resultVar))
 
         if useCounterName:
@@ -9432,17 +9428,18 @@ class CGSpecializedSetter(CGAbstractStat
     """
     def __init__(self, descriptor, attr):
         self.attr = attr
         name = 'set_' + IDLToCIdentifier(attr.identifier.name)
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('%s*' % descriptor.nativeType, 'self'),
                 Argument('JSJitSetterCallArgs', 'args')]
-        CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
+        CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args,
+                                        canRunScript=True)
 
     def definition_body(self):
         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
                                                         self.attr)
         return CGSetterCall(self.attr.type, nativeName, self.descriptor,
                             self.attr).define()
 
     @staticmethod
@@ -14695,17 +14692,17 @@ class CGNativeMember(ClassMethod):
                                  CGUnionStruct.unionTypeDecl(returnType, True),
                                  "aRetVal"))
         elif returnType.isAny():
             args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
         elif returnType.isObject() or returnType.isSpiderMonkeyInterface():
             args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
 
         # And the nsIPrincipal
-        if self.member.getExtendedAttribute('NeedsSubjectPrincipal'):
+        if 'needsSubjectPrincipal' in self.extendedAttrs:
             # Cheat and assume self.descriptorProvider is a descriptor
             if self.descriptorProvider.interface.isExposedInAnyWorker():
                 args.append(Argument("Maybe<nsIPrincipal*>", "aSubjectPrincipal"))
             else:
                 args.append(Argument("nsIPrincipal&", "aPrincipal"))
         # And the caller type, if desired.
         if needsCallerType(self.member):
             args.append(Argument("CallerType", "aCallerType"))
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -595,52 +595,69 @@ class Descriptor(DescriptorProvider):
                 raise TypeError("Unknown value for '%s': %s" % (name, attr[0]))
 
         def ensureValidThrowsExtendedAttribute(attr):
             ensureValidBoolExtendedAttribute(attr, "Throws")
 
         def ensureValidCanOOMExtendedAttribute(attr):
             ensureValidBoolExtendedAttribute(attr, "CanOOM")
 
+        def ensureValidNeedsSubjectPrincipalExtendedAttribute(attr):
+            ensureValidBoolExtendedAttribute(attr, "NeedsSubjectPrincipal")
+
         def maybeAppendInfallibleToAttrs(attrs, throws):
             ensureValidThrowsExtendedAttribute(throws)
             if throws is None:
                 attrs.append("infallible")
 
         def maybeAppendCanOOMToAttrs(attrs, canOOM):
             ensureValidCanOOMExtendedAttribute(canOOM)
             if canOOM is not None:
                 attrs.append("canOOM")
 
+        def maybeAppendNeedsSubjectPrincipalToAttrs(attrs, needsSubjectPrincipal):
+            ensureValidNeedsSubjectPrincipalExtendedAttribute(needsSubjectPrincipal)
+            if needsSubjectPrincipal is not None:
+                attrs.append("needsSubjectPrincipal")
+
         name = member.identifier.name
         throws = self.interface.isJSImplemented() or member.getExtendedAttribute("Throws")
         canOOM = member.getExtendedAttribute("CanOOM")
+        needsSubjectPrincipal = member.getExtendedAttribute("NeedsSubjectPrincipal")
         if member.isMethod():
             # JSObject-returning [NewObject] methods must be fallible,
             # since they have to (fallibly) allocate the new JSObject.
             if (member.getExtendedAttribute("NewObject") and
                 methodReturnsJSObject(member)):
                 throws = True
             attrs = self.extendedAttributes['all'].get(name, [])
             maybeAppendInfallibleToAttrs(attrs, throws)
             maybeAppendCanOOMToAttrs(attrs, canOOM)
+            maybeAppendNeedsSubjectPrincipalToAttrs(attrs,
+                                                    needsSubjectPrincipal)
             return attrs
 
         assert member.isAttr()
         assert bool(getter) != bool(setter)
         key = 'getterOnly' if getter else 'setterOnly'
         attrs = self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, [])
         if throws is None:
             throwsAttr = "GetterThrows" if getter else "SetterThrows"
             throws = member.getExtendedAttribute(throwsAttr)
         maybeAppendInfallibleToAttrs(attrs, throws)
         if canOOM is None:
             canOOMAttr = "GetterCanOOM" if getter else "SetterCanOOM"
             canOOM = member.getExtendedAttribute(canOOMAttr)
         maybeAppendCanOOMToAttrs(attrs, canOOM)
+        if needsSubjectPrincipal is None:
+            needsSubjectPrincipalAttr = (
+                "GetterNeedsSubjectPrincipal" if getter else "SetterNeedsSubjectPrincipal")
+            needsSubjectPrincipal = member.getExtendedAttribute(
+                needsSubjectPrincipalAttr)
+        maybeAppendNeedsSubjectPrincipalToAttrs(attrs, needsSubjectPrincipal)
         return attrs
 
     def supportsIndexedProperties(self):
         return self.operations['IndexedGetter'] is not None
 
     def lengthNeedsCallerType(self):
         """
         Determine whether our length getter needs a caller type; this is needed
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -24,17 +24,17 @@ def generate(output, idlFilename, prepro
     propList = eval(preprocessed)
     props = ""
     for [name, prop, id, flags, pref, proptype] in propList:
         if "CSS_PROPERTY_INTERNAL" in flags:
             continue
         # Unfortunately, even some of the getters here are fallible
         # (e.g. on nsComputedDOMStyle).
         extendedAttrs = ["Throws", "TreatNullAs=EmptyString",
-                         "NeedsSubjectPrincipal"]
+                         "SetterNeedsSubjectPrincipal"]
         if pref is not "":
             extendedAttrs.append('Pref="%s"' % pref)
 
         # webkit properties get a capitalized "WebkitFoo" accessor (added here)
         # as well as a camelcase "webkitFoo" accessor (added next).
         if (prop.startswith("Webkit")):
             props += generateLine(prop, extendedAttrs)
 
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -4145,17 +4145,18 @@ class IDLAttribute(IDLInterfaceMember):
         if self.getExtendedAttribute("CEReactions"):
             if self.readonly:
                 raise WebIDLError("[CEReactions] is not allowed on "
                                   "readonly attributes",
                                   [self.location])
 
     def handleExtendedAttribute(self, attr):
         identifier = attr.identifier()
-        if ((identifier == "SetterThrows" or identifier == "SetterCanOOM")
+        if ((identifier == "SetterThrows" or identifier == "SetterCanOOM" or
+             identifier == "SetterNeedsSubjectPrincipal")
             and self.readonly):
             raise WebIDLError("Readonly attributes must not be flagged as "
                               "[%s]" % identifier,
                               [self.location])
         elif (((identifier == "Throws" or identifier == "GetterThrows" or
                 identifier == "CanOOM" or identifier == "GetterCanOOM") and
                self.getExtendedAttribute("StoreInSlot")) or
               (identifier == "StoreInSlot" and
@@ -4347,16 +4348,18 @@ class IDLAttribute(IDLInterfaceMember):
               identifier == "GetterCanOOM" or
               identifier == "ChromeOnly" or
               identifier == "Func" or
               identifier == "SecureContext" or
               identifier == "Frozen" or
               identifier == "NewObject" or
               identifier == "UnsafeInPrerendering" or
               identifier == "NeedsSubjectPrincipal" or
+              identifier == "SetterNeedsSubjectPrincipal" or
+              identifier == "GetterNeedsSubjectPrincipal" or
               identifier == "NeedsCallerType" or
               identifier == "ReturnValueNeedsContainsHack" or
               identifier == "BinaryName" or
               identifier == "NonEnumerable"):
             # Known attributes that we don't need to do anything with here
             pass
         else:
             raise WebIDLError("Unknown extended attribute %s on attribute" % identifier,
@@ -4983,17 +4986,19 @@ class IDLMethod(IDLInterfaceMember, IDLS
                           "distinguishable" % (argc, self.identifier.name),
                           locations)
 
     def handleExtendedAttribute(self, attr):
         identifier = attr.identifier()
         if (identifier == "GetterThrows" or
             identifier == "SetterThrows" or
             identifier == "GetterCanOOM" or
-            identifier == "SetterCanOOM"):
+            identifier == "SetterCanOOM" or
+            identifier == "SetterNeedsSubjectPrincipal" or
+            identifier == "GetterNeedsSubjectPrincipal"):
             raise WebIDLError("Methods must not be flagged as "
                               "[%s]" % identifier,
                               [attr.location, self.location])
         elif identifier == "Unforgeable":
             if self.isStatic():
                 raise WebIDLError("[Unforgeable] is only allowed on non-static "
                                   "methods", [attr.location, self.location])
             self._unforgeable = True
--- a/dom/clients/manager/ClientChannelHelper.cpp
+++ b/dom/clients/manager/ClientChannelHelper.cpp
@@ -96,26 +96,16 @@ class ClientChannelHelper final : public
         if (reservedClientInfo.isSome()) {
           newLoadInfo->SetReservedClientInfo(reservedClientInfo.ref());
         }
 
         if (initialClientInfo.isSome()) {
           newLoadInfo->SetInitialClientInfo(initialClientInfo.ref());
         }
       }
-
-      // Make sure we keep the service worker controller on same-origin
-      // internal redirects.
-      if (oldLoadInfo != newLoadInfo &&
-          aFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
-        const Maybe<ServiceWorkerDescriptor>& controller = oldLoadInfo->GetController();
-        if (controller.isSome()) {
-          newLoadInfo->SetController(controller.ref());
-        }
-      }
     }
 
     // If it's a cross-origin redirect then we discard the old reserved client
     // and create a new one.
     else {
       // If CheckSameOrigin() worked, then the security manager must exist.
       nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
       MOZ_DIAGNOSTIC_ASSERT(ssm);
@@ -129,16 +119,30 @@ class ClientChannelHelper final : public
       // same-origin security policy.
       reservedClient.reset();
       reservedClient = ClientManager::CreateSource(ClientType::Window,
                                                    mEventTarget, principal);
 
       newLoadInfo->GiveReservedClientSource(Move(reservedClient));
     }
 
+    // Normally we keep the controller across channel redirects, but we must
+    // clear it when a non-subresource load redirects.  Only do this for real
+    // redirects, however.
+    //
+    // There is an open spec question about what to do in this case for
+    // worker script redirects.  For now we clear the controller as that
+    // seems most sane. See:
+    //
+    //  https://github.com/w3c/ServiceWorker/issues/1239
+    //
+    if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
+      newLoadInfo->ClearController();
+    }
+
     nsCOMPtr<nsIChannelEventSink> outerSink = do_GetInterface(mOuter);
     if (outerSink) {
       return outerSink->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags,
                                                aCallback);
     }
 
     aCallback->OnRedirectVerifyCallback(NS_OK);
     return NS_OK;
--- a/dom/clients/manager/ClientHandle.cpp
+++ b/dom/clients/manager/ClientHandle.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientHandle.h"
 
 #include "ClientHandleChild.h"
 #include "ClientHandleOpChild.h"
 #include "ClientManager.h"
 #include "mozilla/dom/PClientManagerChild.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
 
 namespace mozilla {
 namespace dom {
 
 ClientHandle::~ClientHandle()
 {
   Shutdown();
 }
@@ -96,10 +97,30 @@ ClientHandle::ExecutionReady(const Clien
 }
 
 const ClientInfo&
 ClientHandle::Info() const
 {
   return mClientInfo;
 }
 
+RefPtr<GenericPromise>
+ClientHandle::Control(const ServiceWorkerDescriptor& aServiceWorker)
+{
+  RefPtr<GenericPromise::Private> outerPromise =
+    new GenericPromise::Private(__func__);
+
+  RefPtr<ClientOpPromise> innerPromise =
+    StartOp(ClientControlledArgs(aServiceWorker.ToIPC()));
+
+  innerPromise->Then(mSerialEventTarget, __func__,
+    [outerPromise](const ClientOpResult& aResult) {
+      outerPromise->Resolve(true, __func__);
+    },
+    [outerPromise](const ClientOpResult& aResult) {
+      outerPromise->Reject(aResult.get_nsresult(), __func__);
+    });
+
+  return outerPromise.forget();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientHandle.h
+++ b/dom/clients/manager/ClientHandle.h
@@ -4,29 +4,31 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _mozilla_dom_ClientHandle_h
 #define _mozilla_dom_ClientHandle_h
 
 #include "mozilla/dom/ClientInfo.h"
 #include "mozilla/dom/ClientOpPromise.h"
 #include "mozilla/dom/ClientThing.h"
+#include "mozilla/MozPromise.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 namespace mozilla {
 
 namespace dom {
 
 class ClientManager;
 class ClientHandleChild;
 class ClientOpConstructorArgs;
 class PClientManagerChild;
+class ServiceWorkerDescriptor;
 
 // The ClientHandle allows code to take a simple ClientInfo struct and
 // convert it into a live actor-backed object attached to a particular
 // ClientSource somewhere in the browser.  If the ClientSource is
 // destroyed then the ClientHandle will simply begin to reject operations.
 // We do not currently provide a way to be notified when the ClientSource
 // is destroyed, but this could be added in the future.
 class ClientHandle final : public ClientThing<ClientHandleChild>
@@ -57,15 +59,21 @@ class ClientHandle final : public Client
 
   void
   Activate(PClientManagerChild* aActor);
 
 public:
   const ClientInfo&
   Info() const;
 
+  // Mark the ClientSource attached to this handle as controlled by the
+  // given service worker.  The promise will resolve true if the ClientSource
+  // is successfully marked or reject if the operation could not be completed.
+  RefPtr<GenericPromise>
+  Control(const ServiceWorkerDescriptor& aServiceWorker);
+
   NS_INLINE_DECL_REFCOUNTING(ClientHandle);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientHandle_h
--- a/dom/clients/manager/ClientHandleOpParent.cpp
+++ b/dom/clients/manager/ClientHandleOpParent.cpp
@@ -1,23 +1,54 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientHandleOpParent.h"
 
+#include "ClientHandleParent.h"
+#include "ClientSourceParent.h"
+
 namespace mozilla {
 namespace dom {
 
+ClientSourceParent*
+ClientHandleOpParent::GetSource() const
+{
+  auto handle = static_cast<ClientHandleParent*>(Manager());
+  return handle->GetSource();
+}
+
 void
 ClientHandleOpParent::ActorDestroy(ActorDestroyReason aReason)
 {
+  mPromiseRequestHolder.DisconnectIfExists();
 }
 
 void
 ClientHandleOpParent::Init(const ClientOpConstructorArgs& aArgs)
 {
+  ClientSourceParent* source = GetSource();
+  if (!source) {
+    Unused << PClientHandleOpParent::Send__delete__(this, NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  RefPtr<ClientOpPromise> p = source->StartOp(aArgs);
+
+  // Capturing 'this' is safe here because we disconnect the promise in
+  // ActorDestroy() which ensures neither lambda is called if the actor
+  // is destroyed before the source operation completes.
+  p->Then(GetCurrentThreadSerialEventTarget(), __func__,
+    [this] (const ClientOpResult& aResult) {
+      mPromiseRequestHolder.Complete();
+      Unused << PClientHandleOpParent::Send__delete__(this, aResult);
+    },
+    [this] (nsresult aRv) {
+      mPromiseRequestHolder.Complete();
+      Unused << PClientHandleOpParent::Send__delete__(this, aRv);
+    })->Track(mPromiseRequestHolder);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientHandleOpParent.h
+++ b/dom/clients/manager/ClientHandleOpParent.h
@@ -1,23 +1,31 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _mozilla_dom_ClientHandleOpParent_h
 #define _mozilla_dom_ClientHandleOpParent_h
 
+#include "ClientOpPromise.h"
 #include "mozilla/dom/PClientHandleOpParent.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientSourceParent;
+
 class ClientHandleOpParent final : public PClientHandleOpParent
 {
+  MozPromiseRequestHolder<ClientOpPromise> mPromiseRequestHolder;
+
+  ClientSourceParent*
+  GetSource() const;
+
   // PClientHandleOpParent interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
 public:
   ClientHandleOpParent() = default;
   ~ClientHandleOpParent() = default;
 
--- a/dom/clients/manager/ClientIPCTypes.ipdlh
+++ b/dom/clients/manager/ClientIPCTypes.ipdlh
@@ -45,33 +45,53 @@ struct IPCClientWorkerState
 };
 
 union IPCClientState
 {
   IPCClientWindowState;
   IPCClientWorkerState;
 };
 
+struct ClientInfoAndState
+{
+  IPCClientInfo info;
+  IPCClientState state;
+};
+
 struct ClientSourceExecutionReadyArgs
 {
   nsCString url;
   FrameType frameType;
 };
 
+struct ClientControlledArgs
+{
+  IPCServiceWorkerDescriptor serviceWorker;
+};
+
+struct ClientGetInfoAndStateArgs
+{
+  nsID id;
+  PrincipalInfo principalInfo;
+};
+
 struct ClientOpenWindowArgs
 {
 };
 
-struct ClientOpConstructorArgs
+union ClientOpConstructorArgs
 {
+  ClientControlledArgs;
+  ClientGetInfoAndStateArgs;
 };
 
 struct ClientNavigateOpConstructorArgs
 {
 };
 
 union ClientOpResult
 {
   nsresult;
+  ClientInfoAndState;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManager.cpp
+++ b/dom/clients/manager/ClientManager.cpp
@@ -240,10 +240,19 @@ ClientManager::CreateSource(ClientType a
 already_AddRefed<ClientHandle>
 ClientManager::CreateHandle(const ClientInfo& aClientInfo,
                             nsISerialEventTarget* aSerialEventTarget)
 {
   RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
   return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget);
 }
 
+// static
+RefPtr<ClientOpPromise>
+ClientManager::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
+                               nsISerialEventTarget* aSerialEventTarget)
+{
+  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
+  return mgr->StartOp(aArgs, aSerialEventTarget);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManager.h
+++ b/dom/clients/manager/ClientManager.h
@@ -13,16 +13,17 @@ class nsIPrincipal;
 
 namespace mozilla {
 namespace ipc {
 class PBackgroundChild;
 class PrincipalInfo;
 } // namespace ipc
 namespace dom {
 
+class ClientGetInfoAndStateArgs;
 class ClientHandle;
 class ClientInfo;
 class ClientManagerChild;
 class ClientOpConstructorArgs;
 class ClientSource;
 enum class ClientType : uint8_t;
 
 namespace workers {
@@ -32,16 +33,17 @@ class WorkerPrivate;
 // The ClientManager provides a per-thread singleton interface workering
 // with the client subsystem.  It allows globals to create ClientSource
 // objects.  It allows other parts of the system to attach to this globals
 // by creating ClientHandle objects.  The ClientManager also provides
 // methods for querying the list of clients active in the system.
 class ClientManager final : public ClientThing<ClientManagerChild>
 {
   friend class ClientManagerChild;
+  friend class ClientSource;
 
   ClientManager();
   ~ClientManager();
 
   // Utility method to trigger a shutdown of the ClientManager.  This
   // is called in various error conditions or when the last reference
   // is dropped.
   void
@@ -87,15 +89,19 @@ public:
   static UniquePtr<ClientSource>
   CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
                const mozilla::ipc::PrincipalInfo& aPrincipal);
 
   static already_AddRefed<ClientHandle>
   CreateHandle(const ClientInfo& aClientInfo,
                nsISerialEventTarget* aSerialEventTarget);
 
+  static RefPtr<ClientOpPromise>
+  GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
+                  nsISerialEventTarget* aSerialEventTarget);
+
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManager)
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientManager_h
--- a/dom/clients/manager/ClientManagerOpParent.cpp
+++ b/dom/clients/manager/ClientManagerOpParent.cpp
@@ -6,26 +6,61 @@
 
 #include "ClientManagerOpParent.h"
 
 #include "ClientManagerService.h"
 
 namespace mozilla {
 namespace dom {
 
+template <typename Method, typename... Args>
+void
+ClientManagerOpParent::DoServiceOp(Method aMethod, Args&&... aArgs)
+{
+  // Note, we need perfect forarding of the template type in order
+  // to allow already_AddRefed<> to be passed as an arg.
+  RefPtr<ClientOpPromise> p = (mService->*aMethod)(Forward<Args>(aArgs)...);
+
+  // Capturing `this` is safe here because we disconnect the promise in
+  // ActorDestroy() which ensures neither lambda is called if the actor
+  // is destroyed before the source operation completes.
+  p->Then(GetCurrentThreadSerialEventTarget(), __func__,
+    [this] (const mozilla::dom::ClientOpResult& aResult) {
+      mPromiseRequestHolder.Complete();
+      Unused << PClientManagerOpParent::Send__delete__(this, aResult);
+    }, [this] (nsresult aRv) {
+      mPromiseRequestHolder.Complete();
+      Unused << PClientManagerOpParent::Send__delete__(this, aRv);
+    })->Track(mPromiseRequestHolder);
+}
+
 void
 ClientManagerOpParent::ActorDestroy(ActorDestroyReason aReason)
 {
+  mPromiseRequestHolder.DisconnectIfExists();
 }
 
 ClientManagerOpParent::ClientManagerOpParent(ClientManagerService* aService)
   : mService(aService)
 {
   MOZ_DIAGNOSTIC_ASSERT(mService);
 }
 
 void
 ClientManagerOpParent::Init(const ClientOpConstructorArgs& aArgs)
 {
+  switch (aArgs.type()) {
+    case ClientOpConstructorArgs::TClientGetInfoAndStateArgs:
+    {
+      DoServiceOp(&ClientManagerService::GetInfoAndState,
+                  aArgs.get_ClientGetInfoAndStateArgs());
+      break;
+    }
+    default:
+    {
+      MOZ_ASSERT_UNREACHABLE("Unknown Client operation!");
+      break;
+    }
+  }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManagerOpParent.h
+++ b/dom/clients/manager/ClientManagerOpParent.h
@@ -2,25 +2,31 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _mozilla_dom_ClientManagerOpParent_h
 #define _mozilla_dom_ClientManagerOpParent_h
 
 #include "mozilla/dom/PClientManagerOpParent.h"
+#include "ClientOpPromise.h"
 
 namespace mozilla {
 namespace dom {
 
 class ClientManagerService;
 
 class ClientManagerOpParent final : public PClientManagerOpParent
 {
   RefPtr<ClientManagerService> mService;
+  MozPromiseRequestHolder<ClientOpPromise> mPromiseRequestHolder;
+
+  template <typename Method, typename... Args>
+  void
+  DoServiceOp(Method aMethod, Args&&... aArgs);
 
   // PClientManagerOpParent interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
 public:
   explicit ClientManagerOpParent(ClientManagerService* aService);
   ~ClientManagerOpParent() = default;
--- a/dom/clients/manager/ClientManagerService.cpp
+++ b/dom/clients/manager/ClientManagerService.cpp
@@ -285,10 +285,24 @@ void
 ClientManagerService::RemoveManager(ClientManagerParent* aManager)
 {
   AssertIsOnBackgroundThread();
   MOZ_DIAGNOSTIC_ASSERT(aManager);
   DebugOnly<bool> removed = mManagerList.RemoveElement(aManager);
   MOZ_ASSERT(removed);
 }
 
+RefPtr<ClientOpPromise>
+ClientManagerService::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
+{
+  RefPtr<ClientOpPromise> ref;
+
+  ClientSourceParent* source = FindSource(aArgs.id(), aArgs.principalInfo());
+  if (!source || !source->ExecutionReady()) {
+    ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return ref.forget();
+  }
+
+  return source->StartOp(aArgs);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManagerService.h
+++ b/dom/clients/manager/ClientManagerService.h
@@ -1,18 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _mozilla_dom_ClientManagerService_h
 #define _mozilla_dom_ClientManagerService_h
 
-#include "mozilla/ipc/PBackgroundSharedTypes.h"
-#include "mozilla/MozPromise.h"
+#include "ClientOpPromise.h"
 #include "nsDataHashtable.h"
 
 namespace mozilla {
 
 namespace dom {
 
 class ClientManagerParent;
 class ClientSourceParent;
@@ -55,15 +54,18 @@ public:
              const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
 
   void
   AddManager(ClientManagerParent* aManager);
 
   void
   RemoveManager(ClientManagerParent* aManager);
 
+  RefPtr<ClientOpPromise>
+  GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs);
+
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManagerService)
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientManagerService_h
--- a/dom/clients/manager/ClientSource.cpp
+++ b/dom/clients/manager/ClientSource.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientSource.h"
 
 #include "ClientManager.h"
 #include "ClientManagerChild.h"
 #include "ClientSourceChild.h"
+#include "ClientState.h"
 #include "ClientValidation.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "nsIDocShell.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
@@ -49,16 +50,47 @@ ClientSource::ExecutionReady(const Clien
 
   mClientInfo.SetURL(aArgs.url());
   mClientInfo.SetFrameType(aArgs.frameType());
   MaybeExecute([aArgs](PClientSourceChild* aActor) {
     aActor->SendExecutionReady(aArgs);
   });
 }
 
+nsresult
+ClientSource::SnapshotWindowState(ClientState* aStateOut)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsPIDOMWindowInner* window = GetInnerWindow();
+  if (!window || !window->IsCurrentInnerWindow() ||
+      !window->HasActiveDocument()) {
+    *aStateOut = ClientState(ClientWindowState(VisibilityState::Hidden,
+                                               TimeStamp(), false));
+    return NS_OK;
+  }
+
+  nsIDocument* doc = window->GetExtantDoc();
+  if (NS_WARN_IF(!doc)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  ErrorResult rv;
+  bool focused = doc->HasFocus(rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    rv.SuppressException();
+    return rv.StealNSResult();
+  }
+
+  *aStateOut = ClientState(ClientWindowState(doc->VisibilityState(),
+                                             doc->LastFocusTime(), focused));
+
+  return NS_OK;
+}
+
 WorkerPrivate*
 ClientSource::GetWorkerPrivate() const
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
   if (!mOwner.is<WorkerPrivate*>()) {
     return nullptr;
   }
   return mOwner.as<WorkerPrivate*>();
@@ -69,16 +101,28 @@ ClientSource::GetDocShell() const
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
   if (!mOwner.is<nsCOMPtr<nsIDocShell>>()) {
     return nullptr;
   }
   return mOwner.as<nsCOMPtr<nsIDocShell>>();
 }
 
+void
+ClientSource::MaybeCreateInitialDocument()
+{
+  nsIDocShell* docshell = GetDocShell();
+  if (docshell) {
+    // Force the create of the initial document if it does not exist yet.
+    Unused << docshell->GetDocument();
+
+    MOZ_DIAGNOSTIC_ASSERT(GetInnerWindow());
+  }
+}
+
 ClientSource::ClientSource(ClientManager* aManager,
                            nsISerialEventTarget* aEventTarget,
                            const ClientSourceConstructorArgs& aArgs)
   : mManager(aManager)
   , mEventTarget(aEventTarget)
   , mOwner(AsVariant(Nothing()))
   , mClientInfo(aArgs.id(), aArgs.type(), aArgs.principalInfo(), aArgs.creationTime())
 {
@@ -252,16 +296,94 @@ ClientSource::Thaw()
 }
 
 const ClientInfo&
 ClientSource::Info() const
 {
   return mClientInfo;
 }
 
+void
+ClientSource::WorkerSyncPing(WorkerPrivate* aWorkerPrivate)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+  MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
+  MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate == mManager->GetWorkerPrivate());
+  aWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_DIAGNOSTIC_ASSERT(GetActor());
+  GetActor()->SendWorkerSyncPing();
+}
+
+void
+ClientSource::SetController(const ServiceWorkerDescriptor& aServiceWorker)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+
+  if (mController.isSome() && mController.ref() == aServiceWorker) {
+    return;
+  }
+
+  mController.reset();
+  mController.emplace(aServiceWorker);
+}
+
+RefPtr<ClientOpPromise>
+ClientSource::Control(const ClientControlledArgs& aArgs)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+
+  SetController(ServiceWorkerDescriptor(aArgs.serviceWorker()));
+
+  RefPtr<ClientOpPromise> ref =
+    ClientOpPromise::CreateAndResolve(NS_OK, __func__);
+  return ref.forget();
+}
+
+const Maybe<ServiceWorkerDescriptor>&
+ClientSource::GetController() const
+{
+  return mController;
+}
+
+RefPtr<ClientOpPromise>
+ClientSource::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
+{
+  RefPtr<ClientOpPromise> ref;
+
+  ClientState state;
+  nsresult rv = SnapshotState(&state);
+  if (NS_FAILED(rv)) {
+    ref = ClientOpPromise::CreateAndReject(rv, __func__);
+    return ref.forget();
+  }
+
+  ref = ClientOpPromise::CreateAndResolve(ClientInfoAndState(mClientInfo.ToIPC(),
+                                                             state.ToIPC()), __func__);
+  return ref.forget();
+}
+
+nsresult
+ClientSource::SnapshotState(ClientState* aStateOut)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+  MOZ_DIAGNOSTIC_ASSERT(aStateOut);
+
+  if (mClientInfo.Type() == ClientType::Window) {
+    MaybeCreateInitialDocument();
+    nsresult rv = SnapshotWindowState(aStateOut);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    return NS_OK;
+  }
+
+  *aStateOut = ClientState(ClientWorkerState());
+  return NS_OK;
+}
+
 nsISerialEventTarget*
 ClientSource::EventTarget() const
 {
   return mEventTarget;
 }
 
 void
 ClientSource::Traverse(nsCycleCollectionTraversalCallback& aCallback,
--- a/dom/clients/manager/ClientSource.h
+++ b/dom/clients/manager/ClientSource.h
@@ -2,24 +2,29 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _mozilla_dom_ClientSource_h
 #define _mozilla_dom_ClientSource_h
 
 #include "mozilla/dom/ClientInfo.h"
+#include "mozilla/dom/ClientOpPromise.h"
 #include "mozilla/dom/ClientThing.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
+#include "mozilla/Variant.h"
 
 class nsIDocShell;
+class nsISerialEventTarget;
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
 
+class ClientControlledArgs;
 class ClientManager;
 class ClientSourceChild;
 class ClientSourceConstructorArgs;
 class ClientSourceExecutionReadyArgs;
 class PClientManagerChild;
 
 namespace workers {
 class WorkerPrivate;
@@ -41,29 +46,36 @@ class ClientSource final : public Client
   nsCOMPtr<nsISerialEventTarget> mEventTarget;
 
   Variant<Nothing,
           RefPtr<nsPIDOMWindowInner>,
           nsCOMPtr<nsIDocShell>,
           mozilla::dom::workers::WorkerPrivate*> mOwner;
 
   ClientInfo mClientInfo;
+  Maybe<ServiceWorkerDescriptor> mController;
 
   void
   Shutdown();
 
   void
   ExecutionReady(const ClientSourceExecutionReadyArgs& aArgs);
 
   mozilla::dom::workers::WorkerPrivate*
   GetWorkerPrivate() const;
 
   nsIDocShell*
   GetDocShell() const;
 
+  void
+  MaybeCreateInitialDocument();
+
+  nsresult
+  SnapshotWindowState(ClientState* aStateOut);
+
   // Private methods called by ClientManager
   ClientSource(ClientManager* aManager,
                nsISerialEventTarget* aEventTarget,
                const ClientSourceConstructorArgs& aArgs);
 
   void
   Activate(PClientManagerChild* aActor);
 
@@ -86,16 +98,50 @@ public:
   Freeze();
 
   void
   Thaw();
 
   const ClientInfo&
   Info() const;
 
+  // Trigger a synchronous IPC ping to the parent process to confirm that
+  // the ClientSource actor has been created.  This should only be used
+  // by the WorkerPrivate startup code to deal with a ClientHandle::Control()
+  // call racing on the main thread.  Do not call this in other circumstances!
+  void
+  WorkerSyncPing(mozilla::dom::workers::WorkerPrivate* aWorkerPrivate);
+
+  // Synchronously mark the ClientSource as controlled by the given service
+  // worker.  This can happen as a result of a remote operation or directly
+  // by local code.  For example, if a client's initial network load is
+  // intercepted by a controlling service worker then this should be called
+  // immediately.
+  //
+  // Note, there is no way to clear the controlling service worker because
+  // the specification does not allow that operation.
+  void
+  SetController(const ServiceWorkerDescriptor& aServiceWorker);
+
+  // Mark the ClientSource as controlled using the remote operation arguments.
+  // This will in turn call SetController().
+  RefPtr<ClientOpPromise>
+  Control(const ClientControlledArgs& aArgs);
+
+  // Get the ClientSource's current controlling service worker, if one has
+  // been set.
+  const Maybe<ServiceWorkerDescriptor>&
+  GetController() const;
+
+  RefPtr<ClientOpPromise>
+  GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs);
+
+  nsresult
+  SnapshotState(ClientState* aStateOut);
+
   nsISerialEventTarget*
   EventTarget() const;
 
   void
   Traverse(nsCycleCollectionTraversalCallback& aCallback,
            const char* aName,
            uint32_t aFlags);
 };
--- a/dom/clients/manager/ClientSourceChild.cpp
+++ b/dom/clients/manager/ClientSourceChild.cpp
@@ -1,18 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientSourceChild.h"
 
+#include "ClientSource.h"
 #include "ClientSourceOpChild.h"
-#include "ClientThing.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
 
@@ -56,27 +56,33 @@ ClientSourceChild::ClientSourceChild(con
 {
 }
 
 void
 ClientSourceChild::SetOwner(ClientThing<ClientSourceChild>* aThing)
 {
   MOZ_DIAGNOSTIC_ASSERT(aThing);
   MOZ_DIAGNOSTIC_ASSERT(!mSource);
-  mSource = aThing;
+  mSource = static_cast<ClientSource*>(aThing);
 }
 
 void
 ClientSourceChild::RevokeOwner(ClientThing<ClientSourceChild>* aThing)
 {
   MOZ_DIAGNOSTIC_ASSERT(mSource);
-  MOZ_DIAGNOSTIC_ASSERT(mSource == aThing);
+  MOZ_DIAGNOSTIC_ASSERT(mSource == static_cast<ClientSource*>(aThing));
   mSource = nullptr;
 }
 
+ClientSource*
+ClientSourceChild::GetSource() const
+{
+  return mSource;
+}
+
 void
 ClientSourceChild::MaybeStartTeardown()
 {
   if (mTeardownStarted) {
     return;
   }
   mTeardownStarted = true;
   Unused << SendTeardown();
--- a/dom/clients/manager/ClientSourceChild.h
+++ b/dom/clients/manager/ClientSourceChild.h
@@ -6,22 +6,23 @@
 #ifndef _mozilla_dom_ClientSourceChild_h
 #define _mozilla_dom_ClientSourceChild_h
 
 #include "mozilla/dom/PClientSourceChild.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientSource;
 class ClientSourceConstructorArgs;
 template <typename ActorType> class ClientThing;
 
 class ClientSourceChild final : public PClientSourceChild
 {
-  ClientThing<ClientSourceChild>* mSource;
+  ClientSource* mSource;
   bool mTeardownStarted;
 
   // PClientSourceChild interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   PClientSourceOpChild*
   AllocPClientSourceOpChild(const ClientOpConstructorArgs& aArgs) override;
@@ -37,16 +38,19 @@ public:
   explicit ClientSourceChild(const ClientSourceConstructorArgs& aArgs);
 
   void
   SetOwner(ClientThing<ClientSourceChild>* aThing);
 
   void
   RevokeOwner(ClientThing<ClientSourceChild>* aThing);
 
+  ClientSource*
+  GetSource() const;
+
   void
   MaybeStartTeardown();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientSourceChild_h
--- a/dom/clients/manager/ClientSourceOpChild.cpp
+++ b/dom/clients/manager/ClientSourceOpChild.cpp
@@ -1,23 +1,97 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientSourceOpChild.h"
 
+#include "ClientSource.h"
+#include "ClientSourceChild.h"
+#include "mozilla/Unused.h"
+
 namespace mozilla {
 namespace dom {
 
+ClientSource*
+ClientSourceOpChild::GetSource() const
+{
+  auto actor = static_cast<ClientSourceChild*>(Manager());
+  return actor->GetSource();
+}
+
+template<typename Method, typename Args>
+void
+ClientSourceOpChild::DoSourceOp(Method aMethod, const Args& aArgs)
+{
+  RefPtr<ClientOpPromise> promise;
+  nsCOMPtr<nsISerialEventTarget> target;
+
+  // Some ClientSource operations can cause the ClientSource to be destroyed.
+  // This means we should reference the ClientSource pointer for the minimum
+  // possible to start the operation.  Use an extra block scope here to help
+  // enforce this and prevent accidental usage later in the method.
+  {
+    ClientSource* source = GetSource();
+    if (!source) {
+      Unused << PClientSourceOpChild::Send__delete__(this, NS_ERROR_DOM_ABORT_ERR);
+      return;
+    }
+
+    target = source->EventTarget();
+
+    // This may cause the ClientSource object to be destroyed.  Do not
+    // use the source variable after this call.
+    promise = (source->*aMethod)(aArgs);
+  }
+
+  // The ClientSource methods are required to always return a promise.  If
+  // they encounter an error they should just immediately resolve or reject
+  // the promise as appropriate.
+  MOZ_DIAGNOSTIC_ASSERT(promise);
+
+  // Capture 'this' is safe here because we disconnect the promise
+  // ActorDestroy() which ensures nethier lambda is called if the
+  // actor is destroyed before the source operation completes.
+  promise->Then(target, __func__,
+    [this, aArgs] (const mozilla::dom::ClientOpResult& aResult) {
+      mPromiseRequestHolder.Complete();
+      Unused << PClientSourceOpChild::Send__delete__(this, aResult);
+    },
+    [this] (nsresult aRv) {
+      mPromiseRequestHolder.Complete();
+      Unused << PClientSourceOpChild::Send__delete__(this, aRv);
+    })->Track(mPromiseRequestHolder);
+}
+
 void
 ClientSourceOpChild::ActorDestroy(ActorDestroyReason aReason)
 {
+  mPromiseRequestHolder.DisconnectIfExists();
 }
 
 void
 ClientSourceOpChild::Init(const ClientOpConstructorArgs& aArgs)
 {
+  switch (aArgs.type()) {
+    case ClientOpConstructorArgs::TClientControlledArgs:
+    {
+      DoSourceOp(&ClientSource::Control, aArgs.get_ClientControlledArgs());
+      break;
+    }
+    case ClientOpConstructorArgs::TClientGetInfoAndStateArgs:
+    {
+      DoSourceOp(&ClientSource::GetInfoAndState,
+                 aArgs.get_ClientGetInfoAndStateArgs());
+      break;
+    }
+    default:
+    {
+      MOZ_ASSERT_UNREACHABLE("unknown client operation!");
+      break;
+    }
+  }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientSourceOpChild.h
+++ b/dom/clients/manager/ClientSourceOpChild.h
@@ -7,18 +7,29 @@
 #define _mozilla_dom_ClientSourceOpChild_h
 
 #include "mozilla/dom/PClientSourceOpChild.h"
 #include "ClientOpPromise.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientSource;
+
 class ClientSourceOpChild final : public PClientSourceOpChild
 {
+  MozPromiseRequestHolder<ClientOpPromise> mPromiseRequestHolder;
+
+  ClientSource*
+  GetSource() const;
+
+  template <typename Method, typename Args>
+  void
+  DoSourceOp(Method aMethod, const Args& aArgs);
+
   // PClientSourceOpChild interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
 public:
   ClientSourceOpChild() = default;
   ~ClientSourceOpChild() = default;
 
--- a/dom/clients/manager/ClientSourceParent.cpp
+++ b/dom/clients/manager/ClientSourceParent.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/dom/PClientManagerParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
+using mozilla::ipc::AssertIsOnBackgroundThread;
 using mozilla::ipc::BackgroundParent;
 using mozilla::ipc::IPCResult;
 using mozilla::ipc::PrincipalInfo;
 
 namespace {
 
 // It would be nice to use a lambda instead of this class, but we cannot
 // move capture in lambdas yet and ContentParent cannot be AddRef'd off
@@ -77,16 +78,25 @@ ClientSourceParent::KillInvalidChild()
   // typically mean someone sent us bogus data over the IPC link.  We can't
   // trust that process any more.  We have to do this on the main thread, so
   // there is a small window of time before we kill the process.  This is why
   // we start the actor destruction immediately above.
   nsCOMPtr<nsIRunnable> r = new KillContentParentRunnable(Move(process));
   MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
 }
 
+mozilla::ipc::IPCResult
+ClientSourceParent::RecvWorkerSyncPing()
+{
+  AssertIsOnBackgroundThread();
+  // Do nothing here.  This is purely a sync message allowing the child to
+  // confirm that the actor has been created on the parent process.
+  return IPC_OK();
+}
+
 IPCResult
 ClientSourceParent::RecvTeardown()
 {
   Unused << Send__delete__(this);
   return IPC_OK();
 }
 
 IPCResult
@@ -204,16 +214,22 @@ ClientSourceParent::Info() const
 }
 
 bool
 ClientSourceParent::IsFrozen() const
 {
   return mFrozen;
 }
 
+bool
+ClientSourceParent::ExecutionReady() const
+{
+  return mExecutionReady;
+}
+
 void
 ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle)
 {
   MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
   MOZ_DIAGNOSTIC_ASSERT(!mFrozen);
   MOZ_ASSERT(!mHandleList.Contains(aClientHandle));
   mHandleList.AppendElement(aClientHandle);
 }
@@ -221,10 +237,30 @@ ClientSourceParent::AttachHandle(ClientH
 void
 ClientSourceParent::DetachHandle(ClientHandleParent* aClientHandle)
 {
   MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
   MOZ_ASSERT(mHandleList.Contains(aClientHandle));
   mHandleList.RemoveElement(aClientHandle);
 }
 
+RefPtr<ClientOpPromise>
+ClientSourceParent::StartOp(const ClientOpConstructorArgs& aArgs)
+{
+  RefPtr<ClientOpPromise::Private> promise =
+    new ClientOpPromise::Private(__func__);
+
+  // If we are being controlled, remember that data before propagating
+  // on to the ClientSource.
+  if (aArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
+    mController.reset();
+    mController.emplace(aArgs.get_ClientControlledArgs().serviceWorker());
+  }
+
+  // Constructor failure will reject the promise via ActorDestroy().
+  ClientSourceOpParent* actor = new ClientSourceOpParent(aArgs, promise);
+  Unused << SendPClientSourceOpConstructor(actor, aArgs);
+
+  return promise.forget();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientSourceParent.h
+++ b/dom/clients/manager/ClientSourceParent.h
@@ -2,37 +2,43 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef _mozilla_dom_ClientSourceParent_h
 #define _mozilla_dom_ClientSourceParent_h
 
 #include "ClientInfo.h"
+#include "ClientOpPromise.h"
 #include "mozilla/dom/PClientSourceParent.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
 
 namespace mozilla {
 namespace dom {
 
 class ClientHandleParent;
 class ClientManagerService;
 
 class ClientSourceParent final : public PClientSourceParent
 {
   ClientInfo mClientInfo;
+  Maybe<ServiceWorkerDescriptor> mController;
   RefPtr<ClientManagerService> mService;
   nsTArray<ClientHandleParent*> mHandleList;
   bool mExecutionReady;
   bool mFrozen;
 
   void
   KillInvalidChild();
 
   // PClientSourceParent
   mozilla::ipc::IPCResult
+  RecvWorkerSyncPing() override;
+
+  mozilla::ipc::IPCResult
   RecvTeardown() override;
 
   mozilla::ipc::IPCResult
   RecvExecutionReady(const ClientSourceExecutionReadyArgs& aArgs) override;
 
   mozilla::ipc::IPCResult
   RecvFreeze() override;
 
@@ -56,19 +62,25 @@ public:
   Init();
 
   const ClientInfo&
   Info() const;
 
   bool
   IsFrozen() const;
 
+  bool
+  ExecutionReady() const;
+
   void
   AttachHandle(ClientHandleParent* aClientSource);
 
   void
   DetachHandle(ClientHandleParent* aClientSource);
+
+  RefPtr<ClientOpPromise>
+  StartOp(const ClientOpConstructorArgs& aArgs);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientSourceParent_h
--- a/dom/clients/manager/PClientSource.ipdl
+++ b/dom/clients/manager/PClientSource.ipdl
@@ -15,16 +15,17 @@ namespace dom {
 
 sync protocol PClientSource
 {
   manager PClientManager;
 
   manages PClientSourceOp;
 
 parent:
+  sync WorkerSyncPing();
   async Teardown();
   async ExecutionReady(ClientSourceExecutionReadyArgs aArgs);
   async Freeze();
   async Thaw();
 
 child:
   async PClientSourceOp(ClientOpConstructorArgs aArgs);
 
--- a/dom/credentialmanagement/CredentialsContainer.cpp
+++ b/dom/credentialmanagement/CredentialsContainer.cpp
@@ -6,54 +6,64 @@
 
 #include "mozilla/dom/CredentialsContainer.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/WebAuthnManager.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CredentialsContainer, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CredentialsContainer, mParent, mManager)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CredentialsContainer)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CredentialsContainer)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CredentialsContainer)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 CredentialsContainer::CredentialsContainer(nsPIDOMWindowInner* aParent) :
   mParent(aParent)
 {
   MOZ_ASSERT(aParent);
 }
 
 CredentialsContainer::~CredentialsContainer()
 {}
 
+void
+CredentialsContainer::EnsureWebAuthnManager()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mManager) {
+    mManager = new WebAuthnManager(mParent);
+  }
+}
+
 JSObject*
 CredentialsContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CredentialsContainerBinding::Wrap(aCx, this, aGivenProto);
 }
 
 already_AddRefed<Promise>
 CredentialsContainer::Get(const CredentialRequestOptions& aOptions)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
-  return mgr->GetAssertion(mParent, aOptions.mPublicKey, aOptions.mSignal);
+  EnsureWebAuthnManager();
+  return mManager->GetAssertion(aOptions.mPublicKey, aOptions.mSignal);
 }
 
 already_AddRefed<Promise>
 CredentialsContainer::Create(const CredentialCreationOptions& aOptions)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
-  return mgr->MakeCredential(mParent, aOptions.mPublicKey, aOptions.mSignal);
+  EnsureWebAuthnManager();
+  return mManager->MakeCredential(aOptions.mPublicKey, aOptions.mSignal);
 }
 
 already_AddRefed<Promise>
 CredentialsContainer::Store(const Credential& aCredential)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
-  return mgr->Store(mParent, aCredential);
+  EnsureWebAuthnManager();
+  return mManager->Store(aCredential);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/credentialmanagement/CredentialsContainer.h
+++ b/dom/credentialmanagement/CredentialsContainer.h
@@ -7,16 +7,18 @@
 #ifndef mozilla_dom_CredentialsContainer_h
 #define mozilla_dom_CredentialsContainer_h
 
 #include "mozilla/dom/CredentialManagementBinding.h"
 
 namespace mozilla {
 namespace dom {
 
+class WebAuthnManager;
+
 class CredentialsContainer final : public nsISupports
                                  , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CredentialsContainer)
 
   explicit CredentialsContainer(nsPIDOMWindowInner* aParent);
@@ -27,23 +29,28 @@ public:
     return mParent;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   already_AddRefed<Promise>
   Get(const CredentialRequestOptions& aOptions);
+
   already_AddRefed<Promise>
   Create(const CredentialCreationOptions& aOptions);
+
   already_AddRefed<Promise>
   Store(const Credential& aCredential);
 
 private:
   ~CredentialsContainer();
 
+  void EnsureWebAuthnManager();
+
   nsCOMPtr<nsPIDOMWindowInner> mParent;
+  RefPtr<WebAuthnManager> mManager;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CredentialsContainer_h
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -20,16 +20,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPipe.h"
 
 #include "nsContentPolicyUtils.h"
 #include "nsDataHandler.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsNetUtil.h"
 #include "nsPrintfCString.h"
+#include "nsProxyRelease.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "nsHttpChannel.h"
 
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
@@ -53,16 +54,278 @@ ShouldCheckSRI(const InternalRequest* co
   MOZ_DIAGNOSTIC_ASSERT(aResponse);
 
   return !aRequest->GetIntegrity().IsEmpty() &&
          aResponse->Type() != ResponseType::Error;
 }
 
 } // anonymous namespace
 
+//-----------------------------------------------------------------------------
+// AlternativeDataStreamListener
+//-----------------------------------------------------------------------------
+class AlternativeDataStreamListener final : public nsIStreamListener,
+                                            public nsIThreadRetargetableStreamListener
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSISTREAMLISTENER
+  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
+
+  // The status of AlternativeDataStreamListener
+  // LOADING: is the initial status, loading the alternative data
+  // COMPLETED: Alternative data loading is completed
+  // CANCELED: Alternative data loading is canceled, this would make
+  //           AlternativeDataStreamListener ignore all channel callbacks
+  // FALLBACK: fallback the channel callbacks to FetchDriver
+  // Depends on different situaions, the status transition could be followings
+  // 1. LOADING->COMPLETED
+  //    This is the normal status transition for alternative data loading
+  //
+  // 2. LOADING->CANCELED
+  //    LOADING->COMPLETED->CANCELED
+  //    Alternative data loading could be canceled when cacheId from alternative
+  //    data channel does not match with from main data channel(The cacheID
+  //    checking is in FetchDriver::OnStartRequest).
+  //    Notice the alternative data loading could finish before the cacheID
+  //    checking, so the statust transition could be LOADING->COMPLETED->CANCELED
+  //
+  // 3. LOADING->FALLBACK
+  //    For the case that alternative data loading could not be initialized, i.e.
+  //    alternative data does not exist or no preferred alternative data type is
+  //    requested. Once the status becomes FALLBACK, AlternativeDataStreamListener
+  //    transits the channel callback request to FetchDriver, and the status
+  //    should not go back to LOADING, COMPLETED, or CANCELED anymore.
+  enum eStatus {
+    LOADING = 0,
+    COMPLETED,
+    CANCELED,
+    FALLBACK
+  };
+
+  AlternativeDataStreamListener(FetchDriver* aFetchDriver,
+                                nsIChannel* aChannel,
+                                const nsACString& aAlternativeDataType);
+  eStatus Status();
+  void Cancel();
+  uint64_t GetAlternativeDataCacheEntryId();
+  const nsACString& GetAlternativeDataType() const;
+  already_AddRefed<nsICacheInfoChannel> GetCacheInfoChannel();
+  already_AddRefed<nsIInputStream> GetAlternativeInputStream();
+
+private:
+  ~AlternativeDataStreamListener() = default;
+
+  // This creates a strong reference cycle with FetchDriver and its
+  // mAltDataListener. We need to clear at least one reference of them once the
+  // data loading finishes.
+  RefPtr<FetchDriver> mFetchDriver;
+  nsCString mAlternativeDataType;
+  nsCOMPtr<nsIInputStream> mPipeAlternativeInputStream;
+  nsCOMPtr<nsIOutputStream> mPipeAlternativeOutputStream;
+  uint64_t mAlternativeDataCacheEntryId;
+  nsCOMPtr<nsICacheInfoChannel> mCacheInfoChannel;
+  nsCOMPtr<nsIChannel> mChannel;
+  Atomic<eStatus> mStatus;
+};
+
+NS_IMPL_ISUPPORTS(AlternativeDataStreamListener,
+                  nsIStreamListener,
+                  nsIThreadRetargetableStreamListener)
+
+AlternativeDataStreamListener::AlternativeDataStreamListener(FetchDriver* aFetchDriver,
+                                                             nsIChannel* aChannel,
+                                                             const nsACString& aAlternativeDataType)
+  : mFetchDriver(aFetchDriver)
+  , mAlternativeDataType(aAlternativeDataType)
+  , mAlternativeDataCacheEntryId(0)
+  , mChannel(aChannel)
+  , mStatus(AlternativeDataStreamListener::LOADING)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mFetchDriver);
+  MOZ_DIAGNOSTIC_ASSERT(mChannel);
+}
+
+AlternativeDataStreamListener::eStatus
+AlternativeDataStreamListener::Status()
+{
+  return mStatus;
+}
+
+void
+AlternativeDataStreamListener::Cancel()
+{
+  mAlternativeDataCacheEntryId = 0;
+  mCacheInfoChannel = nullptr;
+  mPipeAlternativeOutputStream = nullptr;
+  mPipeAlternativeInputStream = nullptr;
+  if (mChannel && mStatus != AlternativeDataStreamListener::FALLBACK) {
+    // if mStatus is fallback, we need to keep channel to forward request back to
+    // FetchDriver
+    mChannel->Cancel(NS_BINDING_ABORTED);
+    mChannel = nullptr;
+  }
+  mStatus = AlternativeDataStreamListener::CANCELED;
+}
+
+uint64_t
+AlternativeDataStreamListener::GetAlternativeDataCacheEntryId()
+{
+  return mAlternativeDataCacheEntryId;
+}
+
+const nsACString&
+AlternativeDataStreamListener::GetAlternativeDataType() const
+{
+  return mAlternativeDataType;
+}
+
+already_AddRefed<nsIInputStream>
+AlternativeDataStreamListener::GetAlternativeInputStream()
+{
+  nsCOMPtr<nsIInputStream> inputStream = mPipeAlternativeInputStream;
+  return inputStream.forget();
+}
+
+already_AddRefed<nsICacheInfoChannel>
+AlternativeDataStreamListener::GetCacheInfoChannel()
+{
+  nsCOMPtr<nsICacheInfoChannel> channel = mCacheInfoChannel;
+  return channel.forget();
+}
+
+NS_IMETHODIMP
+AlternativeDataStreamListener::OnStartRequest(nsIRequest* aRequest,
+                                              nsISupports* aContext)
+{
+  workers::AssertIsOnMainThread();
+  MOZ_ASSERT(!mAlternativeDataType.IsEmpty());
+  // Checking the alternative data type is the same between we asked and the
+  // saved in the channel.
+  nsAutoCString alternativeDataType;
+  nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(aRequest);
+  mStatus = AlternativeDataStreamListener::LOADING;
+  if (cic &&
+      NS_SUCCEEDED(cic->GetAlternativeDataType(alternativeDataType)) &&
+      mAlternativeDataType.Equals(alternativeDataType) &&
+      NS_SUCCEEDED(cic->GetCacheEntryId(&mAlternativeDataCacheEntryId))) {
+
+    MOZ_DIAGNOSTIC_ASSERT(!mPipeAlternativeInputStream);
+    MOZ_DIAGNOSTIC_ASSERT(!mPipeAlternativeOutputStream);
+    nsresult rv = NS_NewPipe(
+      getter_AddRefs(mPipeAlternativeInputStream),
+      getter_AddRefs(mPipeAlternativeOutputStream),
+      0 /* default segment size */,
+      UINT32_MAX /* infinite pipe */,
+      true /* non-blocking input, otherwise you deadlock */,
+      false /* blocking output, since the pipe is 'in'finite */);
+
+    if (NS_FAILED(rv)) {
+      mFetchDriver->FailWithNetworkError(rv);
+      return rv;
+    }
+
+    MOZ_DIAGNOSTIC_ASSERT(!mCacheInfoChannel);
+    mCacheInfoChannel = cic;
+
+    // call FetchDriver::HttpFetch to load main body
+    MOZ_ASSERT(mFetchDriver);
+    return mFetchDriver->HttpFetch();
+
+  } else {
+    // Needn't load alternative data, since alternative data does not exist.
+    // Set status to FALLBACK to reuse the opened channel to load main body, then
+    // call FetchDriver::OnStartRequest to continue the work.
+    // Unfortunately can't change the stream listener to mFetchDriver, need to
+    // keep AlternativeDataStreamListener alive to redirect OnDataAvailable and
+    // OnStopRequest to mFetchDriver.
+    MOZ_ASSERT(alternativeDataType.IsEmpty());
+    mStatus = AlternativeDataStreamListener::FALLBACK;
+    mAlternativeDataCacheEntryId = 0;
+    MOZ_ASSERT(mFetchDriver);
+    return mFetchDriver->OnStartRequest(aRequest, aContext);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+AlternativeDataStreamListener::OnDataAvailable(nsIRequest* aRequest,
+                                               nsISupports* aContext,
+                                               nsIInputStream* aInputStream,
+                                               uint64_t aOffset,
+                                               uint32_t aCount)
+{
+  if (mStatus == AlternativeDataStreamListener::LOADING) {
+    MOZ_ASSERT(mPipeAlternativeOutputStream);
+    uint32_t read;
+    return aInputStream->ReadSegments(NS_CopySegmentToStream,
+                                      mPipeAlternativeOutputStream,
+                                      aCount, &read);
+  }
+  if (mStatus == AlternativeDataStreamListener::FALLBACK) {
+    MOZ_ASSERT(mFetchDriver);
+    return mFetchDriver->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+AlternativeDataStreamListener::OnStopRequest(nsIRequest* aRequest,
+                                             nsISupports* aContext,
+                                             nsresult aStatusCode)
+{
+  workers::AssertIsOnMainThread();
+
+  // Alternative data loading is going to finish, breaking the reference cycle
+  // here by taking the ownership to a loacl variable.
+  RefPtr<FetchDriver> fetchDriver = mFetchDriver.forget();
+
+  if (mStatus == AlternativeDataStreamListener::CANCELED) {
+    // do nothing
+    return NS_OK;
+  }
+
+  if (mStatus == AlternativeDataStreamListener::FALLBACK) {
+    MOZ_ASSERT(fetchDriver);
+    return fetchDriver->OnStopRequest(aRequest, aContext, aStatusCode);
+  }
+
+  MOZ_DIAGNOSTIC_ASSERT(mStatus == AlternativeDataStreamListener::LOADING);
+
+  MOZ_ASSERT(!mAlternativeDataType.IsEmpty() &&
+             mPipeAlternativeOutputStream &&
+             mPipeAlternativeInputStream);
+
+  mPipeAlternativeOutputStream->Close();
+  mPipeAlternativeOutputStream = nullptr;
+
+  // Cleanup the states for alternative data if needed.
+  if (NS_FAILED(aStatusCode)) {
+    mAlternativeDataCacheEntryId = 0;
+    mCacheInfoChannel = nullptr;
+    mPipeAlternativeInputStream = nullptr;
+  }
+  mStatus = AlternativeDataStreamListener::COMPLETED;
+  // alternative data loading finish, call FetchDriver::FinishOnStopRequest to
+  // continue the final step for the case FetchDriver::OnStopRequest is called
+  // earlier than AlternativeDataStreamListener::OnStopRequest
+  MOZ_ASSERT(fetchDriver);
+  return fetchDriver->FinishOnStopRequest(this);
+}
+
+NS_IMETHODIMP
+AlternativeDataStreamListener::CheckListenerChain()
+{
+  return NS_OK;
+}
+//-----------------------------------------------------------------------------
+// FetchDriver
+//-----------------------------------------------------------------------------
+
 NS_IMPL_ISUPPORTS(FetchDriver,
                   nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
                   nsIThreadRetargetableStreamListener)
 
 FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                          nsILoadGroup* aLoadGroup, nsIEventTarget* aMainThreadEventTarget,
                          bool aIsTrackingFetch)
   : mPrincipal(aPrincipal)
@@ -126,35 +389,36 @@ FetchDriver::Fetch(AbortSignal* aSignal,
     if (aSignal->Aborted()) {
       Abort();
       return NS_OK;
     }
 
     Follow(aSignal);
   }
 
-  rv = HttpFetch();
+  rv = HttpFetch(mRequest->GetPreferredAlternativeDataType());
   if (NS_FAILED(rv)) {
     FailWithNetworkError(rv);
   }
 
   // Any failure is handled by FailWithNetworkError notifying the aObserver.
   return NS_OK;
 }
 
 // This function implements the "HTTP Fetch" algorithm from the Fetch spec.
 // Functionality is often split between here, the CORS listener proxy and the
 // Necko HTTP implementation.
 nsresult
-FetchDriver::HttpFetch()
+FetchDriver::HttpFetch(const nsACString& aPreferredAlternativeDataType)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Step 1. "Let response be null."
   mResponse = nullptr;
+  mOnStopRequestCalled = false;
   nsresult rv;
 
   nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString url;
   mRequest->GetURL(url);
   nsCOMPtr<nsIURI> uri;
@@ -264,18 +528,16 @@ FetchDriver::HttpFetch()
                        mRequest->ContentPolicyType(),
                        mLoadGroup,
                        nullptr, /* aCallbacks */
                        loadFlags,
                        ios);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mLoadGroup = nullptr;
-
   // Insert ourselves into the notification callbacks chain so we can set
   // headers on redirects.
 #ifdef DEBUG
   {
     nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
     chan->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
     MOZ_ASSERT(!notificationCallbacks);
   }
@@ -409,17 +671,33 @@ FetchDriver::HttpFetch()
 
   if (mIsTrackingFetch && nsContentUtils::IsLowerNetworkPriority()) {
     nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(chan);
     if (p) {
       p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
     }
   }
 
-  rv = chan->AsyncOpen2(this);
+  // if the preferred alternative data type in InternalRequest is not empty, set
+  // the data type on the created channel and also create a AlternativeDataStreamListener
+  // to be the stream listener of the channel.
+  if (!aPreferredAlternativeDataType.IsEmpty()) {
+    nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(chan);
+    if (cic) {
+      cic->PreferAlternativeDataType(aPreferredAlternativeDataType);
+      MOZ_ASSERT(!mAltDataListener);
+      mAltDataListener =
+        new AlternativeDataStreamListener(this, chan, aPreferredAlternativeDataType);
+      rv = chan->AsyncOpen2(mAltDataListener);
+    } else {
+      rv = chan->AsyncOpen2(this);
+    }
+  } else {
+    rv = chan->AsyncOpen2(this);
+  }
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Step 4 onwards of "HTTP Fetch" is handled internally by Necko.
 
   mChannel = chan;
   return NS_OK;
 }
 already_AddRefed<InternalResponse>
@@ -575,16 +853,54 @@ FetchDriver::OnStartRequest(nsIRequest* 
       contentLenStr.AppendInt(contentLength);
       response->Headers()->Append(NS_LITERAL_CSTRING("Content-Length"),
                                   contentLenStr,
                                   result);
       MOZ_ASSERT(!result.Failed());
     }
   }
 
+  nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(aRequest);
+  if (cic && mAltDataListener) {
+    // Skip the case that mAltDataListener->Status() equals to FALLBACK, that means
+    // the opened channel for alternative data loading is reused for loading the
+    // main data.
+    if (mAltDataListener->Status() != AlternativeDataStreamListener::FALLBACK) {
+      // Verify the cache ID is the same with from alternative data cache.
+      // If the cache ID is different, droping the alternative data loading,
+      // otherwise setup the response's alternative body and cacheInfoChannel.
+      uint64_t cacheEntryId = 0;
+      if (NS_SUCCEEDED(cic->GetCacheEntryId(&cacheEntryId)) &&
+          cacheEntryId != mAltDataListener->GetAlternativeDataCacheEntryId()) {
+        mAltDataListener->Cancel();
+      } else {
+        // AlternativeDataStreamListener::OnStartRequest had already been called,
+        // the alternative data input stream and cacheInfo channel must be created.
+        nsCOMPtr<nsICacheInfoChannel> cacheInfo = mAltDataListener->GetCacheInfoChannel();
+        nsCOMPtr<nsIInputStream> altInputStream = mAltDataListener->GetAlternativeInputStream();
+        MOZ_ASSERT(altInputStream && cacheInfo);
+        response->SetAlternativeBody(altInputStream);
+        nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
+          new nsMainThreadPtrHolder<nsICacheInfoChannel>("nsICacheInfoChannel",
+                                                         cacheInfo,
+                                                         false));
+        response->SetCacheInfoChannel(handle);
+      }
+    } else if (!mAltDataListener->GetAlternativeDataType().IsEmpty()) {
+      // If the status is FALLBACK and the mAltDataListener::mAlternativeDataType
+      // is not empty, that means the data need to be saved into cache, setup the
+      // response's nsICacheInfoChannel for caching the data after loading.
+      nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
+        new nsMainThreadPtrHolder<nsICacheInfoChannel>("nsICacheInfoChannel",
+                                                       cic,
+                                                       false));
+      response->SetCacheInfoChannel(handle);
+    }
+  }
+
   // We open a pipe so that we can immediately set the pipe's read end as the
   // response's body. Setting the segment size to UINT32_MAX means that the
   // pipe has infinite space. The nsIChannel will continue to buffer data in
   // xpcom events even if we block on a fixed size pipe.  It might be possible
   // to suspend the channel and then resume when there is space available, but
   // for now use an infinite pipe to avoid blocking.
   nsCOMPtr<nsIInputStream> pipeInputStream;
   rv = NS_NewPipe(getter_AddRefs(pipeInputStream),
@@ -795,24 +1111,33 @@ FetchDriver::OnDataAvailable(nsIRequest*
 
 NS_IMETHODIMP
 FetchDriver::OnStopRequest(nsIRequest* aRequest,
                            nsISupports* aContext,
                            nsresult aStatusCode)
 {
   workers::AssertIsOnMainThread();
 
+  MOZ_DIAGNOSTIC_ASSERT(!mOnStopRequestCalled);
+  mOnStopRequestCalled = true;
+
+  // main data loading is going to finish, breaking the reference cycle.
+  RefPtr<AlternativeDataStreamListener> altDataListener = mAltDataListener.forget();
+
   // We need to check mObserver, which is nulled by FailWithNetworkError(),
   // because in the case of "error" redirect mode, aStatusCode may be NS_OK but
   // mResponse will definitely be null so we must not take the else branch.
   if (NS_FAILED(aStatusCode) || !mObserver) {
     nsCOMPtr<nsIAsyncOutputStream> outputStream = do_QueryInterface(mPipeOutputStream);
     if (outputStream) {
       outputStream->CloseWithStatus(NS_BINDING_FAILED);
     }
+    if (altDataListener) {
+      altDataListener->Cancel();
+    }
 
     // We proceed as usual here, since we've already created a successful response
     // from OnStartRequest.
   } else {
     MOZ_ASSERT(mResponse);
     MOZ_ASSERT(!mResponse->IsError());
 
     // From "Main Fetch" step 19: SRI-part3.
@@ -830,27 +1155,52 @@ FetchDriver::OnStopRequest(nsIRequest* a
       if (mDocument && mDocument->GetDocumentURI()) {
         mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
       } else if (!mWorkerScript.IsEmpty()) {
         sourceUri.Assign(mWorkerScript);
       }
       nsresult rv = mSRIDataVerifier->Verify(mSRIMetadata, channel, sourceUri,
                                              reporter);
       if (NS_FAILED(rv)) {
+        if (altDataListener) {
+          altDataListener->Cancel();
+        }
         FailWithNetworkError(rv);
         // Cancel request.
         return rv;
       }
     }
 
     if (mPipeOutputStream) {
       mPipeOutputStream->Close();
     }
   }
 
+  return FinishOnStopRequest(altDataListener);
+}
+
+nsresult
+FetchDriver::FinishOnStopRequest(AlternativeDataStreamListener* aAltDataListener)
+{
+  workers::AssertIsOnMainThread();
+  // OnStopRequest is not called from channel, that means the main data loading
+  // does not finish yet. Reaching here since alternative data loading finishes.
+  if (!mOnStopRequestCalled) {
+    return NS_OK;
+  }
+
+  MOZ_DIAGNOSTIC_ASSERT(!mAltDataListener);
+  // Wait for alternative data loading finish if we needed it.
+  if (aAltDataListener &&
+      aAltDataListener->Status() == AlternativeDataStreamListener::LOADING) {
+    // For LOADING case, channel holds the reference of altDataListener, no need
+    // to restore it to mAltDataListener.
+    return NS_OK;
+  }
+
   if (mObserver) {
     // From "Main Fetch" step 19.1, 19.2: Process response.
     if (ShouldCheckSRI(mRequest, mResponse)) {
       MOZ_ASSERT(mResponse);
       mObserver->OnResponseAvailable(mResponse);
       #ifdef DEBUG
         mResponseAvailableCalled = true;
       #endif
--- a/dom/fetch/FetchDriver.h
+++ b/dom/fetch/FetchDriver.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FetchDriver_h
 #define mozilla_dom_FetchDriver_h
 
 #include "nsIChannelEventSink.h"
+#include "nsICacheInfoChannel.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIStreamListener.h"
 #include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/ConsoleReportCollector.h"
 #include "mozilla/dom/AbortSignal.h"
 #include "mozilla/dom/SRIMetadata.h"
 #include "mozilla/RefPtr.h"
 
@@ -83,16 +84,18 @@ protected:
 
   virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0;
 
   nsCOMPtr<nsIConsoleReportCollector> mReporter;
 private:
   bool mGotResponseAvailable;
 };
 
+class AlternativeDataStreamListener;
+
 class FetchDriver final : public nsIStreamListener,
                           public nsIChannelEventSink,
                           public nsIInterfaceRequestor,
                           public nsIThreadRetargetableStreamListener,
                           public AbortFollower
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
@@ -141,34 +144,42 @@ private:
 
   // This is written once in OnStartRequest on the main thread and then
   // written/read in OnDataAvailable() on any thread.  Necko guarantees
   // that these do not overlap.
   bool mNeedToObserveOnDataAvailable;
 
   bool mIsTrackingFetch;
 
+  RefPtr<AlternativeDataStreamListener> mAltDataListener;
+  bool mOnStopRequestCalled;
+
 #ifdef DEBUG
   bool mResponseAvailableCalled;
   bool mFetchCalled;
 #endif
 
+  friend class AlternativeDataStreamListener;
+
   FetchDriver() = delete;
   FetchDriver(const FetchDriver&) = delete;
   FetchDriver& operator=(const FetchDriver&) = delete;
   ~FetchDriver();
 
-  nsresult HttpFetch();
+
+  nsresult HttpFetch(const nsACString& aPreferredAlternativeDataType = EmptyCString());
   // Returns the filtered response sent to the observer.
   already_AddRefed<InternalResponse>
   BeginAndGetFilteredResponse(InternalResponse* aResponse,
                               bool aFoundOpaqueRedirect);
   // Utility since not all cases need to do any post processing of the filtered
   // response.
   void FailWithNetworkError(nsresult rv);
 
   void SetRequestHeaders(nsIHttpChannel* aChannel) const;
+
+  nsresult FinishOnStopRequest(AlternativeDataStreamListener* aAltDataListener);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_FetchDriver_h
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -47,16 +47,18 @@ InternalRequest::GetRequestConstructorCo
                              mContentPolicyType :
                              nsIContentPolicy::TYPE_FETCH;
   copy->mMode = mMode;
   copy->mCredentialsMode = mCredentialsMode;
   copy->mCacheMode = mCacheMode;
   copy->mRedirectMode = mRedirectMode;
   copy->mCreatedByFetchEvent = mCreatedByFetchEvent;
   copy->mContentPolicyTypeOverridden = mContentPolicyTypeOverridden;
+
+  copy->mPreferredAlternativeDataType = mPreferredAlternativeDataType;
   return copy.forget();
 }
 
 already_AddRefed<InternalRequest>
 InternalRequest::Clone()
 {
   RefPtr<InternalRequest> clone = new InternalRequest(*this);
 
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -547,16 +547,28 @@ public:
   SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
 
   const UniquePtr<mozilla::ipc::PrincipalInfo>&
   GetPrincipalInfo() const
   {
     return mPrincipalInfo;
   }
 
+  const nsCString&
+  GetPreferredAlternativeDataType() const
+  {
+    return mPreferredAlternativeDataType;
+  }
+
+  void
+  SetPreferredAlternativeDataType(const nsACString& aDataType)
+  {
+    mPreferredAlternativeDataType = aDataType;
+  }
+
 private:
   // Does not copy mBodyStream.  Use fallible Clone() for complete copy.
   explicit InternalRequest(const InternalRequest& aOther);
 
   ~InternalRequest();
 
   static RequestContext
   MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType);
@@ -569,16 +581,18 @@ private:
 
   nsCString mMethod;
   // mURLList: a list of one or more fetch URLs
   nsTArray<nsCString> mURLList;
   RefPtr<InternalHeaders> mHeaders;
   nsCOMPtr<nsIInputStream> mBodyStream;
   int64_t mBodyLength;
 
+  nsCString mPreferredAlternativeDataType;
+
   nsContentPolicyType mContentPolicyType;
 
   // Empty string: no-referrer
   // "about:client": client (default)
   // URL: an URL
   nsString mReferrer;
   ReferrerPolicy mReferrerPolicy;
 
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -3,17 +3,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_InternalResponse_h
 #define mozilla_dom_InternalResponse_h
 
 #include "nsIInputStream.h"
+#include "nsICacheInfoChannel.h"
 #include "nsISupportsImpl.h"
+#include "nsProxyRelease.h"
 
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/ResponseBinding.h"
 #include "mozilla/dom/ChannelInfo.h"
 #include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace ipc {
@@ -243,16 +245,67 @@ public:
 
   int64_t
   GetPaddingSize();
 
   void
   SetPaddingSize(int64_t aPaddingSize);
 
   void
+  SetAlternativeBody(nsIInputStream* aAlternativeBody)
+  {
+    if (mWrappedResponse) {
+      return mWrappedResponse->SetAlternativeBody(aAlternativeBody);
+    }
+    // A request's body may not be reset once set.
+    MOZ_DIAGNOSTIC_ASSERT(!mAlternativeBody);
+
+    mAlternativeBody = aAlternativeBody;
+  }
+
+  already_AddRefed<nsIInputStream>
+  TakeAlternativeBody()
+  {
+    if (mWrappedResponse) {
+      return mWrappedResponse->TakeAlternativeBody();
+    }
+
+    if (!mAlternativeBody) {
+      return nullptr;
+    }
+
+    // cleanup the non-alternative body here.
+    // Once alternative data is used, the real body is no need anymore.
+    mBody = nullptr;
+    mBodySize = UNKNOWN_BODY_SIZE;
+    return mAlternativeBody.forget();
+  }
+
+  void
+  SetCacheInfoChannel(const nsMainThreadPtrHandle<nsICacheInfoChannel>& aCacheInfoChannel)
+  {
+    if (mWrappedResponse) {
+      return mWrappedResponse->SetCacheInfoChannel(aCacheInfoChannel);
+    }
+    MOZ_ASSERT(!mCacheInfoChannel);
+    mCacheInfoChannel = aCacheInfoChannel;
+  }
+
+  nsMainThreadPtrHandle<nsICacheInfoChannel>
+  TakeCacheInfoChannel()
+  {
+    if (mWrappedResponse) {
+      return mWrappedResponse->TakeCacheInfoChannel();
+    }
+    nsMainThreadPtrHandle<nsICacheInfoChannel> rtn = mCacheInfoChannel;
+    mCacheInfoChannel = nullptr;
+    return rtn;
+  }
+
+  void
   InitChannelInfo(nsIChannel* aChannel)
   {
     mChannelInfo.InitFromChannel(aChannel);
   }
 
   void
   InitChannelInfo(const mozilla::ipc::IPCChannelInfo& aChannelInfo)
   {
@@ -321,16 +374,21 @@ private:
   RefPtr<InternalHeaders> mHeaders;
   nsCOMPtr<nsIInputStream> mBody;
   int64_t mBodySize;
   // It's used to passed to the CacheResponse to generate padding size. Once, we
   // generate the padding size for resposne, we don't need it anymore.
   Maybe<uint32_t> mPaddingInfo;
   int64_t mPaddingSize;
   nsresult mErrorCode;
+
+  // For alternative data such as JS Bytecode cached in the HTTP cache.
+  nsCOMPtr<nsIInputStream> mAlternativeBody;
+  nsMainThreadPtrHandle<nsICacheInfoChannel> mCacheInfoChannel;
+
 public:
   static const int64_t UNKNOWN_BODY_SIZE = -1;
   static const int64_t UNKNOWN_PADDING_SIZE = -1;
 private:
   ChannelInfo mChannelInfo;
   UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
 
   // For filtered responses.
--- a/dom/html/HTMLFrameElement.h
+++ b/dom/html/HTMLFrameElement.h
@@ -95,17 +95,17 @@ public:
   {
     GetHTMLAttr(nsGkAtoms::scrolling, aScrolling);
   }
   void SetScrolling(const nsAString& aScrolling, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::scrolling, aScrolling, aError);
   }
 
-  void GetSrc(nsString& aSrc, nsIPrincipal&)
+  void GetSrc(nsString& aSrc)
   {
     GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
   }
   void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
   }
 
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -41,17 +41,17 @@ public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override;
 
   uint32_t GetSandboxFlags();
 
   // Web IDL binding methods
-  void GetSrc(nsString& aSrc, nsIPrincipal&) const
+  void GetSrc(nsString& aSrc) const
   {
     GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
   }
   void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
   }
   void GetSrcdoc(DOMString& aSrcdoc)
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -93,25 +93,25 @@ public:
   bool IsMap()
   {
     return GetBoolAttr(nsGkAtoms::ismap);
   }
   void SetIsMap(bool aIsMap, ErrorResult& aError)
   {
     SetHTMLBoolAttr(nsGkAtoms::ismap, aIsMap, aError);
   }
-  uint32_t Width()
+  MOZ_CAN_RUN_SCRIPT uint32_t Width()
   {
     return GetWidthHeightForImage(mCurrentRequest).width;
   }
   void SetWidth(uint32_t aWidth, ErrorResult& aError)
   {
     SetUnsignedIntAttr(nsGkAtoms::width, aWidth, 0, aError);
   }
-  uint32_t Height()
+  MOZ_CAN_RUN_SCRIPT uint32_t Height()
   {
     return GetWidthHeightForImage(mCurrentRequest).height;
   }
   void SetHeight(uint32_t aHeight, ErrorResult& aError)
   {
     SetUnsignedIntAttr(nsGkAtoms::height, aHeight, 0, aError);
   }
   uint32_t NaturalWidth();
@@ -137,33 +137,29 @@ public:
   void GetAlt(nsAString& aAlt)
   {
     GetHTMLAttr(nsGkAtoms::alt, aAlt);
   }
   void SetAlt(const nsAString& aAlt, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::alt, aAlt, aError);
   }
-  void GetSrc(nsAString& aSrc, nsIPrincipal&)
-  {
-    GetSrc(aSrc);
-  }
   void GetSrc(nsAString& aSrc)
   {
     GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
   }
   void SetSrc(const nsAString& aSrc, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
   }
   void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
   }
-  void GetSrcset(nsAString& aSrcset, nsIPrincipal&)
+  void GetSrcset(nsAString& aSrcset)
   {
     GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
   }
   void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, aError);
   }
   void GetCrossOrigin(nsAString& aResult)
@@ -236,18 +232,18 @@ public:
   }
 
   net::ReferrerPolicy
   GetImageReferrerPolicy() override
   {
     return GetReferrerPolicyAsEnum();
   }
 
-  int32_t X();
-  int32_t Y();
+  MOZ_CAN_RUN_SCRIPT int32_t X();
+  MOZ_CAN_RUN_SCRIPT int32_t Y();
   void GetLowsrc(nsAString& aLowsrc)
   {
     GetURIAttr(nsGkAtoms::lowsrc, nullptr, aLowsrc);
   }
   void SetLowsrc(const nsAString& aLowsrc, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::lowsrc, aLowsrc, aError);
   }
@@ -371,17 +367,17 @@ protected:
   // Given a <source> node that is a previous sibling *or* ourselves, try to
   // create a ResponsiveSelector.
 
   // If the node's srcset/sizes make for an invalid selector, returns
   // false. This does not guarantee the resulting selector matches an image,
   // only that it is valid.
   bool TryCreateResponsiveSelector(nsIContent *aSourceNode);
 
-  CSSIntPoint GetXY();
+  MOZ_CAN_RUN_SCRIPT CSSIntPoint GetXY();
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
   void UpdateFormOwner();
 
   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify) override;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -563,17 +563,17 @@ public:
   {
     GetHTMLAttr(nsGkAtoms::formtarget, aValue);
   }
   void SetFormTarget(const nsAString& aValue, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::formtarget, aValue, aRv);
   }
 
-  uint32_t Height();
+  MOZ_CAN_RUN_SCRIPT uint32_t Height();
 
   void SetHeight(uint32_t aValue, ErrorResult& aRv)
   {
     SetUnsignedIntAttr(nsGkAtoms::height, aValue, 0, aRv);
   }
 
   bool Indeterminate() const
   {
@@ -709,17 +709,17 @@ public:
     if (aValue == 0) {
       aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
       return;
     }
 
     SetUnsignedIntAttr(nsGkAtoms::size, aValue, DEFAULT_COLS, aRv);
   }
 
-  void GetSrc(nsAString& aValue, nsIPrincipal&)
+  void GetSrc(nsAString& aValue)
   {
     GetURIAttr(nsGkAtoms::src, nullptr, aValue);
   }
   void SetSrc(const nsAString& aValue, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::src, aValue, aTriggeringPrincipal, aRv);
   }
 
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -83,20 +83,16 @@ public:
   // WebIDL
   bool Disabled();
   void SetDisabled(bool aDisabled);
 
   void GetHref(nsAString& aValue)
   {
     GetURIAttr(nsGkAtoms::href, nullptr, aValue);
   }
-  void GetHref(nsString& aValue, nsIPrincipal&)
-  {
-    GetHref(aValue);
-  }
   void SetHref(const nsAString& aHref, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::href, aHref, aTriggeringPrincipal, aRv);
   }
   void SetHref(const nsAString& aHref, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::href, aHref, aRv);
   }
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -437,20 +437,16 @@ public:
    * cycle collection unlinking!
    */
   MediaStream* GetSrcMediaStream() const;
 
   // WebIDL
 
   MediaError* GetError() const;
 
-  void GetSrc(nsString& aSrc, nsIPrincipal&)
-  {
-    GetSrc(aSrc);
-  }
   void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aRv);
   }
 
   // XPCOM GetCurrentSrc() is OK
 
   void GetCrossOrigin(nsAString& aResult)
--- a/dom/html/HTMLSourceElement.h
+++ b/dom/html/HTMLSourceElement.h
@@ -49,17 +49,17 @@ public:
   static bool WouldMatchMediaForDocument(const nsAString& aMediaStr,
                                          const nsIDocument *aDocument);
 
   // Return the MediaSource object if any associated with the src attribute
   // when it was set.
   MediaSource* GetSrcMediaSource() { return mSrcMediaSource; };
 
   // WebIDL
-  void GetSrc(nsString& aSrc, nsIPrincipal&)
+  void GetSrc(nsString& aSrc)
   {
     GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
   }
   void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, rv);
   }
 
@@ -77,17 +77,17 @@ public:
   {
     GetHTMLAttr(nsGkAtoms::type, aType);
   }
   void SetType(const nsAString& aType, ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::type, aType, rv);
   }
 
-  void GetSrcset(DOMString& aSrcset, nsIPrincipal&)
+  void GetSrcset(DOMString& aSrcset)
   {
     GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
   }
   void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, rv);
   }
 
--- a/dom/html/ImageDocument.h
+++ b/dom/html/ImageDocument.h
@@ -60,17 +60,19 @@ public:
   {
     return mImageIsOverflowingHorizontally || mImageIsOverflowingVertically;
   }
   bool ImageIsResized() const
   {
     return mImageIsResized;
   }
   already_AddRefed<imgIRequest> GetImageRequest(ErrorResult& aRv);
-  void ShrinkToFit();
+  // ShrinkToFit is called from xpidl methods and we don't have a good
+  // way to mark those MOZ_CAN_RUN_SCRIPT yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void ShrinkToFit();
   void RestoreImage();
   void RestoreImageTo(int32_t aX, int32_t aY)
   {
     ScrollImageTo(aX, aY, true);
   }
   void ToggleImageSize();
 
 protected:
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -171,16 +171,17 @@ public:
   void SetSpellcheck(bool aSpellcheck, mozilla::ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::spellcheck,
                 aSpellcheck ? NS_LITERAL_STRING("true")
                             : NS_LITERAL_STRING("false"),
                 aError);
   }
 
+  MOZ_CAN_RUN_SCRIPT
   void GetInnerText(mozilla::dom::DOMString& aValue, mozilla::ErrorResult& aError);
   void SetInnerText(const nsAString& aValue);
 
   /**
    * Determine whether an attribute is an event (onclick, etc.)
    * @param aName the attribute
    * @return whether the name is an event handler name
    */
@@ -260,16 +261,17 @@ protected:
   virtual ~nsGenericHTMLElement() {}
 
 public:
   /**
    * Get width and height, using given image request if attributes are unset.
    * Pass a reference to the image request, since the method may change the
    * value and we want to use the updated value.
    */
+  MOZ_CAN_RUN_SCRIPT
   nsSize GetWidthHeightForImage(RefPtr<imgRequestProxy>& aImageRequest);
 
   // XPIDL methods
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
   NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
 
   NS_IMETHOD GetSpellcheck(bool* aSpellcheck) final override {
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -204,21 +204,17 @@ public:
        const nsAString& aFeatures,
        bool aReplace,
        mozilla::ErrorResult& rv);
   void Close(mozilla::ErrorResult& rv);
   void Write(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText,
              mozilla::ErrorResult& rv);
   void Writeln(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText,
                mozilla::ErrorResult& rv);
-  void GetDesignMode(nsAString& aDesignMode,
-                     nsIPrincipal& aSubjectPrincipal)
-  {
-    GetDesignMode(aDesignMode);
-  }
+  // XPCOM GetDesignMode is fine.
   void SetDesignMode(const nsAString& aDesignMode,
                      nsIPrincipal& aSubjectPrincipal,
                      mozilla::ErrorResult& rv);
   void SetDesignMode(const nsAString& aDesignMode,
                      const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal,
                      mozilla::ErrorResult& rv);
   bool ExecCommand(const nsAString& aCommandID, bool aDoShowUI,
                    const nsAString& aValue,
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -913,17 +913,17 @@ already_AddRefed<KnowsCompositor>
 MediaDecoder::GetCompositor()
 {
   MediaDecoderOwner* owner = GetOwner();
   nsIDocument* ownerDoc = owner ? owner->GetDocument() : nullptr;
   RefPtr<LayerManager> layerManager =
     ownerDoc ? nsContentUtils::LayerManagerForDocument(ownerDoc) : nullptr;
   RefPtr<KnowsCompositor> knows =
     layerManager ? layerManager->AsKnowsCompositor() : nullptr;
-  return knows.forget();
+  return knows ? knows->GetForMedia().forget() : nullptr;
 }
 
 void
 MediaDecoder::NotifyCompositor()
 {
   RefPtr<KnowsCompositor> knowsCompositor = GetCompositor();
   if (knowsCompositor) {
     nsCOMPtr<nsIRunnable> r =
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -118,17 +118,20 @@ private:
   }
   void Set(MediaResult* aError) { mError = aError; }
   void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
   void Set(UseNullDecoder aUseNullDecoder) { mUseNullDecoder = aUseNullDecoder; }
   void Set(OptionSet aOptions) { mOptions = aOptions; }
   void Set(VideoFrameRate aRate) { mRate = aRate; }
   void Set(layers::KnowsCompositor* aKnowsCompositor)
   {
-    mKnowsCompositor = aKnowsCompositor;
+    if (aKnowsCompositor) {
+      mKnowsCompositor = aKnowsCompositor;
+      MOZ_ASSERT(aKnowsCompositor->IsThreadSafe());
+    }
   }
   void Set(TrackInfo::TrackType aType)
   {
     mType = aType;
   }
   void Set(MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
   {
     mOnWaitingForKeyEvent = aOnWaitingForKey;
--- a/dom/plugins/base/npapi.h
+++ b/dom/plugins/base/npapi.h
@@ -468,16 +468,17 @@ typedef enum {
   , NPNVmuteAudioBool = 4000 /* Request that the browser wants to mute or unmute the plugin */
 #if defined(XP_WIN)
   , NPNVaudioDeviceChangeDetails = 4001 /* Provides information about the new default audio device */
 #endif
 #if defined(XP_MACOSX)
   , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
                                                                CA model compositing */
 #endif
+  , NPNVLast
 } NPNVariable;
 
 typedef enum {
   NPNURLVCookie = 501,
   NPNURLVProxy
 } NPNURLVariable;
 
 /*
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -368,40 +368,21 @@ struct ParamTraits<NPRect>
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     aLog->append(StringPrintf(L"[%u, %u, %u, %u]", aParam.top, aParam.left,
                               aParam.bottom, aParam.right));
   }
 };
 
 template <>
-struct ParamTraits<NPWindowType>
-{
-  typedef NPWindowType paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    aMsg->WriteInt16(int16_t(aParam));
-  }
-
-  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
-  {
-    int16_t result;
-    if (aMsg->ReadInt16(aIter, &result)) {
-      *aResult = paramType(result);
-      return true;
-    }
-    return false;
-  }
-
-  static void Log(const paramType& aParam, std::wstring* aLog)
-  {
-    aLog->append(StringPrintf(L"%d", int16_t(aParam)));
-  }
-};
+struct ParamTraits<NPWindowType> :
+  public ContiguousEnumSerializerInclusive<NPWindowType,
+                                           NPWindowType::NPWindowTypeWindow,
+                                           NPWindowType::NPWindowTypeDrawable>
+{};
 
 template <>
 struct ParamTraits<mozilla::plugins::NPRemoteWindow>
 {
   typedef mozilla::plugins::NPRemoteWindow paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
@@ -665,86 +646,36 @@ struct ParamTraits<mozilla::plugins::IPC
       *aResult = p;
       return true;
     }
     return false;
   }
 };
 
 template <>
-struct ParamTraits<NPNVariable>
-{
-  typedef NPNVariable paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    WriteParam(aMsg, int(aParam));
-  }
+struct ParamTraits<NPNVariable> :
+  public ContiguousEnumSerializer<NPNVariable,
+                                  NPNVariable::NPNVxDisplay,
+                                  NPNVariable::NPNVLast>
+{};
 
-  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
-  {
-    int intval;
-    if (ReadParam(aMsg, aIter, &intval)) {
-      *aResult = paramType(intval);
-      return true;
-    }
-    return false;
-  }
-};
+// The only accepted value is NPNURLVariable::NPNURLVProxy
+template<>
+struct ParamTraits<NPNURLVariable> :
+  public ContiguousEnumSerializerInclusive<NPNURLVariable,
+                                           NPNURLVariable::NPNURLVProxy,
+                                           NPNURLVariable::NPNURLVProxy>
+{};
 
 template<>
-struct ParamTraits<NPNURLVariable>
-{
-  typedef NPNURLVariable paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    WriteParam(aMsg, int(aParam));
-  }
-
-  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
-  {
-    int intval;
-    if (ReadParam(aMsg, aIter, &intval) &&
-        intval == NPNURLVProxy) {
-      *aResult = paramType(intval);
-      return true;
-    }
-    return false;
-  }
-};
-
-
-template<>
-struct ParamTraits<NPCoordinateSpace>
-{
-  typedef NPCoordinateSpace paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    WriteParam(aMsg, int32_t(aParam));
-  }
-
-  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
-  {
-    int32_t intval;
-    if (ReadParam(aMsg, aIter, &intval)) {
-      switch (intval) {
-      case NPCoordinateSpacePlugin:
-      case NPCoordinateSpaceWindow:
-      case NPCoordinateSpaceFlippedWindow:
-      case NPCoordinateSpaceScreen:
-      case NPCoordinateSpaceFlippedScreen:
-        *aResult = paramType(intval);
-        return true;
-      }
-    }
-    return false;
-  }
-};
+struct ParamTraits<NPCoordinateSpace> :
+  public ContiguousEnumSerializerInclusive<NPCoordinateSpace,
+                                           NPCoordinateSpace::NPCoordinateSpacePlugin,
+                                           NPCoordinateSpace::NPCoordinateSpaceFlippedScreen>
+{};
 
 template <>
 struct ParamTraits<mozilla::plugins::NPAudioDeviceChangeDetailsIPC>
 {
   typedef mozilla::plugins::NPAudioDeviceChangeDetailsIPC paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -4,23 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/U2F.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/WebCryptoCommon.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/dom/WebAuthnTransactionChild.h"
 #include "nsContentUtils.h"
 #include "nsICryptoHash.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsURLParsers.h"
-#include "U2FTransactionChild.h"
 #include "U2FUtil.h"
 #include "hasht.h"
 
 using namespace mozilla::ipc;
 
 // Forward decl because of nsHTMLDocument.h's complex dependency on /layout/style
 class nsHTMLDocument {
 public:
@@ -288,19 +288,19 @@ U2F::~U2F()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mTransaction.isSome()) {
     RejectTransaction(NS_ERROR_ABORT);
   }
 
   if (mChild) {
-    RefPtr<U2FTransactionChild> c;
+    RefPtr<WebAuthnTransactionChild> c;
     mChild.swap(c);
-    c->Send__delete__(c);
+    c->Disconnect();
   }
 
   mRegisterCallback.reset();
   mSignCallback.reset();
 }
 
 void
 U2F::Init(ErrorResult& aRv)
@@ -432,18 +432,18 @@ U2F::Register(const nsAString& aAppId,
                                   authSelection);
 
   MOZ_ASSERT(mTransaction.isNothing());
   mTransaction = Some(U2FTransaction(clientData));
   mChild->SendRequestRegister(mTransaction.ref().mId, info);
 }
 
 void
-U2F::FinishRegister(const uint64_t& aTransactionId,
-                    nsTArray<uint8_t>& aRegBuffer)
+U2F::FinishMakeCredential(const uint64_t& aTransactionId,
+                          nsTArray<uint8_t>& aRegBuffer)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Check for a valid transaction.
   if (mTransaction.isNothing() || mTransaction.ref().mId != aTransactionId) {
     return;
   }
 
@@ -561,19 +561,19 @@ U2F::Sign(const nsAString& aAppId,
                                 extensions);
 
   MOZ_ASSERT(mTransaction.isNothing());
   mTransaction = Some(U2FTransaction(clientData));
   mChild->SendRequestSign(mTransaction.ref().mId, info);
 }
 
 void
-U2F::FinishSign(const uint64_t& aTransactionId,
-                nsTArray<uint8_t>& aCredentialId,
-                nsTArray<uint8_t>& aSigBuffer)
+U2F::FinishGetAssertion(const uint64_t& aTransactionId,
+                        nsTArray<uint8_t>& aCredentialId,
+                        nsTArray<uint8_t>& aSigBuffer)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Check for a valid transaction.
   if (mTransaction.isNothing() || mTransaction.ref().mId != aTransactionId) {
     return;
   }
 
@@ -744,17 +744,17 @@ U2F::MaybeCreateBackgroundActor()
     return true;
   }
 
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actorChild)) {
     return false;
   }
 
-  RefPtr<U2FTransactionChild> mgr(new U2FTransactionChild(this));
+  RefPtr<WebAuthnTransactionChild> mgr(new WebAuthnTransactionChild(this));
   PWebAuthnTransactionChild* constructedMgr =
     actorChild->SendPWebAuthnTransactionConstructor(mgr);
 
   if (NS_WARN_IF(!constructedMgr)) {
     return false;
   }
 
   MOZ_ASSERT(constructedMgr == mgr);
--- a/dom/u2f/U2F.h
+++ b/dom/u2f/U2F.h
@@ -7,29 +7,30 @@
 #ifndef mozilla_dom_U2F_h
 #define mozilla_dom_U2F_h
 
 #include "js/TypeDecls.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/U2FBinding.h"
+#include "mozilla/dom/WebAuthnManagerBase.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/MozPromise.h"
 #include "nsProxyRelease.h"
 #include "nsWrapperCache.h"
 #include "U2FAuthenticator.h"
 #include "nsIDOMEventListener.h"
 
 class nsISerialEventTarget;
 
 namespace mozilla {
 namespace dom {
 
-class U2FTransactionChild;
+class WebAuthnTransactionChild;
 class U2FRegisterCallback;
 class U2FSignCallback;
 
 // Defined in U2FBinding.h by the U2F.webidl; their use requires a JSContext.
 struct RegisterRequest;
 struct RegisteredKey;
 
 class U2FTransaction
@@ -54,16 +55,17 @@ private:
   // transactions, where messages can intersect. Can overflow.
   static uint64_t NextId() {
     static uint64_t id = 0;
     return ++id;
   }
 };
 
 class U2F final : public nsIDOMEventListener
+                , public WebAuthnManagerBase
                 , public nsWrapperCache
 {
 public:
   NS_DECL_NSIDOMEVENTLISTENER
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(U2F)
 
@@ -92,28 +94,32 @@ public:
   void
   Sign(const nsAString& aAppId,
        const nsAString& aChallenge,
        const Sequence<RegisteredKey>& aRegisteredKeys,
        U2FSignCallback& aCallback,
        const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
        ErrorResult& aRv);
 
+  // WebAuthnManagerBase
+
   void
-  FinishRegister(const uint64_t& aTransactionId, nsTArray<uint8_t>& aRegBuffer);
+  FinishMakeCredential(const uint64_t& aTransactionId,
+                       nsTArray<uint8_t>& aRegBuffer) override;
 
   void
-  FinishSign(const uint64_t& aTransactionId,
-             nsTArray<uint8_t>& aCredentialId,
-             nsTArray<uint8_t>& aSigBuffer);
+  FinishGetAssertion(const uint64_t& aTransactionId,
+                     nsTArray<uint8_t>& aCredentialId,
+                     nsTArray<uint8_t>& aSigBuffer) override;
 
   void
-  RequestAborted(const uint64_t& aTransactionId, const nsresult& aError);
+  RequestAborted(const uint64_t& aTransactionId,
+                 const nsresult& aError) override;
 
-  void ActorDestroyed();
+  void ActorDestroyed() override;
 
 private:
   ~U2F();
 
   // Visibility event handling.
   void ListenForVisibilityEvents();
   void StopListeningForVisibilityEvents();
 
@@ -130,17 +136,17 @@ private:
   nsString mOrigin;
   nsCOMPtr<nsPIDOMWindowInner> mParent;
 
   // U2F API callbacks.
   Maybe<nsMainThreadPtrHandle<U2FRegisterCallback>> mRegisterCallback;
   Maybe<nsMainThreadPtrHandle<U2FSignCallback>> mSignCallback;
 
   // IPC Channel to the parent process.
-  RefPtr<U2FTransactionChild> mChild;
+  RefPtr<WebAuthnTransactionChild> mChild;
 
   // The current transaction, if any.
   Maybe<U2FTransaction> mTransaction;
 };
 
 } // namespace dom
 } // namespace mozilla
 
deleted file mode 100644
--- a/dom/u2f/U2FTransactionChild.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "U2FTransactionChild.h"
-
-namespace mozilla {
-namespace dom {
-
-mozilla::ipc::IPCResult
-U2FTransactionChild::RecvConfirmRegister(const uint64_t& aTransactionId,
-                                         nsTArray<uint8_t>&& aRegBuffer)
-{
-  mU2F->FinishRegister(aTransactionId, aRegBuffer);
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-U2FTransactionChild::RecvConfirmSign(const uint64_t& aTransactionId,
-                                     nsTArray<uint8_t>&& aCredentialId,
-                                     nsTArray<uint8_t>&& aBuffer)
-{
-  mU2F->FinishSign(aTransactionId, aCredentialId, aBuffer);
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-U2FTransactionChild::RecvAbort(const uint64_t& aTransactionId,
-                               const nsresult& aError)
-{
-  mU2F->RequestAborted(aTransactionId, aError);
-  return IPC_OK();
-}
-
-void
-U2FTransactionChild::ActorDestroy(ActorDestroyReason why)
-{
-  mU2F->ActorDestroyed();
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/u2f/U2FTransactionChild.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_U2FTransactionChild_h
-#define mozilla_dom_U2FTransactionChild_h
-
-#include "mozilla/dom/WebAuthnTransactionChildBase.h"
-
-/*
- * Child process IPC implementation for U2F API. Receives results of U2F
- * transactions from the parent process, and sends them to the U2FManager
- * to either cancel the transaction, or be formatted and relayed to content.
- */
-
-namespace mozilla {
-namespace dom {
-
-class U2FTransactionChild final : public WebAuthnTransactionChildBase
-{
-public:
-  explicit U2FTransactionChild(U2F* aU2F) : mU2F(aU2F) {
-    MOZ_ASSERT(mU2F);
-  }
-
-  mozilla::ipc::IPCResult
-  RecvConfirmRegister(const uint64_t& aTransactionId,
-                      nsTArray<uint8_t>&& aRegBuffer) override;
-
-  mozilla::ipc::IPCResult
-  RecvConfirmSign(const uint64_t& aTransactionId,
-                  nsTArray<uint8_t>&& aCredentialId,
-                  nsTArray<uint8_t>&& aBuffer) override;
-
-  mozilla::ipc::IPCResult
-  RecvAbort(const uint64_t& aTransactionId, const nsresult& aError) override;
-
-  void ActorDestroy(ActorDestroyReason why) override;
-
-private:
-  // ~U2F() will destroy child actors.
-  U2F* mU2F;
-};
-
-}
-}
-
-#endif //mozilla_dom_U2FTransactionChild_h
deleted file mode 100644
--- a/dom/u2f/U2FTransactionParent.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "U2FTransactionParent.h"
-#include "mozilla/dom/U2FTokenManager.h"
-#include "mozilla/ipc/BackgroundParent.h"
-
-namespace mozilla {
-namespace dom {
-
-mozilla::ipc::IPCResult
-U2FTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
-                                          const WebAuthnMakeCredentialInfo& aTransactionInfo)
-{
-  AssertIsOnBackgroundThread();
-  U2FTokenManager* mgr = U2FTokenManager::Get();
-  mgr->Register(this, aTransactionId, aTransactionInfo);
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-U2FTransactionParent::RecvRequestSign(const uint64_t& aTransactionId,
-                                      const WebAuthnGetAssertionInfo& aTransactionInfo)
-{
-  AssertIsOnBackgroundThread();
-  U2FTokenManager* mgr = U2FTokenManager::Get();
-  mgr->Sign(this, aTransactionId, aTransactionInfo);
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-U2FTransactionParent::RecvRequestCancel(const uint64_t& aTransactionId)
-{
-  AssertIsOnBackgroundThread();
-  U2FTokenManager* mgr = U2FTokenManager::Get();
-  mgr->Cancel(this, aTransactionId);
-  return IPC_OK();
-}
-
-void
-U2FTransactionParent::ActorDestroy(ActorDestroyReason aWhy)
-{
-  AssertIsOnBackgroundThread();
-  U2FTokenManager* mgr = U2FTokenManager::Get();
-  mgr->MaybeClearTransaction(this);
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/u2f/U2FTransactionParent.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_U2FTransactionParent_h
-#define mozilla_dom_U2FTransactionParent_h
-
-#include "mozilla/dom/PWebAuthnTransactionParent.h"
-
-/*
- * Parent process IPC implementation for WebAuthn and U2F API. Receives
- * authentication data to be either registered or signed by a key, passes
- * information to U2FTokenManager.
- */
-
-namespace mozilla {
-namespace dom {
-
-class U2FTransactionParent final : public PWebAuthnTransactionParent
-{
-public:
-  NS_INLINE_DECL_REFCOUNTING(U2FTransactionParent);
-  U2FTransactionParent() = default;
-
-  virtual mozilla::ipc::IPCResult
-  RecvRequestRegister(const uint64_t& aTransactionId,
-                      const WebAuthnMakeCredentialInfo& aTransactionInfo) override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvRequestSign(const uint64_t& aTransactionId,
-                  const WebAuthnGetAssertionInfo& aTransactionInfo) override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvRequestCancel(const uint64_t& aTransactionId) override;
-
-  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
-private:
-  ~U2FTransactionParent() = default;
-};
-
-}
-}
-
-#endif //mozilla_dom_U2FTransactionParent_h
--- a/dom/u2f/moz.build
+++ b/dom/u2f/moz.build
@@ -10,18 +10,16 @@ with Files("**"):
 EXPORTS.mozilla.dom += [
     'U2F.h',
     'U2FAuthenticator.h',
     'U2FUtil.h',
 ]
 
 UNIFIED_SOURCES += [
     'U2F.cpp',
-    'U2FTransactionChild.cpp',
-    'U2FTransactionParent.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/dom/base',
--- a/dom/vr/test/mochitest/VRSimulationDriver.js
+++ b/dom/vr/test/mochitest/VRSimulationDriver.js
@@ -1,16 +1,20 @@
 
 var VRServiceTest;
 var vrMockDisplay;
 
 var VRSimulationDriver = (function() {
 "use strict";
 
 var AttachWebVRDisplay = function() {
+  if (vrMockDisplay) {
+    // Avoid creating multiple displays
+    return Promise.resolve(vrMockDisplay);
+  }
   var promise = VRServiceTest.attachVRDisplay("VRDisplayTest");
   promise.then(function (display) {
     assert_true(display != null, "AttachWebVRDisplay should success.");
     vrMockDisplay = display;
   });
 
   return promise;
 };
--- a/dom/vr/test/mochitest/mochitest.ini
+++ b/dom/vr/test/mochitest/mochitest.ini
@@ -9,13 +9,14 @@ support-files =
 [test_vrController_displayId.html]
 # Enable Linux after Bug 1310655 # TIMED_OUT for Android.
 skip-if = (os != "win" && release_or_beta) || (os == "android")
 [test_vrDisplay_canvas2d.html]
 skip-if = (os != "win" && release_or_beta) # Enable Linux after Bug 1310655
 [test_vrDisplay_exitPresent.html]
 skip-if = (os != "win" && release_or_beta) # Enable Linux after Bug 1310655
 [test_vrDisplay_getFrameData.html]
-skip-if = (os != "win" && release_or_beta) # Enable Linux after Bug 1310655
+# Enable Linux after Bug 1310655, enable Android after Bug 1348246
+skip-if = (os != "win" && release_or_beta) || (os == "android")
 [test_vrDisplay_onvrdisplaydeactivate_crosscontent.html]
 skip-if = true
 [test_vrDisplay_requestPresent.html]
 skip-if = true
--- a/dom/vr/test/mochitest/runVRTest.js
+++ b/dom/vr/test/mochitest/runVRTest.js
@@ -1,9 +1,11 @@
 function runVRTest(callback) {
   SpecialPowers.pushPrefEnv({"set" : [["dom.vr.puppet.enabled", true],
                                       ["dom.vr.require-gesture", false],
-                                      ["dom.vr.test.enabled", true]]},
+                                      ["dom.vr.test.enabled", true],
+                                      ["dom.vr.display.enumerate.interval", 0],
+                                      ["dom.vr.controller.enumerate.interval", 0]]},
   () => {
     VRServiceTest = navigator.requestVRServiceTest();
     callback();
   });
 }
\ No newline at end of file
--- a/dom/vr/test/mochitest/test_vrController_displayId.html
+++ b/dom/vr/test/mochitest/test_vrController_displayId.html
@@ -33,22 +33,23 @@
               }
           });
         }, "Finish to verify VRController.displayId.");
       }
 
       function startTest() {
         promise_test((test) => {
           listenControllerEvents();
-          return navigator.getVRDisplays().then((displays) => {
-            vrDisplay = displays[0];
-            assert_equals(displays.length, 1, "displays.length must be one after attach.");
-            assert_equals(displays[0].displayId, 1, "displayId must be one.");
-            addController();
-            addController();
+          return VRSimulationDriver.AttachWebVRDisplay().then(() => {
+            return navigator.getVRDisplays().then((displays) => {
+              vrDisplay = displays[0];
+              assert_equals(displays.length, 1, "displays.length must be one after attach.");
+              addController();
+              addController();
+            });
           });
         }, "Finish to add VRDisplay.");
       }
 
       runVRTest(startTest);
     </script>
   </body>
 </html>
\ No newline at end of file
--- a/dom/vr/test/mochitest/test_vrDisplay_canvas2d.html
+++ b/dom/vr/test/mochitest/test_vrDisplay_canvas2d.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
   <head>
     <title>VRDisplay Canvas2D</title>
     <meta name="timeout" content="long"/>
     <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
+    <script src="VRSimulationDriver.js"></script>
     <script src="runVRTest.js"></script>
   </head>
   <body>
     <script>
       "use strict";
       var vrDisplay;
 
       function requestPresentTest() {
@@ -30,22 +31,24 @@
       function startTest() {
         promise_test((test) => {
           var canvas = document.createElement('canvas');
           (document.body || document.documentElement).appendChild(canvas);
           var context = canvas.getContext('2d');
           var img = document.createElement('img');
           img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACw=";
 
-          return navigator.getVRDisplays().then((displays) => {
-            assert_equals(displays.length, 1, "displays.length must be one after attach.");
-            vrDisplay = displays[0];
-            var frameData = new VRFrameData();
-            return vrDisplay.requestPresent([{source: canvas}]).then(() => {
-              requestPresentTest();
+          return VRSimulationDriver.AttachWebVRDisplay().then(() => {
+            return navigator.getVRDisplays().then((displays) => {
+              assert_equals(displays.length, 1, "displays.length must be one after attach.");
+              vrDisplay = displays[0];
+              var frameData = new VRFrameData();
+              return vrDisplay.requestPresent([{source: canvas}]).then(() => {
+                requestPresentTest();
+              });
             });
           });
         }, "Finish running WebVR Canvas2D test.");
       }
 
       runVRTest(startTest);
     </script>
   </body>
--- a/dom/vr/test/mochitest/test_vrDisplay_exitPresent.html
+++ b/dom/vr/test/mochitest/test_vrDisplay_exitPresent.html
@@ -1,44 +1,51 @@
 <!DOCTYPE html>
 <html>
   <head>
     <title>VRDisplay ExitPresent</title>
     <meta name="timeout" content="long"/>
     <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
+    <script src="VRSimulationDriver.js"></script>
     <script src="runVRTest.js"></script>
   </head>
   <body>
     <script>
       function testExitPresentOnOtherIframe(content) {
           return content.navigator.getVRDisplays().then((displays) => {
             content.vrDisplay = displays[0];
             return content.vrDisplay.exitPresent();
         });
       }
       var initVRPresentation = function(content) {
-            return content.navigator.getVRDisplays().then((displays) => {
+        return VRSimulationDriver.AttachWebVRDisplay().then(() => {
+          return content.navigator.getVRDisplays().then((displays) => {
             content.vrDisplay = displays[0];
             content.canvas = content.document.createElement("canvas");
             content.canvas.id = "vrCanvas";
             return content.vrDisplay.requestPresent([{source:content.canvas}]);
           });
+        });
       }
       function startTest() {
         var ifr1 = document.getElementById("iframe1");
         var ifr2 = document.getElementById("iframe2");
         var frame1 = ifr1.contentWindow;
         var frame2 = ifr2.contentWindow;
-        initVRPresentation(frame1).then(() => {
-          promise_test((test) => {
-            return promise_rejects(test, null, testExitPresentOnOtherIframe(frame2));
-          }, "We cannot exist VR presentation established by another content, this promise is expected to be rejected.")
-        });
+        promise_test((test) => {
+          return VRSimulationDriver.AttachWebVRDisplay().then(() => {
+            return initVRPresentation(frame1).then(() => {
+              promise_test((test) => {
+                return promise_rejects(test, null, testExitPresentOnOtherIframe(frame2));
+              }, "We cannot exit VR presentation established by another content, this promise is expected to be rejected.")
+            });
+          });
+        }, "Finish running WebVR exitPresent test.");
       }
       runVRTest(startTest);
     </script>
 
     <iframe id="iframe1"></iframe>
     <iframe id="iframe2"></iframe>
   </body>
 </html>
\ No newline at end of file
--- a/dom/vr/test/reftest/VRSimulationDriver.js
+++ b/dom/vr/test/reftest/VRSimulationDriver.js
@@ -1,16 +1,20 @@
 
 var VRServiceTest;
 var vrMockDisplay;
 
 var VRSimulationDriver = (function() {
 "use strict";
 
 var AttachWebVRDisplay = function() {
+  if (vrMockDisplay) {
+    // Avoid creating multiple displays
+    return Promise.resolve(vrMockDisplay);
+  }
   var promise = VRServiceTest.attachVRDisplay("VRDisplayTest");
   promise.then(function (display) {
     vrMockDisplay = display;
   });
 
   return promise;
 };
 
--- a/dom/vr/test/reftest/reftest.list
+++ b/dom/vr/test/reftest/reftest.list
@@ -1,10 +1,10 @@
 # WebVR Reftests
 # Please confirm there is no other VR display connected. Otherwise, VRPuppetDisplay can't be attached.
-default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1) pref(dom.vr.display.rafMaxDuration,200)
+default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1) pref(dom.vr.display.rafMaxDuration,200) pref(dom.vr.display.enumerate.interval,0) pref(dom.vr.controller.enumerate.interval,0)
 
 # VR SubmitFrame is only implemented for D3D11.1 and MacOSX now.
 # Our Windows 7 test machines don't support D3D11.1, so we run these tests on Windows 8+ only.
 skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||!layersGPUAccelerated||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == draw_rect.html wrapper.html?draw_rect.png
 # On MacOSX platform, getting different color interpolation result.
 # For lower resolution Mac hardware, we need to adjust it to fuzzy-if(cocoaWidget,1,1200).
 fuzzy-if(cocoaWidget,1,600) skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||!layersGPUAccelerated||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == change_size.html wrapper.html?change_size.png
--- a/dom/webauthn/PWebAuthnTransaction.ipdl
+++ b/dom/webauthn/PWebAuthnTransaction.ipdl
@@ -47,21 +47,24 @@ struct WebAuthnGetAssertionInfo {
   uint8_t[] ClientDataHash;
   uint32_t TimeoutMS;
   WebAuthnScopedCredentialDescriptor[] AllowList;
   WebAuthnExtension[] Extensions;
 };
 
 async protocol PWebAuthnTransaction {
   manager PBackground;
+
   parent:
-    async __delete__();
     async RequestRegister(uint64_t aTransactionId, WebAuthnMakeCredentialInfo aTransactionInfo);
     async RequestSign(uint64_t aTransactionId, WebAuthnGetAssertionInfo aTransactionInfo);
     async RequestCancel(uint64_t aTransactionId);
+    async DestroyMe();
+
   child:
+    async __delete__();
     async ConfirmRegister(uint64_t aTransactionId, uint8_t[] RegBuffer);
     async ConfirmSign(uint64_t aTransactionId, uint8_t[] CredentialID, uint8_t[] ReplyBuffer);
     async Abort(uint64_t aTransactionId, nsresult Error);
 };
 
 }
 }
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -4,17 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "hasht.h"
 #include "nsICryptoHash.h"
 #include "nsNetCID.h"
 #include "nsThreadUtils.h"
 #include "WebAuthnCoseIdentifiers.h"
-#include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/AuthenticatorAttestationResponse.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PWebAuthnTransaction.h"
 #include "mozilla/dom/U2FUtil.h"
 #include "mozilla/dom/WebAuthnCBORUtil.h"
 #include "mozilla/dom/WebAuthnManager.h"
 #include "mozilla/dom/WebAuthnTransactionChild.h"
 #include "mozilla/dom/WebAuthnUtil.h"
@@ -35,17 +34,16 @@ const uint8_t FLAG_AT = 0x40; // Authent
 const uint8_t FLAG_UV = 0x04; // User was Verified (biometrics, etc.); this
                               // flag is not possible with U2F devices
 
 /***********************************************************************
  * Statics
  **********************************************************************/
 
 namespace {
-StaticRefPtr<WebAuthnManager> gWebAuthnManager;
 static mozilla::LazyLogModule gWebAuthnManagerLog("webauthnmanager");
 }
 
 NS_NAMED_LITERAL_STRING(kVisibilityChange, "visibilitychange");
 
 NS_IMPL_ISUPPORTS(WebAuthnManager, nsIDOMEventListener);
 
 /***********************************************************************
@@ -142,65 +140,59 @@ RelaxSameOrigin(nsPIDOMWindowInner* aPar
   if (!html->IsRegistrableDomainSuffixOfOrEqualTo(aInputRpId, originHost)) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   aRelaxedRpId.Assign(NS_ConvertUTF16toUTF8(aInputRpId));
   return NS_OK;
 }
 
-static void
-ListenForVisibilityEvents(nsPIDOMWindowInner* aParent,
-                          WebAuthnManager* aListener)
+void
+WebAuthnManager::ListenForVisibilityEvents()
 {
-  MOZ_ASSERT(aParent);
-  MOZ_ASSERT(aListener);
-
-  nsCOMPtr<nsIDocument> doc = aParent->GetExtantDoc();
+  nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
   if (NS_WARN_IF(!doc)) {
     return;
   }
 
-  nsresult rv = doc->AddSystemEventListener(kVisibilityChange, aListener,
+  nsresult rv = doc->AddSystemEventListener(kVisibilityChange, this,
                                             /* use capture */ true,
                                             /* wants untrusted */ false);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 }
 
-static void
-StopListeningForVisibilityEvents(nsPIDOMWindowInner* aParent,
-                                 WebAuthnManager* aListener)
+void
+WebAuthnManager::StopListeningForVisibilityEvents()
 {
-  MOZ_ASSERT(aParent);
-  MOZ_ASSERT(aListener);
-
-  nsCOMPtr<nsIDocument> doc = aParent->GetExtantDoc();
+  nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
   if (NS_WARN_IF(!doc)) {
     return;
   }
 
-  nsresult rv = doc->RemoveSystemEventListener(kVisibilityChange, aListener,
+  nsresult rv = doc->RemoveSystemEventListener(kVisibilityChange, this,
                                                /* use capture */ true);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 }
 
 /***********************************************************************
  * WebAuthnManager Implementation
  **********************************************************************/
 
-WebAuthnManager::WebAuthnManager()
+WebAuthnManager::WebAuthnManager(nsPIDOMWindowInner* aParent)
+  : mParent(aParent)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aParent);
 }
 
 void
 WebAuthnManager::ClearTransaction()
 {
   if (!NS_WARN_IF(mTransaction.isNothing())) {
-    StopListeningForVisibilityEvents(mTransaction.ref().mParent, this);
+    StopListeningForVisibilityEvents();
   }
 
   mTransaction.reset();
   Unfollow();
 }
 
 void
 WebAuthnManager::RejectTransaction(const nsresult& aError)
@@ -228,17 +220,17 @@ WebAuthnManager::~WebAuthnManager()
 
   if (mTransaction.isSome()) {
     RejectTransaction(NS_ERROR_ABORT);
   }
 
   if (mChild) {
     RefPtr<WebAuthnTransactionChild> c;
     mChild.swap(c);
-    c->Send__delete__(c);
+    c->Disconnect();
   }
 }
 
 bool
 WebAuthnManager::MaybeCreateBackgroundActor()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -246,82 +238,57 @@ WebAuthnManager::MaybeCreateBackgroundAc
     return true;
   }
 
   PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actor)) {
     return false;
   }
 
-  RefPtr<WebAuthnTransactionChild> mgr(new WebAuthnTransactionChild());
+  RefPtr<WebAuthnTransactionChild> mgr(new WebAuthnTransactionChild(this));
   PWebAuthnTransactionChild* constructedMgr =
     actor->SendPWebAuthnTransactionConstructor(mgr);
 
   if (NS_WARN_IF(!constructedMgr)) {
     return false;
   }
 
   MOZ_ASSERT(constructedMgr == mgr);
   mChild = mgr.forget();
 
   return true;
 }
 
-//static
-WebAuthnManager*
-WebAuthnManager::GetOrCreate()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (gWebAuthnManager) {
-    return gWebAuthnManager;
-  }
-
-  gWebAuthnManager = new WebAuthnManager();
-  ClearOnShutdown(&gWebAuthnManager);
-  return gWebAuthnManager;
-}
-
-//static
-WebAuthnManager*
-WebAuthnManager::Get()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return gWebAuthnManager;
-}
-
 already_AddRefed<Promise>
-WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
-                                const MakePublicKeyCredentialOptions& aOptions,
+WebAuthnManager::MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
                                 const Optional<OwningNonNull<AbortSignal>>& aSignal)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aParent);
 
   if (mTransaction.isSome()) {
     CancelTransaction(NS_ERROR_ABORT);
   }
 
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(global, rv);
   if (rv.Failed()) {
     return nullptr;
   }
 
   // Abort the request if aborted flag is already set.
   if (aSignal.WasPassed() && aSignal.Value().Aborted()) {
     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     return promise.forget();
   }
 
   nsString origin;
   nsCString rpId;
-  rv = GetOrigin(aParent, origin, rpId);
+  rv = GetOrigin(mParent, origin, rpId);
   if (NS_WARN_IF(rv.Failed())) {
     promise->MaybeReject(rv);
     return promise.forget();
   }
 
   // Enforce 4.4.3 User Account Parameters for Credential Generation
   if (aOptions.mUser.mId.WasPassed()) {
     // When we add UX, we'll want to do more with this value, but for now
@@ -349,17 +316,17 @@ WebAuthnManager::MakeCredential(nsPIDOMW
     // If rpId is specified, then invoke the procedure used for relaxing the
     // same-origin restriction by setting the document.domain attribute, using
     // rpId as the given value but without changing the current document’s
     // domain. If no errors are thrown, set rpId to the value of host as
     // computed by this procedure, and rpIdHash to the SHA-256 hash of rpId.
     // Otherwise, reject promise with a DOMException whose name is
     // "SecurityError", and terminate this algorithm.
 
-    if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRp.mId.Value(), rpId))) {
+    if (NS_FAILED(RelaxSameOrigin(mParent, aOptions.mRp.mId.Value(), rpId))) {
       promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
       return promise.forget();
     }
   }
 
   CryptoBuffer rpIdHash;
   if (!rpIdHash.SetLength(SHA256_LENGTH, fallible)) {
     promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
@@ -493,64 +460,61 @@ WebAuthnManager::MakeCredential(nsPIDOMW
 
   WebAuthnMakeCredentialInfo info(rpIdHash,
                                   clientDataHash,
                                   adjustedTimeout,
                                   excludeList,
                                   extensions,
                                   authSelection);
 
-  ListenForVisibilityEvents(aParent, this);
+  ListenForVisibilityEvents();
 
   AbortSignal* signal = nullptr;
   if (aSignal.WasPassed()) {
     signal = &aSignal.Value();
     Follow(signal);
   }
 
   MOZ_ASSERT(mTransaction.isNothing());
-  mTransaction = Some(WebAuthnTransaction(aParent,
-                                          promise,
+  mTransaction = Some(WebAuthnTransaction(promise,
                                           rpIdHash,
                                           clientDataJSON,
                                           signal));
 
   mChild->SendRequestRegister(mTransaction.ref().mId, info);
   return promise.forget();
 }
 
 already_AddRefed<Promise>
-WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
-                              const PublicKeyCredentialRequestOptions& aOptions,
+WebAuthnManager::GetAssertion(const PublicKeyCredentialRequestOptions& aOptions,
                               const Optional<OwningNonNull<AbortSignal>>& aSignal)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aParent);
 
   if (mTransaction.isSome()) {
     CancelTransaction(NS_ERROR_ABORT);
   }
 
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(global, rv);
   if (rv.Failed()) {
     return nullptr;
   }
 
   // Abort the request if aborted flag is already set.
   if (aSignal.WasPassed() && aSignal.Value().Aborted()) {
     promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     return promise.forget();
   }
 
   nsString origin;
   nsCString rpId;
-  rv = GetOrigin(aParent, origin, rpId);
+  rv = GetOrigin(mParent, origin, rpId);
   if (NS_WARN_IF(rv.Failed())) {
     promise->MaybeReject(rv);
     return promise.forget();
   }
 
   // If timeoutSeconds was specified, check if its value lies within a
   // reasonable range as defined by the platform and if not, correct it to the
   // closest value lying within that range.
@@ -566,17 +530,17 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
     // If rpId is specified, then invoke the procedure used for relaxing the
     // same-origin restriction by setting the document.domain attribute, using
     // rpId as the given value but without changing the current document’s
     // domain. If no errors are thrown, set rpId to the value of host as
     // computed by this procedure, and rpIdHash to the SHA-256 hash of rpId.
     // Otherwise, reject promise with a DOMException whose name is
     // "SecurityError", and terminate this algorithm.
 
-    if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRpId.Value(), rpId))) {
+    if (NS_FAILED(RelaxSameOrigin(mParent, aOptions.mRpId.Value(), rpId))) {
       promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
       return promise.forget();
     }
   }
 
   CryptoBuffer rpIdHash;
   if (!rpIdHash.SetLength(SHA256_LENGTH, fallible)) {
     promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
@@ -656,47 +620,44 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
   nsTArray<WebAuthnExtension> extensions;
 
   WebAuthnGetAssertionInfo info(rpIdHash,
                                 clientDataHash,
                                 adjustedTimeout,
                                 allowList,
                                 extensions);
 
-  ListenForVisibilityEvents(aParent, this);
+  ListenForVisibilityEvents();
 
   AbortSignal* signal = nullptr;
   if (aSignal.WasPassed()) {
     signal = &aSignal.Value();
     Follow(signal);
   }
 
   MOZ_ASSERT(mTransaction.isNothing());
-  mTransaction = Some(WebAuthnTransaction(aParent,
-                                          promise,
+  mTransaction = Some(WebAuthnTransaction(promise,
                                           rpIdHash,
                                           clientDataJSON,
                                           signal));
 
   mChild->SendRequestSign(mTransaction.ref().mId, info);
   return promise.forget();
 }
 
 already_AddRefed<Promise>
-WebAuthnManager::Store(nsPIDOMWindowInner* aParent,
-                       const Credential& aCredential)
+WebAuthnManager::Store(const Credential& aCredential)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aParent);
 
   if (mTransaction.isSome()) {
     CancelTransaction(NS_ERROR_ABORT);
   }
 
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(global, rv);
   if (rv.Failed()) {
     return nullptr;
   }
 
   promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
@@ -811,22 +772,22 @@ WebAuthnManager::FinishMakeCredential(co
     RejectTransaction(rv);
     return;
   }
 
   // Create a new PublicKeyCredential object and populate its fields with the
   // values returned from the authenticator as well as the clientDataJSON
   // computed earlier.
   RefPtr<AuthenticatorAttestationResponse> attestation =
-      new AuthenticatorAttestationResponse(mTransaction.ref().mParent);
+      new AuthenticatorAttestationResponse(mParent);
   attestation->SetClientDataJSON(clientDataBuf);
   attestation->SetAttestationObject(attObj);
 
   RefPtr<PublicKeyCredential> credential =
-      new PublicKeyCredential(mTransaction.ref().mParent);
+      new PublicKeyCredential(mParent);
   credential->SetId(keyHandleBase64Url);
   credential->SetType(NS_LITERAL_STRING("public-key"));
   credential->SetRawId(keyHandleBuf);
   credential->SetResponse(attestation);
 
   mTransaction.ref().mPromise->MaybeResolve(credential);
   ClearTransaction();
 }
@@ -896,23 +857,22 @@ WebAuthnManager::FinishGetAssertion(cons
   }
 
   // If any authenticator returns success:
 
   // Create a new PublicKeyCredential object named value and populate its fields
   // with the values returned from the authenticator as well as the
   // clientDataJSON computed earlier.
   RefPtr<AuthenticatorAssertionResponse> assertion =
-    new AuthenticatorAssertionResponse(mTransaction.ref().mParent);
+    new AuthenticatorAssertionResponse(mParent);
   assertion->SetClientDataJSON(clientDataBuf);
   assertion->SetAuthenticatorData(authenticatorDataBuf);
   assertion->SetSignature(signatureBuf);
 
-  RefPtr<PublicKeyCredential> credential =
-    new PublicKeyCredential(mTransaction.ref().mParent);
+  RefPtr<PublicKeyCredential> credential = new PublicKeyCredential(mParent);
   credential->SetId(credentialBase64Url);
   credential->SetType(NS_LITERAL_STRING("public-key"));
   credential->SetRawId(credentialBuf);
   credential->SetResponse(assertion);
 
   mTransaction.ref().mPromise->MaybeResolve(credential);
   ClearTransaction();
 }
--- a/dom/webauthn/WebAuthnManager.h
+++ b/dom/webauthn/WebAuthnManager.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_WebAuthnManager_h
 #define mozilla_dom_WebAuthnManager_h
 
 #include "mozilla/MozPromise.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/PWebAuthnTransaction.h"
+#include "mozilla/dom/WebAuthnManagerBase.h"
 #include "nsIDOMEventListener.h"
 
 /*
  * Content process manager for the WebAuthn protocol. Created on calls to the
  * WebAuthentication DOM object, this manager handles establishing IPC channels
  * for WebAuthn transactions, as well as keeping track of JS Promise objects
  * representing transactions in flight.
  *
@@ -58,34 +59,29 @@ struct AssertionOptions;
 class OwningArrayBufferViewOrArrayBuffer;
 struct MakePublicKeyCredentialOptions;
 class Promise;
 class WebAuthnTransactionChild;
 
 class WebAuthnTransaction
 {
 public:
-  WebAuthnTransaction(nsPIDOMWindowInner* aParent,
-                      const RefPtr<Promise>& aPromise,
+  WebAuthnTransaction(const RefPtr<Promise>& aPromise,
                       const nsTArray<uint8_t>& aRpIdHash,
                       const nsCString& aClientData,
                       AbortSignal* aSignal)
-    : mParent(aParent)
-    , mPromise(aPromise)
+    : mPromise(aPromise)
     , mRpIdHash(aRpIdHash)
     , mClientData(aClientData)
     , mSignal(aSignal)
     , mId(NextId())
   {
     MOZ_ASSERT(mId > 0);
   }
 
-  // Parent of the context we're running the transaction in.
-  nsCOMPtr<nsPIDOMWindowInner> mParent;
-
   // JS Promise representing the transaction status.
   RefPtr<Promise> mPromise;
 
   // The RP ID hash.
   nsTArray<uint8_t> mRpIdHash;
 
   // Client data used to assemble reply objects.
   nsCString mClientData;
@@ -101,69 +97,78 @@ private:
   // forever, it's sufficient to differentiate between temporally close
   // transactions, where messages can intersect. Can overflow.
   static uint64_t NextId() {
     static uint64_t id = 0;
     return ++id;
   }
 };
 
-class WebAuthnManager final : public nsIDOMEventListener
+class WebAuthnManager final : public WebAuthnManagerBase
+                            , public nsIDOMEventListener
                             , public AbortFollower
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 
-  static WebAuthnManager* GetOrCreate();
-  static WebAuthnManager* Get();
+  explicit WebAuthnManager(nsPIDOMWindowInner* aParent);
 
   already_AddRefed<Promise>
-  MakeCredential(nsPIDOMWindowInner* aParent,
-                 const MakePublicKeyCredentialOptions& aOptions,
+  MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
                  const Optional<OwningNonNull<AbortSignal>>& aSignal);
 
   already_AddRefed<Promise>
-  GetAssertion(nsPIDOMWindowInner* aParent,
-               const PublicKeyCredentialRequestOptions& aOptions,
+  GetAssertion(const PublicKeyCredentialRequestOptions& aOptions,
                const Optional<OwningNonNull<AbortSignal>>& aSignal);
 
   already_AddRefed<Promise>
-  Store(nsPIDOMWindowInner* aParent, const Credential& aCredential);
+  Store(const Credential& aCredential);
+
+  // WebAuthnManagerBase
 
   void
   FinishMakeCredential(const uint64_t& aTransactionId,
-                       nsTArray<uint8_t>& aRegBuffer);
+                       nsTArray<uint8_t>& aRegBuffer) override;
 
   void
   FinishGetAssertion(const uint64_t& aTransactionId,
                      nsTArray<uint8_t>& aCredentialId,
-                     nsTArray<uint8_t>& aSigBuffer);
+                     nsTArray<uint8_t>& aSigBuffer) override;
 
   void
-  RequestAborted(const uint64_t& aTransactionId, const nsresult& aError);
+  RequestAborted(const uint64_t& aTransactionId,
+                 const nsresult& aError) override;
+
+  void ActorDestroyed() override;
+
+  // AbortFollower
 
   void Abort() override;
 
-  void ActorDestroyed();
+private:
+  virtual ~WebAuthnManager();
 
-private:
-  WebAuthnManager();
-  virtual ~WebAuthnManager();
+  // Visibility event handling.
+  void ListenForVisibilityEvents();
+  void StopListeningForVisibilityEvents();
 
   // Clears all information we have about the current transaction.
   void ClearTransaction();
   // Rejects the current transaction and calls ClearTransaction().
   void RejectTransaction(const nsresult& aError);
   // Cancels the current transaction (by sending a Cancel message to the
   // parent) and rejects it by calling RejectTransaction().
   void CancelTransaction(const nsresult& aError);
 
   bool MaybeCreateBackgroundActor();
 
+  // The parent window.
+  nsCOMPtr<nsPIDOMWindowInner> mParent;
+
   // IPC Channel to the parent process.
   RefPtr<WebAuthnTransactionChild> mChild;
 
   // The current transaction, if any.
   Maybe<WebAuthnTransaction> mTransaction;
 };
 
 } // namespace dom
new file mode 100644
--- /dev/null
+++ b/dom/webauthn/WebAuthnManagerBase.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WebAuthnManagerBase_h
+#define mozilla_dom_WebAuthnManagerBase_h
+
+/*
+ * A base class used by WebAuthn and U2F implementations, providing shared
+ * functionality and requiring an interface used by the IPC child actors.
+ */
+
+namespace mozilla {
+namespace dom {
+
+class WebAuthnManagerBase
+{
+public:
+  virtual void
+  FinishMakeCredential(const uint64_t& aTransactionId,
+                       nsTArray<uint8_t>& aRegBuffer) = 0;
+
+  virtual void
+  FinishGetAssertion(const uint64_t& aTransactionId,
+                     nsTArray<uint8_t>& aCredentialId,
+                     nsTArray<uint8_t>& aSigBuffer) = 0;
+
+  virtual void
+  RequestAborted(const uint64_t& aTransactionId,
+                 const nsresult& aError) = 0;
+
+  virtual void ActorDestroyed() = 0;
+};
+
+}
+}
+
+#endif //mozilla_dom_WebAuthnManagerBase_h
--- a/dom/webauthn/WebAuthnTransactionChild.cpp
+++ b/dom/webauthn/WebAuthnTransactionChild.cpp
@@ -4,51 +4,81 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/WebAuthnTransactionChild.h"
 
 namespace mozilla {
 namespace dom {
 
+WebAuthnTransactionChild::WebAuthnTransactionChild(WebAuthnManagerBase* aManager)
+  : mManager(aManager)
+{
+  MOZ_ASSERT(aManager);
+
+  // Retain a reference so the task object isn't deleted without IPDL's
+  // knowledge. The reference will be released by
+  // mozilla::ipc::BackgroundChildImpl::DeallocPWebAuthnTransactionChild.
+  NS_ADDREF_THIS();
+}
+
 mozilla::ipc::IPCResult
 WebAuthnTransactionChild::RecvConfirmRegister(const uint64_t& aTransactionId,
                                               nsTArray<uint8_t>&& aRegBuffer)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
-  MOZ_ASSERT(mgr);
-  mgr->FinishMakeCredential(aTransactionId, aRegBuffer);
+  if (NS_WARN_IF(!mManager)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  mManager->FinishMakeCredential(aTransactionId, aRegBuffer);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebAuthnTransactionChild::RecvConfirmSign(const uint64_t& aTransactionId,
                                           nsTArray<uint8_t>&& aCredentialId,
                                           nsTArray<uint8_t>&& aBuffer)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
-  MOZ_ASSERT(mgr);
-  mgr->FinishGetAssertion(aTransactionId, aCredentialId, aBuffer);
+  if (NS_WARN_IF(!mManager)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  mManager->FinishGetAssertion(aTransactionId, aCredentialId, aBuffer);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebAuthnTransactionChild::RecvAbort(const uint64_t& aTransactionId,
                                     const nsresult& aError)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
-  MOZ_ASSERT(mgr);
-  mgr->RequestAborted(aTransactionId, aError);
+  if (NS_WARN_IF(!mManager)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  mManager->RequestAborted(aTransactionId, aError);
   return IPC_OK();
 }
 
 void
 WebAuthnTransactionChild::ActorDestroy(ActorDestroyReason why)
 {
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
-  // This could happen after the WebAuthnManager has been shut down.
-  if (mgr) {
-    mgr->ActorDestroyed();
+  // Called by either a __delete__ message from the parent, or when the
+  // channel disconnects. Clear out the child actor reference to be sure.
+  if (mManager) {
+    mManager->ActorDestroyed();
+    mManager = nullptr;
   }
 }
 
+void
+WebAuthnTransactionChild::Disconnect()
+{
+  mManager = nullptr;
+
+  // The WebAuthnManager released us, but we're going to be held alive by the
+  // IPC layer. The parent will explicitly destroy us via Send__delete__(),
+  // after receiving the DestroyMe message.
+
+  SendDestroyMe();
+}
+
 }
 }
--- a/dom/webauthn/WebAuthnTransactionChild.h
+++ b/dom/webauthn/WebAuthnTransactionChild.h
@@ -2,42 +2,54 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_WebAuthnTransactionChild_h
 #define mozilla_dom_WebAuthnTransactionChild_h
 
-#include "mozilla/dom/WebAuthnTransactionChildBase.h"
+#include "mozilla/dom/PWebAuthnTransactionChild.h"
+#include "mozilla/dom/WebAuthnManagerBase.h"
 
 /*
  * Child process IPC implementation for WebAuthn API. Receives results of
  * WebAuthn transactions from the parent process, and sends them to the
  * WebAuthnManager either cancel the transaction, or be formatted and relayed to
  * content.
  */
 
 namespace mozilla {
 namespace dom {
 
-class WebAuthnTransactionChild final : public WebAuthnTransactionChildBase
+class WebAuthnTransactionChild final : public PWebAuthnTransactionChild
 {
 public:
+  NS_INLINE_DECL_REFCOUNTING(WebAuthnTransactionChild);
+  explicit WebAuthnTransactionChild(WebAuthnManagerBase* aManager);
+
   mozilla::ipc::IPCResult
   RecvConfirmRegister(const uint64_t& aTransactionId,
-                      nsTArray<uint8_t>&& aRegBuffer) override;
+                      nsTArray<uint8_t>&& aRegBuffer);
 
   mozilla::ipc::IPCResult
   RecvConfirmSign(const uint64_t& aTransactionId,
                   nsTArray<uint8_t>&& aCredentialId,
-                  nsTArray<uint8_t>&& aBuffer) override;
+                  nsTArray<uint8_t>&& aBuffer);
 
   mozilla::ipc::IPCResult
-  RecvAbort(const uint64_t& aTransactionId, const nsresult& aError) override;
+  RecvAbort(const uint64_t& aTransactionId, const nsresult& aError);
+
+  void ActorDestroy(ActorDestroyReason why);
+
+  void Disconnect();
 
-  void ActorDestroy(ActorDestroyReason why) override;
+private:
+  ~WebAuthnTransactionChild() = default;
+
+  // Nulled by ~WebAuthnManager() when disconnecting.
+  WebAuthnManagerBase* mManager;
 };
 
 }
 }
 
 #endif //mozilla_dom_WebAuthnTransactionChild_h
deleted file mode 100644
--- a/dom/webauthn/WebAuthnTransactionChildBase.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/WebAuthnTransactionChildBase.h"
-
-namespace mozilla {
-namespace dom {
-
-WebAuthnTransactionChildBase::WebAuthnTransactionChildBase()
-{
-  // Retain a reference so the task object isn't deleted without IPDL's
-  // knowledge. The reference will be released by
-  // mozilla::ipc::BackgroundChildImpl::DeallocPWebAuthnTransactionChild.
-  NS_ADDREF_THIS();
-}
-
-}
-}
deleted file mode 100644
--- a/dom/webauthn/WebAuthnTransactionChildBase.h
+++ /dev/null
@@ -1,36 +0,0 @@
-
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_WebAuthnTransactionChildBase_h
-#define mozilla_dom_WebAuthnTransactionChildBase_h
-
-#include "mozilla/dom/PWebAuthnTransactionChild.h"
-
-/*
- * A base class to be used by child process IPC implementations for WebAuthn
- * and U2F. This mostly handles refcounting so we can properly dereference
- * in mozilla::ipc::BackgroundChildImpl::DeallocPWebAuthnTransactionChild(),
- * a function that doesn't know which of the two implementations is passed.
- */
-
-namespace mozilla {
-namespace dom {
-
-class WebAuthnTransactionChildBase : public PWebAuthnTransactionChild
-{
-public:
-  NS_INLINE_DECL_REFCOUNTING(WebAuthnTransactionChildBase);
-  WebAuthnTransactionChildBase();
-
-protected:
-  ~WebAuthnTransactionChildBase() = default;
-};
-
-}
-}
-
-#endif //mozilla_dom_WebAuthnTransactionChildBase_h
--- a/dom/webauthn/WebAuthnTransactionParent.cpp
+++ b/dom/webauthn/WebAuthnTransactionParent.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/WebAuthnTransactionParent.h"
 #include "mozilla/dom/U2FTokenManager.h"
+#include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 
 namespace mozilla {
 namespace dom {
 
 mozilla::ipc::IPCResult
 WebAuthnTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
                                                const WebAuthnMakeCredentialInfo& aTransactionInfo)
@@ -35,17 +36,45 @@ mozilla::ipc::IPCResult
 WebAuthnTransactionParent::RecvRequestCancel(const uint64_t& aTransactionId)
 {
   AssertIsOnBackgroundThread();
   U2FTokenManager* mgr = U2FTokenManager::Get();
   mgr->Cancel(this, aTransactionId);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+WebAuthnTransactionParent::RecvDestroyMe()
+{
+  AssertIsOnBackgroundThread();
+
+  // The child was disconnected from the WebAuthnManager instance and will send
+  // no further messages. It is kept alive until we delete it explicitly.
+
+  // The child should have cancelled any active transaction. This means
+  // we expect no more messages to the child. We'll crash otherwise.
+
+  // The IPC roundtrip is complete. No more messages, hopefully.
+  IProtocol* mgr = Manager();
+  if (!Send__delete__(this)) {
+    return IPC_FAIL_NO_REASON(mgr);
+  }
+
+  return IPC_OK();
+}
+
 void
 WebAuthnTransactionParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsOnBackgroundThread();
+
+  // Called either by Send__delete__() in RecvDestroyMe() above, or when
+  // the channel disconnects. Ensure the token manager forgets about us.
   U2FTokenManager* mgr = U2FTokenManager::Get();
-  mgr->MaybeClearTransaction(this);
+
+  // The manager could probably be null on shutdown?
+  if (mgr) {
+    mgr->MaybeClearTransaction(this);
+  }
+}
+
 }
 }
-}
--- a/dom/webauthn/WebAuthnTransactionParent.h
+++ b/dom/webauthn/WebAuthnTransactionParent.h
@@ -30,16 +30,19 @@ public:
 
   virtual mozilla::ipc::IPCResult
   RecvRequestSign(const uint64_t& aTransactionId,
                   const WebAuthnGetAssertionInfo& aTransactionInfo) override;
 
   virtual mozilla::ipc::IPCResult
   RecvRequestCancel(const uint64_t& aTransactionId) override;
 
+  virtual mozilla::ipc::IPCResult
+  RecvDestroyMe() override;
+
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   ~WebAuthnTransactionParent() = default;
 };
 
 }
 }
--- a/dom/webauthn/moz.build
+++ b/dom/webauthn/moz.build
@@ -17,18 +17,18 @@ EXPORTS.mozilla.dom += [
     'AuthenticatorResponse.h',
     'PublicKeyCredential.h',
     'U2FHIDTokenManager.h',
     'U2FSoftTokenManager.h',
     'U2FTokenManager.h',
     'U2FTokenTransport.h',
     'WebAuthnCBORUtil.h',
     'WebAuthnManager.h',
+    'WebAuthnManagerBase.h',
     'WebAuthnTransactionChild.h',
-    'WebAuthnTransactionChildBase.h',
     'WebAuthnTransactionParent.h',
     'WebAuthnUtil.h',
 ]
 
 UNIFIED_SOURCES += [
     'AuthenticatorAssertionResponse.cpp',
     'AuthenticatorAttestationResponse.cpp',
     'AuthenticatorResponse.cpp',
@@ -36,17 +36,16 @@ UNIFIED_SOURCES += [
     'cbor-cpp/src/output_dynamic.cpp',
     'PublicKeyCredential.cpp',
     'U2FHIDTokenManager.cpp',
     'U2FSoftTokenManager.cpp',
     'U2FTokenManager.cpp',
     'WebAuthnCBORUtil.cpp',
     'WebAuthnManager.cpp',
     'WebAuthnTransactionChild.cpp',
-    'WebAuthnTransactionChildBase.cpp',
     'WebAuthnTransactionParent.cpp',
     'WebAuthnUtil.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
--- a/dom/webidl/Attr.webidl
+++ b/dom/webidl/Attr.webidl
@@ -7,17 +7,17 @@
  * http://www.w3.org/TR/2012/WD-dom-20120105/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface Attr : Node {
   readonly attribute DOMString localName;
-           [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+           [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString value;
 
   [Constant]
   readonly attribute DOMString name;
   [Constant]
   readonly attribute DOMString? namespaceURI;
   [Constant]
   readonly attribute DOMString? prefix;
--- a/dom/webidl/CSSStyleDeclaration.webidl
+++ b/dom/webidl/CSSStyleDeclaration.webidl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/csswg/cssom/
  */
 
 interface CSSStyleDeclaration {
-  [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+  [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
   attribute DOMString cssText;
 
   readonly attribute unsigned long length;
   getter DOMString item(unsigned long index);
 
   [Throws]
   DOMString getPropertyValue(DOMString property);
   // Mozilla extension, sort of
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -216,17 +216,17 @@ partial interface Element {
   [ChromeOnly] readonly attribute long scrollTopMin;
                readonly attribute long scrollTopMax;
   [ChromeOnly] readonly attribute long scrollLeftMin;
                readonly attribute long scrollLeftMax;
 };
 
 // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
 partial interface Element {
-  [CEReactions, NeedsSubjectPrincipal, Pure,SetterThrows,TreatNullAs=EmptyString]
+  [CEReactions, SetterNeedsSubjectPrincipal, Pure, SetterThrows, TreatNullAs=EmptyString]
   attribute DOMString innerHTML;
   [CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString]
   attribute DOMString outerHTML;
   [CEReactions, Throws]
   void insertAdjacentHTML(DOMString position, DOMString text);
 };
 
 // http://www.w3.org/TR/selectors-api/#interface-definitions
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -37,17 +37,17 @@ interface HTMLDocument : Document {
   WindowProxy? open(DOMString url, DOMString name, DOMString features, optional boolean replace = false);
   [CEReactions, Throws]
   void close();
   [CEReactions, Throws]
   void write(DOMString... text);
   [CEReactions, Throws]
   void writeln(DOMString... text);
 
-  [CEReactions, SetterThrows, NeedsSubjectPrincipal]
+  [CEReactions, SetterThrows, SetterNeedsSubjectPrincipal]
            attribute DOMString designMode;
   [CEReactions, Throws, NeedsSubjectPrincipal]
   boolean execCommand(DOMString commandId, optional boolean showUI = false,
                       optional DOMString value = "");
   [Throws, NeedsSubjectPrincipal]
   boolean queryCommandEnabled(DOMString commandId);
   [Throws]
   boolean queryCommandIndeterm(DOMString commandId);
--- a/dom/webidl/HTMLFrameElement.webidl
+++ b/dom/webidl/HTMLFrameElement.webidl
@@ -12,17 +12,17 @@
 
 // http://www.whatwg.org/specs/web-apps/current-work/#htmlframeelement
 [HTMLConstructor]
 interface HTMLFrameElement : HTMLElement {
            [CEReactions, SetterThrows]
            attribute DOMString name;
            [CEReactions, SetterThrows]
            attribute DOMString scrolling;
-           [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+           [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString src;
            [CEReactions, SetterThrows]
            attribute DOMString frameBorder;
            [CEReactions, SetterThrows]
            attribute DOMString longDesc;
            [CEReactions, SetterThrows]
            attribute boolean noResize;
   [NeedsSubjectPrincipal]
--- a/dom/webidl/HTMLIFrameElement.webidl
+++ b/dom/webidl/HTMLIFrameElement.webidl
@@ -8,17 +8,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 [HTMLConstructor]
 interface HTMLIFrameElement : HTMLElement {
-  [CEReactions, NeedsSubjectPrincipal, SetterThrows, Pure]
+  [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows, Pure]
            attribute DOMString src;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString srcdoc;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString name;
   [PutForwards=value] readonly attribute DOMTokenList sandbox;
            // attribute boolean seamless;
   [CEReactions, SetterThrows, Pure]
--- a/dom/webidl/HTMLImageElement.webidl
+++ b/dom/webidl/HTMLImageElement.webidl
@@ -16,19 +16,19 @@ interface imgIRequest;
 interface URI;
 interface nsIStreamListener;
 
 [HTMLConstructor,
  NamedConstructor=Image(optional unsigned long width, optional unsigned long height)]
 interface HTMLImageElement : HTMLElement {
            [CEReactions, SetterThrows]
            attribute DOMString alt;
-           [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+           [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString src;
-           [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+           [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString srcset;
            [CEReactions, SetterThrows]
            attribute DOMString? crossOrigin;
            [CEReactions, SetterThrows]
            attribute DOMString useMap;
            [CEReactions, SetterThrows]
            attribute DOMString referrerPolicy;
            [CEReactions, SetterThrows]
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -76,17 +76,17 @@ interface HTMLInputElement : HTMLElement
   [CEReactions, Pure, SetterThrows]
            attribute DOMString placeholder;
   [CEReactions, Pure, SetterThrows]
            attribute boolean readOnly;
   [CEReactions, Pure, SetterThrows]
            attribute boolean required;
   [CEReactions, Pure, SetterThrows]
            attribute unsigned long size;
-  [CEReactions, Pure, NeedsSubjectPrincipal, SetterThrows]
+  [CEReactions, Pure, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString src;
   [CEReactions, Pure, SetterThrows]
            attribute DOMString step;
   [CEReactions, Pure, SetterThrows]
            attribute DOMString type;
   [CEReactions, Pure, SetterThrows]
            attribute DOMString defaultValue;
   [CEReactions, Pure, TreatNullAs=EmptyString, SetterThrows, NeedsCallerType]
--- a/dom/webidl/HTMLLinkElement.webidl
+++ b/dom/webidl/HTMLLinkElement.webidl
@@ -11,17 +11,17 @@
  * and create derivative works of this document.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-link-element
 [HTMLConstructor]
 interface HTMLLinkElement : HTMLElement {
   [Pure]
            attribute boolean disabled;
-  [CEReactions, NeedsSubjectPrincipal, SetterThrows, Pure]
+  [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows, Pure]
            attribute DOMString href;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString? crossOrigin;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString rel;
   [PutForwards=value]
   readonly attribute DOMTokenList relList;
   [CEReactions, SetterThrows, Pure]
--- a/dom/webidl/HTMLMediaElement.webidl
+++ b/dom/webidl/HTMLMediaElement.webidl
@@ -12,17 +12,17 @@
  */
 
 interface HTMLMediaElement : HTMLElement {
 
   // error state
   readonly attribute MediaError? error;
 
   // network state
-  [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+  [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString src;
   readonly attribute DOMString currentSrc;
 
   [CEReactions, SetterThrows]
            attribute DOMString? crossOrigin;
   const unsigned short NETWORK_EMPTY = 0;
   const unsigned short NETWORK_IDLE = 1;
   const unsigned short NETWORK_LOADING = 2;
--- a/dom/webidl/HTMLSourceElement.webidl
+++ b/dom/webidl/HTMLSourceElement.webidl
@@ -8,22 +8,22 @@
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 [HTMLConstructor]
 interface HTMLSourceElement : HTMLElement {
-           [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+           [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString src;
            [CEReactions, SetterThrows]
            attribute DOMString type;
 };
 
 partial interface HTMLSourceElement {
-           [CEReactions, NeedsSubjectPrincipal, SetterThrows]
+           [CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
            attribute DOMString srcset;
            [CEReactions, SetterThrows]
            attribute DOMString sizes;
            [CEReactions, SetterThrows]
            attribute DOMString media;
 };
--- a/dom/webidl/Location.webidl
+++ b/dom/webidl/Location.webidl
@@ -15,17 +15,17 @@
 interface Location {
   // Bug 824857: no support for stringifier attributes yet.
   //  stringifier attribute USVString href;
 
   // Bug 824857 should remove this.
   [Throws, NeedsSubjectPrincipal]
   stringifier;
 
-  [Throws, CrossOriginWritable, NeedsSubjectPrincipal]
+  [Throws, CrossOriginWritable, GetterNeedsSubjectPrincipal]
            attribute USVString href;
   [Throws, NeedsSubjectPrincipal]
   readonly attribute USVString origin;
   [Throws, NeedsSubjectPrincipal]
            attribute USVString protocol;
   [Throws, NeedsSubjectPrincipal]
            attribute USVString host;
   [Throws, NeedsSubjectPrincipal]
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -193,22 +193,16 @@ partial interface Navigator {
   [Throws, ChromeOnly]
   void addIdleObserver(MozIdleObserver aIdleObserver);
 
   /**
    * Navigator requests to remove an idle observer from the existing window.
    */
   [Throws, ChromeOnly]
   void removeIdleObserver(MozIdleObserver aIdleObserver);
-
-  /**
-   * Make CPU instruction subset information available for UpdateUtils.
-   */
-  [ChromeOnly]
-  readonly attribute boolean cpuHasSSE2;
 };
 
 // nsIDOMNavigatorDesktopNotification
 partial interface Navigator {
   [Throws, Pref="notification.feature.enabled", UnsafeInPrerendering]
   readonly attribute DesktopNotificationCenter mozNotification;
 };
 
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -54,17 +54,17 @@ interface Node : EventTarget {
   readonly attribute Node? lastChild;
   [Pure]
   readonly attribute Node? previousSibling;
   [Pure]
   readonly attribute Node? nextSibling;
 
   [CEReactions, SetterThrows, Pure]
            attribute DOMString? nodeValue;
-  [CEReactions, SetterThrows, GetterCanOOM, NeedsSubjectPrincipal, Pure]
+  [CEReactions, SetterThrows, GetterCanOOM, SetterNeedsSubjectPrincipal, Pure]
            attribute DOMString? textContent;
   [CEReactions, Throws]
   Node insertBefore(Node node, Node? child);
   [CEReactions, Throws]
   Node appendChild(Node node);
   [CEReactions, Throws]
   Node replaceChild(Node node, Node child);
   [CEReactions, Throws]
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -565,16 +565,17 @@ class ScriptLoaderRunnable final : publi
   friend class CachePromiseHandler;
   friend class CacheScriptLoader;
   friend class LoaderListener;
 
   WorkerPrivate* mWorkerPrivate;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
   nsTArray<ScriptLoadInfo> mLoadInfos;
   RefPtr<CacheCreator> mCacheCreator;
+  Maybe<ServiceWorkerDescriptor> mController;
   bool mIsMainScript;
   WorkerScriptType mWorkerScriptType;
   bool mCanceled;
   bool mCanceledMainThread;
   ErrorResult& mRv;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
@@ -1211,16 +1212,20 @@ private:
 
       mWorkerPrivate->SetReferrerPolicyFromHeaderValue(tRPHeaderCValue);
 
       WorkerPrivate* parent = mWorkerPrivate->GetParent();
       if (parent) {
         // XHR Params Allowed
         mWorkerPrivate->SetXHRParamsAllowed(parent->XHRParamsAllowed());
       }
+
+      if (chanLoadInfo) {
+        mController = chanLoadInfo->GetController();
+      }
     }
 
     return NS_OK;
   }
 
   void
   DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString,
                         uint32_t aStringLen,
@@ -1977,18 +1982,21 @@ ScriptExecutorRunnable::WorkerRun(JSCont
       // Top level scripts only!
       if (mIsWorkerScript) {
         aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
       }
       return true;
     }
 
     // If this is a top level script that succeeded, then mark the
-    // Client execution ready.
+    // Client execution ready and possible controlled by a service worker.
     if (mIsWorkerScript) {
+      if (mScriptLoader.mController.isSome()) {
+        aWorkerPrivate->Control(mScriptLoader.mController.ref());
+      }
       aWorkerPrivate->ExecutionReady();
     }
 
     NS_ConvertUTF16toUTF8 filename(loadInfo.mURL);
 
     JS::CompileOptions options(aCx);
     options.setFileAndLine(filename.get(), 1)
            .setNoScriptRval(true);
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -332,22 +332,44 @@ public:
     mInternalResponse->UnfilteredHeaders()->GetEntries(entries);
     for (uint32_t i = 0; i < entries.Length(); ++i) {
        mChannel->SynthesizeHeader(entries[i].mName, entries[i].mValue);
     }
 
     auto castLoadInfo = static_cast<LoadInfo*>(loadInfo.get());
     castLoadInfo->SynthesizeServiceWorkerTainting(mInternalResponse->GetTainting());
 
-    nsCOMPtr<nsIInputStream> body;
-    mInternalResponse->GetUnfilteredBody(getter_AddRefs(body));
+    // Get the preferred alternative data type of outter channel
+    nsAutoCString preferredAltDataType(EmptyCString());
+    nsCOMPtr<nsICacheInfoChannel> outerChannel = do_QueryInterface(underlyingChannel);
+    if (outerChannel) {
+      outerChannel->GetPreferredAlternativeDataType(preferredAltDataType);
+    }
+
+    // Get the alternative data type saved in the InternalResponse
+    nsAutoCString altDataType;
+    nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel =
+      mInternalResponse->TakeCacheInfoChannel().get();
+    if (cacheInfoChannel) {
+      cacheInfoChannel->GetAlternativeDataType(altDataType);
+    }
+
+     nsCOMPtr<nsIInputStream> body;
+    if (preferredAltDataType.Equals(altDataType)) {
+      body = mInternalResponse->TakeAlternativeBody();
+    }
+    if (!body) {
+      mInternalResponse->GetUnfilteredBody(getter_AddRefs(body));
+    }
+
     RefPtr<BodyCopyHandle> copyHandle;
     copyHandle = new BodyCopyHandle(Move(mClosure));
 
-    rv = mChannel->StartSynthesizedResponse(body, copyHandle, mResponseURLSpec,
+    rv = mChannel->StartSynthesizedResponse(body, copyHandle, cacheInfoChannel,
+                                            mResponseURLSpec,
                                             mInternalResponse->IsRedirected());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED);
       return NS_OK;
     }
 
     nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
     if (obsService) {
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -32,16 +32,18 @@
 
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ClientHandle.h"
+#include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
@@ -2319,35 +2321,57 @@ ServiceWorkerManager::MaybeCheckNavigati
   //    algorithm.
   RefPtr<ServiceWorkerRegistrationInfo> registration;
   mControlledDocuments.Get(aDoc, getter_AddRefs(registration));
   if (registration) {
     registration->MaybeScheduleUpdate();
   }
 }
 
-void
+RefPtr<GenericPromise>
 ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
                                                 nsIDocument* aDoc,
                                                 const nsAString& aDocumentId)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aDoc);
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
   MOZ_DIAGNOSTIC_ASSERT(storageAllowed == nsContentUtils::StorageAccess::eAllow);
 #endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
 
+  RefPtr<GenericPromise> ref = GenericPromise::CreateAndResolve(true, __func__);
+
   aRegistration->StartControllingADocument();
   mControlledDocuments.Put(aDoc, aRegistration);
   if (!aDocumentId.IsEmpty()) {
     aDoc->SetId(aDocumentId);
   }
+
+  // Mark the document's ClientSource as controlled using the ClientHandle
+  // interface.  While we could get at the ClientSource directly from the
+  // document here, our goal is to move ServiceWorkerManager to a separate
+  // process.  Using the ClientHandle supports this remote operation.
+  ServiceWorkerInfo* activeWorker = aRegistration->GetActive();
+  nsPIDOMWindowInner* innerWindow = aDoc->GetInnerWindow();
+  if (activeWorker && innerWindow) {
+    Maybe<ClientInfo> clientInfo = innerWindow->GetClientInfo();
+    if (clientInfo.isSome()) {
+      RefPtr<ClientHandle> clientHandle =
+        ClientManager::CreateHandle(clientInfo.ref(),
+                                    SystemGroup::EventTargetFor(TaskCategory::Other));
+      if (clientHandle) {
+        ref = Move(clientHandle->Control(activeWorker->Descriptor()));
+      }
+    }
+  }
+
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
+  return Move(ref);
 }
 
 void
 ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration)
 {
   aRegistration->StopControllingADocument();
   if (aRegistration->IsControllingDocuments() || !aRegistration->IsIdle()) {
     return;
@@ -2648,16 +2672,58 @@ ServiceWorkerManager::DispatchFetchEvent
     // before we get to this point.  Therefore we must handle a nullptr
     // active worker here.
     serviceWorker = registration->GetActive();
     if (!serviceWorker) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
+    // If there is a reserved client it should be marked as controlled before
+    // the FetchEvent is dispatched.
+    nsCOMPtr<nsILoadInfo> loadInfo = internalChannel->GetLoadInfo();
+    if (loadInfo) {
+      Maybe<ClientInfo> clientInfo = loadInfo->GetReservedClientInfo();
+
+      // Also override the initial about:blank controller since the real
+      // network load may be intercepted by a different service worker.  If
+      // the intial about:blank has a controller here its simply been
+      // inherited from its parent.
+      if (clientInfo.isNothing()) {
+        clientInfo = loadInfo->GetInitialClientInfo();
+
+        // TODO: We need to handle the case where the initial about:blank is
+        //       controlled, but the final document load is not.  Right now
+        //       the spec does not really say what to do.  There currently
+        //       is no way for the controller to be cleared from a client in
+        //       the spec or our implementation.  We may want to force a
+        //       new inner window to be created instead of reusing the
+        //       initial about:blank global.  See bug 1419620 and the spec
+        //       issue here: https://github.com/w3c/ServiceWorker/issues/1232
+      }
+
+      if (clientInfo.isSome()) {
+        // First, attempt to mark the reserved client controlled directly.  This
+        // will update the controlled status in the ClientManagerService in the
+        // parent.  It will also eventually propagate back to the ClientSource.
+        RefPtr<ClientHandle> clientHandle =
+          ClientManager::CreateHandle(clientInfo.ref(),
+                                      SystemGroup::EventTargetFor(TaskCategory::Other));
+        if (clientHandle) {
+          clientHandle->Control(serviceWorker->Descriptor());
+        }
+      }
+
+      // But we also note the reserved state on the LoadInfo.  This allows the
+      // ClientSource to be updated immediately after the nsIChannel starts.
+      // This is necessary to have the correct controller in place for immediate
+      // follow-on requests.
+      loadInfo->SetController(serviceWorker->Descriptor());
+    }
+
     AddNavigationInterception(serviceWorker->Scope(), aChannel);
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(serviceWorker);
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -10,16 +10,17 @@
 #include "nsIServiceWorkerManager.h"
 #include "nsCOMPtr.h"
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ConsoleReportCollector.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/MozPromise.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerCommon.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
@@ -385,17 +386,17 @@ private:
                                             WhichServiceWorker aWhichOne);
   void
   InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
                                             WhichServiceWorker aWhichOnes);
 
   void
   NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration);
 
-  void
+  RefPtr<GenericPromise>
   StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
                             nsIDocument* aDoc,
                             const nsAString& aDocumentId);
 
   void
   StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration);
 
   already_AddRefed<ServiceWorkerRegistrationInfo>
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ServiceWorkerPrivate.h"
 
 #include "ServiceWorkerManager.h"
 #include "ServiceWorkerWindowClient.h"
 #include "nsContentUtils.h"
+#include "nsICacheInfoChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsINamed.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPushErrorReporter.h"
 #include "nsISupportsImpl.h"
 #include "nsITimedChannel.h"
 #include "nsIUploadChannel2.h"
@@ -1603,16 +1604,28 @@ private:
                                                               NS_ConvertUTF8toUTF16(mReferrer),
                                                               mReferrerPolicy,
                                                               mContentPolicyType,
                                                               mIntegrity);
     internalReq->SetBody(mUploadStream, -1);
     // For Telemetry, note that this Request object was created by a Fetch event.
     internalReq->SetCreatedByFetchEvent();
 
+    nsCOMPtr<nsIChannel> channel;
+    nsresult rv = mInterceptedChannel->GetChannel(getter_AddRefs(channel));
+    NS_ENSURE_SUCCESS(rv, false);
+
+    nsAutoCString alternativeDataType;
+    nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(channel);
+    if (cic &&
+        NS_SUCCEEDED(cic->GetPreferredAlternativeDataType(alternativeDataType)) &&
+        !alternativeDataType.IsEmpty()) {
+      internalReq->SetPreferredAlternativeDataType(alternativeDataType);
+    }
+
     nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(globalObj.GetAsSupports());
     if (NS_WARN_IF(!global)) {
       return false;
     }
 
     // TODO This request object should be created with a AbortSignal object
     // which should be aborted if the loading is aborted. See bug 1394102.
     RefPtr<Request> request = new Request(global, internalReq, nullptr);
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5328,28 +5328,61 @@ WorkerPrivate::EnsureClientSource()
   if (!mClientSource) {
     return false;
   }
 
   if (mFrozen) {
     mClientSource->Freeze();
   }
 
+  // Shortly after the client is reserved we will try loading the main script
+  // for the worker.  This may get intercepted by the ServiceWorkerManager
+  // which will then try to create a ClientHandle.  Its actually possible for
+  // the main thread to create this ClientHandle before our IPC message creating
+  // the ClientSource completes.  To avoid this race we synchronously ping our
+  // parent Client actor here.  This ensure the worker ClientSource is created
+  // in the parent before the main thread might try reaching it with a
+  // ClientHandle.
+  //
+  // An alternative solution would have been to handle the out-of-order operations
+  // on the parent side.  We could have created a small window where we allow
+  // ClientHandle objects to exist without a ClientSource.  We would then time
+  // out these handles if they stayed orphaned for too long.  This approach would
+  // be much more complex, but also avoid this extra bit of latency when starting
+  // workers.
+  //
+  // Note, we only have to do this for workers that can be controlled by a
+  // service worker.  So avoid the sync overhead here if we are starting a
+  // service worker or a chrome worker.
+  if (Type() != WorkerTypeService && !IsChromeWorker()) {
+    mClientSource->WorkerSyncPing(this);
+  }
+
   return true;
 }
 
 const ClientInfo&
 WorkerPrivate::GetClientInfo() const
 {
   AssertIsOnWorkerThread();
   MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   return mClientSource->Info();
 }
 
 void
+WorkerPrivate::Control(const ServiceWorkerDescriptor& aServiceWorker)
+{
+  AssertIsOnWorkerThread();
+  MOZ_DIAGNOSTIC_ASSERT(mClientSource);
+  MOZ_DIAGNOSTIC_ASSERT(!IsChromeWorker());
+  MOZ_DIAGNOSTIC_ASSERT(Type() != WorkerTypeService);
+  mClientSource->SetController(aServiceWorker);
+}
+
+void
 WorkerPrivate::ExecutionReady()
 {
   AssertIsOnWorkerThread();
   MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   mClientSource->WorkerExecutionReady(this);
 }
 
 void
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1499,16 +1499,19 @@ public:
 
   bool
   EnsureClientSource();
 
   const ClientInfo&
   GetClientInfo() const;
 
   void
+  Control(const ServiceWorkerDescriptor& aServiceWorker);
+
+  void
   ExecutionReady();
 
 private:
   WorkerPrivate(WorkerPrivate* aParent,
                 const nsAString& aScriptURL, bool aIsChromeWorker,
                 WorkerType aWorkerType, const nsAString& aWorkerName,
                 const nsACString& aServiceWorkerScope,
                 WorkerLoadInfo& aLoadInfo);
--- a/dom/workers/test/serviceworkers/fetch.js
+++ b/dom/workers/test/serviceworkers/fetch.js
@@ -12,16 +12,18 @@ function get_query_params(url) {
   return ret;
 }
 
 addEventListener('fetch', function(event) {
   if (event.request.url.includes('fail.html')) {
     event.respondWith(fetch('hello.html', { integrity: 'abc' }));
   } else if (event.request.url.includes('fake.html')) {
     event.respondWith(fetch('hello.html'));
+  } else if (event.request.url.includes("file_js_cache")) {
+    event.respondWith(fetch(event.request));
   } else if (event.request.url.includes('redirect')) {
     let param = get_query_params(event.request.url);
     let url = param['url'];
     let mode = param['mode'];
 
     event.respondWith(fetch(url, { mode: mode }));
   }
 });
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Add a tag script to save the bytecode</title>
+</head>
+<body>
+  <script id="watchme" src="file_js_cache.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache.js
@@ -0,0 +1,5 @@
+function baz() {}
+function bar() {}
+function foo() { bar() }
+foo();
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache_cleanup.js
@@ -0,0 +1,14 @@
+"use strict";
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function clearCache() {
+  const cacheStorageSrv = Cc["@mozilla.org/netwerk/cache-storage-service;1"].
+                          getService(Ci.nsICacheStorageService);
+  cacheStorageSrv.clear();
+}
+
+addMessageListener("teardown", function() {
+  clearCache();
+  sendAsyncMessage("teardown-complete");
+});
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache_save_after_load.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Save the bytecode when all scripts are executed</title>
+</head>
+<body>
+  <script id="watchme" src="file_js_cache_save_after_load.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache_save_after_load.js
@@ -0,0 +1,15 @@
+function send_ping() {
+  window.dispatchEvent(new Event("ping"));
+}
+send_ping(); // ping (=1)
+
+window.addEventListener("load", function () {
+  send_ping(); // ping (=2)
+
+  // Append a script which should call |foo|, before the encoding of this script
+  // bytecode.
+  var script = document.createElement("script");
+  script.type = "text/javascript";
+  script.innerText = "send_ping();"; // ping (=3)
+  document.head.appendChild(script);
+});
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache_syntax_error.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Do not save bytecode on compilation errors</title>
+</head>
+<body>
+  <script id="watchme" src="file_js_cache_syntax_error.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache_syntax_error.js
@@ -0,0 +1,1 @@
+var // SyntaxError: missing variable name.
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/file_js_cache_with_sri.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Add a tag script to save the bytecode</title>
+</head>
+<body>
+  <script id="watchme" src="file_js_cache.js"
+          integrity="sha384-8YSwN2ywq1SVThihWhj7uTVZ4UeIDwo3GgdPYnug+C+OS0oa6kH2IXBclwMaDJFb">
+  </script>
+</body>
+</html>
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -198,16 +198,24 @@ support-files =
   xslt/*
   unresolved_fetch_worker.js
   header_checker.sjs
   openWindow_worker.js
   redirect.sjs
   open_window/client.html
   lorem_script.js
   file_blob_response_worker.js
+  file_js_cache_cleanup.js
+  file_js_cache.html
+  file_js_cache_with_sri.html
+  file_js_cache.js
+  file_js_cache_save_after_load.html
+  file_js_cache_save_after_load.js
+  file_js_cache_syntax_error.html
+  file_js_cache_syntax_error.js
   !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
   !/dom/tests/mochitest/notification/MockServices.js
   !/dom/tests/mochitest/notification/NotificationTest.js
   blocking_install_event_worker.js
   sw_bad_mime_type.js
   sw_bad_mime_type.js^headers^
   error_reporting_helpers.js
   fetch.js
@@ -309,16 +317,17 @@ tags = openwindow
 [test_request_context_style.html]
 [test_request_context_track.html]
 [test_request_context_video.html]
 [test_request_context_worker.html]
 [test_request_context_xhr.html]
 [test_request_context_xslt.html]
 [test_sandbox_intercept.html]
 [test_scopes.html]
+[test_script_loader_intercepted_js_cache.html]
 [test_sanitize.html]
 [test_sanitize_domain.html]
 [test_serviceworker.html]
 [test_service_worker_allowed.html]
 [test_serviceworker_header.html]
 [test_serviceworker_interfaces.html]
 [test_serviceworker_not_sharedworker.html]
 [test_skip_waiting.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_script_loader_intercepted_js_cache.html
@@ -0,0 +1,224 @@
+<!DOCTYPE html>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1350359 -->
+<!-- The JS bytecode cache is not supposed to be observable. To make it
+     observable, the ScriptLoader is instrumented to trigger events on the
+     script tag. These events are followed to reconstruct the code path taken by
+     the script loader and associate a simple name which is checked in these
+     test cases.
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for saving and loading bytecode in/from the necko cache</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="utils.js"></script>
+  <script type="application/javascript">
+
+    // This is the state machine of the trace events produced by the
+    // ScriptLoader. This state machine is used to give a name to each
+    // code path, such that we can assert each code path with a single word.
+    var scriptLoaderStateMachine = {
+      "scriptloader_load_source": {
+        "scriptloader_execute": {
+          "scriptloader_encode": {
+            "scriptloader_bytecode_saved": "bytecode_saved",
+            "scriptloader_bytecode_failed": "bytecode_failed"
+          },
+          "scriptloader_no_encode": "source_exec"
+        }
+      },
+      "scriptloader_load_bytecode": {
+        "scriptloader_fallback": {
+          // Replicate the top-level state machine without
+          // "scriptloader_load_bytecode" transition.
+          "scriptloader_load_source": {
+            "scriptloader_execute": {
+              "scriptloader_encode": {
+                "scriptloader_bytecode_saved": "fallback_bytecode_saved",
+                "scriptloader_bytecode_failed": "fallback_bytecode_failed"
+              },
+              "scriptloader_no_encode": "fallback_source_exec"
+            }
+          }
+        },
+        "scriptloader_execute": "bytecode_exec"
+      }
+    };
+
+    var gScript = SpecialPowers.
+      loadChromeScript('http://mochi.test:8888/tests/dom/workers/test/serviceworkers/file_js_cache_cleanup.js');
+
+    function WaitForScriptTagEvent(url) {
+      var iframe = document.createElement("iframe");
+      document.body.appendChild(iframe);
+
+      var stateMachine = scriptLoaderStateMachine;
+      var stateHistory = [];
+      var stateMachineResolve, stateMachineReject;
+      var statePromise = new Promise((resolve, reject) => {
+        stateMachineResolve = resolve;
+        stateMachineReject = reject;
+      });
+      var ping = 0;
+
+      // Walk the script loader state machine with the emitted events.
+      function log_event(evt) {
+        // If we have multiple script tags in the loaded source, make sure
+        // we only watch a single one.
+        if (evt.target.id != "watchme")
+          return;
+
+        dump("## ScriptLoader event: " + evt.type + "\n");
+        stateHistory.push(evt.type)
+        if (typeof stateMachine == "object")
+          stateMachine = stateMachine[evt.type];
+        if (typeof stateMachine == "string") {
+          // We arrived to a final state, report the name of it.
+          var result = stateMachine;
+          if (ping) {
+            result = `${result} & ping(=${ping})`;
+          }
+          stateMachineResolve(result);
+        } else if (stateMachine === undefined) {
+          // We followed an unknown transition, report the known history.
+          stateMachineReject(stateHistory);
+        }
+      }
+
+        var iwin = iframe.contentWindow;
+      iwin.addEventListener("scriptloader_load_source", log_event);
+      iwin.addEventListener("scriptloader_load_bytecode", log_event);
+      iwin.addEventListener("scriptloader_generate_bytecode", log_event);
+      iwin.addEventListener("scriptloader_execute", log_event);
+      iwin.addEventListener("scriptloader_encode", log_event);
+      iwin.addEventListener("scriptloader_no_encode", log_event);
+      iwin.addEventListener("scriptloader_bytecode_saved", log_event);
+      iwin.addEventListener("scriptloader_bytecode_failed", log_event);
+      iwin.addEventListener("scriptloader_fallback", log_event);
+      iwin.addEventListener("ping", (evt) => {
+        ping += 1;
+        dump(`## Content event: ${evt.type} (=${ping})\n`);
+      });
+      iframe.src = url;
+
+      statePromise.then(() => {
+        document.body.removeChild(iframe);
+      });
+      return statePromise;
+    }
+
+    promise_test(async function() {
+      // Setting dom.expose_test_interfaces pref causes the
+      // nsScriptLoadRequest to fire event on script tags, with information
+      // about its internal state. The ScriptLoader source send events to
+      // trace these and resolve a promise with the path taken by the
+      // script loader.
+      //
+      // Setting dom.script_loader.bytecode_cache.strategy to -1 causes the
+      // nsScriptLoadRequest to force all the conditions necessary to make a
+      // script be saved as bytecode in the alternate data storage provided
+      // by the channel (necko cache).
+      await SpecialPowers.pushPrefEnv({set: [
+        ["dom.serviceWorkers.enabled", true],
+        ["dom.serviceWorkers.testing.enabled", true],
+        ['dom.script_loader.bytecode_cache.enabled', true],
+        ['dom.expose_test_interfaces', true],
+        ['dom.script_loader.bytecode_cache.strategy', -1]
+      ]});
+
+      // Register the service worker that perform the pass-through fetch.
+      var registration = await navigator.serviceWorker
+                                        .register("fetch.js", {scope: "./"});
+      let sw = registration.installing || registration.active;
+
+      // wait for service worker be activated
+      await waitForState(sw, 'activated');
+
+      await testCheckTheJSBytecodeCache();
+      await testSavebytecodeAfterTheInitializationOfThePage();
+      await testDoNotSaveBytecodeOnCompilationErrors();
+
+      await registration.unregister();
+      await teardown();
+    });
+
+    function teardown() {
+      return new Promise((resolve, reject) => {
+        gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
+          gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
+          gScript.destroy();
+          resolve();
+        });
+        gScript.sendAsyncMessage("teardown");
+      });
+    }
+
+    async function testCheckTheJSBytecodeCache() {
+      dump("## Test: Check the JS bytecode cache\n");
+
+      // Load the test page, and verify that the code path taken by the
+      // nsScriptLoadRequest corresponds to the code path which is loading a
+      // source and saving it as bytecode.
+      var stateMachineResult = WaitForScriptTagEvent("file_js_cache.html");
+      assert_equals(await stateMachineResult, "bytecode_saved",
+                    "[1] ScriptLoadRequest status after the first visit");
+
+      // Reload the same test page, and verify that the code path taken by
+      // the nsScriptLoadRequest corresponds to the code path which is
+      // loading bytecode and executing it.
+      stateMachineResult = WaitForScriptTagEvent("file_js_cache.html");
+      assert_equals(await stateMachineResult, "bytecode_exec",
+                    "[2] ScriptLoadRequest status after the second visit");
+
+      // Load another page which loads the same script with an SRI, while
+      // the cached bytecode does not have any. This should fallback to
+      // loading the source before saving the bytecode once more.
+      stateMachineResult = WaitForScriptTagEvent("file_js_cache_with_sri.html");
+      assert_equals(await stateMachineResult, "fallback_bytecode_saved",
+                    "[3] ScriptLoadRequest status after the SRI hash");
+
+      // Loading a page, which has the same SRI should verify the SRI and
+      // continue by executing the bytecode.
+      var stateMachineResult1 = WaitForScriptTagEvent("file_js_cache_with_sri.html");
+
+      // Loading a page which does not have a SRI while we have one in the
+      // cache should not change anything. We should also be able to load
+      // the cache simultanesouly.
+      var stateMachineResult2 = WaitForScriptTagEvent("file_js_cache.html");
+
+      assert_equals(await stateMachineResult1, "bytecode_exec",
+                    "[4] ScriptLoadRequest status after same SRI hash");
+      assert_equals(await stateMachineResult2, "bytecode_exec",
+                    "[5] ScriptLoadRequest status after visit with no SRI");
+    }
+
+    async function testSavebytecodeAfterTheInitializationOfThePage() {
+      dump("## Test: Save bytecode after the initialization of the page");
+
+      // The test page add a new script which generate a "ping" event, which
+      // should be recorded before the bytecode is stored in the cache.
+      var stateMachineResult =
+          WaitForScriptTagEvent("file_js_cache_save_after_load.html");
+      assert_equals(await stateMachineResult, "bytecode_saved & ping(=3)",
+                    "Wait on all scripts to be executed");
+    }
+
+    async function testDoNotSaveBytecodeOnCompilationErrors() {
+      dump("## Test: Do not save bytecode on compilation errors");
+
+      // The test page loads a script which contains a syntax error, we should
+      // not attempt to encode any bytecode for it.
+      var stateMachineResult =
+          WaitForScriptTagEvent("file_js_cache_syntax_error.html");
+      assert_equals(await stateMachineResult, "source_exec",
+                    "Check the lack of bytecode encoding");
+    }
+
+  done();
+  </script>
+</head>
+<body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1350359">Mozilla Bug 1350359</a>
+</body>
+</html>
--- a/extensions/spellcheck/locales/en-US/hunspell/README_en_US.txt
+++ b/extensions/spellcheck/locales/en-US/hunspell/README_en_US.txt
@@ -1,11 +1,11 @@
 en_US-mozilla Hunspell Dictionary
-Generated from SCOWL Version 2017.01.22
-Tue Jan 24 22:59:28 EST 2017
+Generated from SCOWL Version 2017.08.24
+Mon Dec  4 10:21:53 EST 2017
 
 http://wordlist.sourceforge.net
 
 README file for English Hunspell dictionaries derived from SCOWL.
 
 These dictionaries are created using the speller/make-hunspell-dict
 script in SCOWL.
 
@@ -339,9 +339,9 @@ and Australian word list.  It is under t
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   SUCH DAMAGE.
 
-Build Date: Tue Jan 24 22:59:28 EST 2017
+Build Date: Mon Dec  4 10:21:53 EST 2017
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-added
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/5-mozilla-added
@@ -1162,17 +1162,16 @@ Cybil's
 Cyndi
 Cyndi's
 Cynthy
 Cynthy's
 Cyrille
 Cyrille's
 D'Arcy
 DRM
-DVDs
 Dacey
 Dacey's
 Dacia
 Daffy's
 Dag's
 Dagmar
 Dagmar's
 Dagny
@@ -2464,16 +2463,17 @@ Ivie
 Ivie's
 Ivoire
 Ivor
 Ivor's
 Izzy
 Izzy's
 JPEG's
 JPEGs
+JSON
 Jabez
 Jabez's
 Jacinta
 Jacinta's
 Jacki
 Jacki's
 Jacklin
 Jacklin's
@@ -5190,20 +5190,23 @@ admin's
 adoptee
 adoptee's
 adoptees
 advocator
 advocator's
 advocators
 adware's
 adwares
-aggregator
-aggregator's
-aggregators
 alkoxy
+amici
+amicus
+analytics
+anaphylactic
+anaphylaxes
+anaphylaxis
 anonymization
 anonymization's
 anonymizations
 anonymize
 anonymized
 anonymizes
 anonymizing
 anthropomorphized
@@ -5234,16 +5237,22 @@ aurei
 auteur's
 auteurs
 autocomplete
 autocompletes
 avant-garde
 axe
 axe's
 badging
+balkanization
+balkanize
+balkanized
+balkanizes
+balkanizing
+bimodal
 biodiesel
 biodiesel's
 bioinformatic
 bioinformatic's
 bioinformatics
 biosyntheses
 biotech's
 blogroll
@@ -5254,16 +5263,17 @@ bloviated
 bloviates
 bloviating
 bloviation
 bloviator
 bloviator's
 bloviators
 bookselling
 broadcasted
+bullseyes
 cDNA
 canceller
 canceller's
 canonicalization
 canonicalization's
 canonicalizations
 canonicalize
 canonicalized
@@ -5281,16 +5291,17 @@ chickenshit's
 ciphertext
 ciphertexts
 closable
 codec
 codec's
 codecs
 codon's
 coli
+collegial
 colonoscope
 colonoscope's
 colonoscopes
 commenters
 compositeness
 concurrents
 conferable
 config
@@ -5324,16 +5335,21 @@ datasheet's
 datasheets
 decertification
 decertifications
 decertified
 decertifies
 decertify
 decertifying
 deconstructionist's
+decrypt
+decryptable
+decrypted
+decrypting
+decrypts
 degenerations
 dehydrogenase's
 deliverables
 dequeue
 dequeued
 dequeues
 dequeuing
 designee
@@ -5349,34 +5365,39 @@ dihydro
 disarrangements
 disassembler
 disassembler's
 disassemblers
 disassembly's
 disclaimable
 disclosable
 discountenance's
+discoverable
 disintermediation
 disintermediations
 dissentious
 djinn
 donator
 donator's
 donators
 durian
 durian's
 durians
+dystopian
+dystopians
+dystopias
 eBook
 eBook's
 eBooks
 eCommerce
 eCommerce's
 elicitor
 elicitor's
 elicitors
+encodings
 encyclopaedia
 enqueue
 enqueued
 enqueues
 enqueuing
 eschatologist
 eschatologist's
 eschatologists
@@ -5384,16 +5405,21 @@ exacta
 exactable
 exactas
 exactingness
 exactions
 exactor
 exactor's
 exactors
 experimentalism
+explainer
+explainers
+expunction
+expungement
+expungements
 filesystem
 filesystem's
 filesystems
 filmography
 financials
 fluidize
 fluidizes
 fluidizing
@@ -5402,16 +5428,19 @@ flyer's
 flyers
 foci
 forma
 fracker
 frackers
 freegan
 freegans
 fuckhead's
+fugacious
+fugaciously
+fugaciousness
 gamification
 gamified
 gamifies
 gamify
 gamifying
 gastroenterologist
 gastroenterologist's
 gastroenterology
@@ -5454,22 +5483,28 @@ intermediacy
 intermediated
 intermediateness
 intermediating
 intermediation
 intermediations
 intermediator
 intermediator's
 intermediators
+intermittence
+intermittences
+intermittencies
+intermittency
 interruptible
 intersexual
 intersexual's
 intersexualism
 intersexuality
 intersexuals
+intifada
+intifadas
 jewellery
 judgement
 judgement's
 judgements
 kbps
 keylogger
 keylogger's
 keyloggers
@@ -5486,16 +5521,18 @@ lepidopterists
 limnological
 limnologist
 limnologist's
 limnologists
 limnology
 limnology's
 linguistical
 mRNA
+malform
+malforms
 malwares
 mammalia
 megajoule
 megajoule's
 mesothelioma
 mesothelioma's
 metadata's
 methoxy
@@ -5537,28 +5574,31 @@ navet
 navet's
 neurophysiology's
 neuroscience's
 neurosciences
 neuroscientist
 neuroscientist's
 neuroscientists
 newswires
+nondeterminism
+nondeterministic
 octopi
 oligo
 opposable
 opposer
 outlier's
 parallelization
 parallelization's
 parallelizations
 parallelize
 parallelized
 parallelizes
 parallelizing
+parsers
 permalink
 permalink's
 permalinks
 permittee
 phlebotomist
 phlebotomist's
 phlebotomists
 phlebotomize
@@ -5570,18 +5610,23 @@ phosphorylate
 phosphorylated
 phosphorylates
 phosphorylating
 plaintext
 polynucleotide
 polynucleotide's
 polynucleotides
 polypeptide's
+positivities
+positivity
+positivity's
 poutine
 poutines
+preinstall
+preinstalled
 prejudgement
 prejudgement's
 prejudgements
 preliminarily
 proclaimable
 procreations
 profiler
 profiler's
@@ -5611,39 +5656,51 @@ reactivity's
 reappointments
 rebroadcasted
 recency
 recompilation's
 recurse
 recursed
 recurses
 recursing
+recusal
+recusals
+rediscoverable
 reflux's
 relocations
+remediate
+remediated
+remediates
+remediating
 renominations
 repartitions
 resizable
 resizer
 resubmission's
 retransmission's
 rheumatological
 rheumatologist
 rheumatologist's
 rheumatologists
 rheumatology
 rheumatology's
+roadmap
+roadmaps
 rotatably
 sativa
 savoir
 schnaps
 schrod
 schrods
+scooch
+scooched
+scooches
+scooching
 scot-free
 screenshot's
-searchable
 selfing
 selfism
 selfist
 selfists
 seraphim
 shemale
 shemale's
 shemales
@@ -5659,16 +5716,19 @@ signups
 snarkily
 sommelier
 sommelier's
 sommeliers
 spelt
 spick
 spicks
 spywares
+strategize
+strategized
+strategizing
 substituent's
 substituents
 subsumptions
 syllabi
 synches
 synesthesia
 synesthete
 synesthetes
@@ -5719,16 +5779,17 @@ unchecking
 unchecks
 undeliverables
 undesignated
 unironic
 unironically
 unlabelled
 validator
 validators
+vanishingly
 vertebrata
 volcanological
 volcanologist
 volcanologist's
 volcanologists
 volcanology
 volcanology's
 webdesign
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/README_en_US-custom.txt
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/README_en_US-custom.txt
@@ -1,11 +1,11 @@
 en_US-custom Hunspell Dictionary
-Generated from SCOWL Version 2017.01.22
-Tue Jan 24 22:59:27 EST 2017
+Generated from SCOWL Version 2017.08.24
+Mon Dec  4 10:21:52 EST 2017
 
 http://wordlist.sourceforge.net
 
 README file for English Hunspell dictionaries derived from SCOWL.
 
 These dictionaries are created using the speller/make-hunspell-dict
 script in SCOWL.
 
@@ -339,10 +339,10 @@ and Australian word list.  It is under t
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   SUCH DAMAGE.
 
-Build Date: Tue Jan 24 22:59:27 EST 2017
+Build Date: Mon Dec  4 10:21:52 EST 2017
 With Input Command: ../mk-list -v1 --accents=both en_US 60
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/orig/en_US-custom.dic
@@ -1,9 +1,9 @@
-49467
+49547
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -1041,16 +1041,17 @@ Begin/M
 Behan/M
 Behring/M
 Beiderbecke/M
 Beijing/M
 Beirut/M
 Bekesy/M
 Bela/M
 Belarus/M
+Belarusian
 Belau/M
 Belem/M
 Belfast/M
 Belg
 Belgian/SM
 Belgium/M
 Belgrade/M
 Belinda/M
@@ -1068,16 +1069,17 @@ Belorussian/MS
 Belshazzar/M
 Beltane/M
 Belushi/M
 Ben/M
 Benacerraf/M
 Benares/M
 Benchley/M
 Bender/M
+Bendictus
 Bendix/M
 Benedict/M
 Benedictine/MS
 Benelux/M
 Benet/M
 Benetton/M
 Bengal/SM
 Bengali/M
@@ -1405,16 +1407,17 @@ Brenner/M
 Brent/M
 Brenton/M
 Brest/M
 Bret/M
 Breton/M
 Brett/M
 Brewer/M
 Brewster/M
+Brexit
 Brezhnev/M
 Brian/M
 Briana/M
 Brianna/M
 Brice/M
 Bridalveil/M
 Bridgeport/M
 Bridger/M
@@ -1584,17 +1587,17 @@ CAM
 CAP
 CARE
 CATV
 CB
 CBC/M
 CBS/M
 CCTV
 CCU
-CD/M
+CD/SM
 CDC
 CDT
 CEO/M
 CF
 CFC/M
 CFO
 CGI
 CIA/M
@@ -2461,17 +2464,17 @@ DOD
 DOE
 DOS/M
 DOT
 DP/SM
 DPT
 DST
 DTP
 DUI
-DVD
+DVD/S
 DVR/SM
 DWI
 Dachau/M
 Dacron/SM
 Dada/M
 Dadaism/M
 Daedalus/M
 Daguerre/M
@@ -5968,16 +5971,17 @@ Mafioso/M
 Magdalena/M
 Magdalene/M
 Magellan/M
 Magellanic/M
 Maggie/M
 Maghreb/M
 Magi
 Maginot/M
+Magnificat
 Magnitogorsk/M
 Magog/M
 Magoo/M
 Magritte/M
 Magsaysay/M
 Magus
 Magyar/SM
 Mahabharata/M
@@ -8736,16 +8740,17 @@ Secretary
 Seder/MS
 Sedna/M
 Seebeck/M
 Seeger/M
 Sega/M
 Segovia/M
 Segre/M
 Segundo/M
+Segway/S
 Seiko/M
 Seine/M
 Seinfeld/M
 Sejong/M
 Selassie/M
 Selectric/M
 Selena/M
 Seleucid/M
@@ -10868,16 +10873,17 @@ acetaminophen/M
 acetate/MS
 acetic
 acetone/M
 acetonic
 acetyl
 acetylene/M
 ache/DSMG
 achene/MS
+achievable/U
 achieve/BLZGDRS
 achievement/SM
 achiever/M
 aching/Y
 achoo/M
 achromatic
 achy/TR
 acid/SMY
@@ -11279,16 +11285,17 @@ agglutinate/DSXGN
 agglutination/M
 aggrandize/GLDS
 aggrandizement/M
 aggravate/GNXDS
 aggravating/Y
 aggravation/M
 aggregate/MGNDSX
 aggregation/M
+aggregator/SM
 aggression/M
 aggressive/PY
 aggressiveness/M
 aggressor/SM
 aggrieve/DSG
 aggro
 aghast
 agile/Y
@@ -11672,16 +11679,17 @@ amiably
 amicability/M
 amicable
 amicably
 amid
 amide/MS
 amidship/S
 amidst
 amigo/MS
+amine/S
 amino
 amir/SM
 amiss
 amity/M
 ammeter/SM
 ammo/M
 ammonia/M
 ammonium
@@ -11734,16 +11742,17 @@ amputation/M
 amputee/MS
 amt
 amuck
 amulet/MS
 amuse/LGDS
 amusement/MS
 amusing/Y
 amylase/M
+amyloid
 an/CS
 anabolism/M
 anachronism/SM
 anachronistic
 anachronistically
 anaconda/SM
 anaerobe/SM
 anaerobic
@@ -12013,32 +12022,35 @@ antiknock/M
 antilabor
 antilogarithm/SM
 antimacassar/MS
 antimalarial
 antimatter/M
 antimicrobial
 antimissile
 antimony/M
+antineutrino/SM
+antineutron/MS
 antinuclear
 antioxidant/MS
 antiparticle/SM
 antipasti
 antipasto/MS
 antipathetic
 antipathy/SM
 antipersonnel
 antiperspirant/SM
 antiphon/SM
 antiphonal/MYS
 antipodal/S
 antipodean/MS
 antipodes/M
 antipollution
 antipoverty
+antiproton/MS
 antiquarian/SM
 antiquarianism/M
 antiquary/SM
 antiquate/GDS
 antique/DSMG
 antiquity/SM
 antirrhinum/S
 antiscience
@@ -12570,17 +12582,17 @@ assignable
 assignation/MS
 assigned/U
 assignee/M
 assigner/MS
 assignment/AMS
 assignor/MS
 assimilate/DSGN
 assimilation/M
-assist/GMDS
+assist/GVMDS
 assistance/M
 assistant/SM
 assisted/U
 assize/MS
 assn
 assoc
 associate's
 associate/EDSGNV
@@ -14568,16 +14580,17 @@ botanic
 botanical/Y
 botanist/SM
 botany/M
 botch/DRSZGM
 botcher/M
 both
 bother/SMDG
 botheration
+bothered/U
 bothersome
 botnet/SM
 bottle/DRSMZG
 bottleneck/MS
 bottler/M
 bottom/SMDG
 bottomless
 botulinum
@@ -15045,17 +15058,17 @@ bulkhead/MS
 bulkiness/M
 bulky/RTP
 bull/MDGS
 bulldog/SM
 bulldogged
 bulldogging
 bulldoze/ZGDRS
 bulldozer/M
-bullet/SM
+bullet/SMD
 bulletin/MDGS
 bulletproof/SDG
 bullfight/SMRZG
 bullfighter/M
 bullfighting/M
 bullfinch/MS
 bullfrog/MS
 bullhead/MDS
@@ -15063,16 +15076,17 @@ bullheaded/PY
 bullheadedness/M
 bullhorn/MS
 bullion/M
 bullish/YP
 bullishness/M
 bullock/SM
 bullpen/SM
 bullring/MS
+bullseye
 bullshit/MS!
 bullshitted/!
 bullshitter/SM!
 bullshitting/!
 bullwhip/S
 bully/DSMG
 bulrush/MS
 bulwark/MS
@@ -15945,16 +15959,17 @@ caveat/MS
 caveman/M
 cavemen
 cavern/MS
 cavernous/Y
 caviar/M
 cavil/ZGJMDRS
 caviler/M
 caving/M
+cavitation
 cavity/FSM
 cavort/DGS
 caw/SMDG
 cay/CSM
 cayenne/M
 cayuse/MS
 cc
 cease/CMGDS
@@ -16972,18 +16987,18 @@ clumsily
 clumsiness/M
 clumsy/TRP
 clung
 clunk/SMDRZG
 clunker/M
 clunky/TR
 cluster/MDSG
 clutch/GMDS
-clutter/MDSG
-cluttered/U
+clutter's
+clutter/UDSG
 clvi
 clvii
 clxi
 clxii
 clxiv
 clxix
 clxvi
 clxvii
@@ -17045,16 +17060,17 @@ coccyges
 coccyx/M
 cochineal/M
 cochlea/SM
 cochleae
 cochlear
 cock/MDGS
 cockade/SM
 cockamamie
+cockatiel/MS
 cockatoo/SM
 cockatrice/SM
 cockchafer/S
 cockcrow/SM
 cockerel/SM
 cockeyed
 cockfight/MGS
 cockfighting/M
@@ -17213,17 +17229,17 @@ collectivist/SM
 collectivization/M
 collectivize/DSG
 collector/MS
 colleen/SM
 college/SM
 collegiality/M
 collegian/MS
 collegiate
-collide/DSG
+collide/DRSZG
 collie/RSMZ
 collier/M
 colliery/SM
 collision/SM
 collocate/MGNDSX
 collocation/M
 colloid/SM
 colloidal
@@ -17296,20 +17312,20 @@ combed/U
 comber/M
 combination/SM
 combine's
 combine/ADSG
 combined/U
 combiner/MS
 combings/M
 combo/SM
+combust/SGVD
 combustibility/M
 combustible/MS
 combustion/M
-combustive
 come/IMZGRS
 comeback/MS
 comedian/MS
 comedic
 comedienne/MS
 comedown/MS
 comedy/SM
 comeliness/M
@@ -17642,16 +17658,17 @@ condense/DRSZG
 condenser/M
 condescending/Y
 condescension/M
 condign
 condiment/MS
 condition's
 condition/AGSD
 conditional/SMY
+conditionality
 conditioned/U
 conditioner/SM
 conditioning/M
 condo/SM
 condolence/SM
 condom/SM
 condominium/MS
 condone/DSG
@@ -17979,16 +17996,17 @@ continuance/EMS
 continuation/EMS
 continue/EGDS
 continuity/ESM
 continuous/EY
 continuum/M
 contort/GD
 contortion/MS
 contortionist/SM
+contra
 contraband/M
 contrabassoon/S
 contraception/M
 contraceptive/SM
 contract/MDG
 contractible
 contractile
 contractility
@@ -18406,16 +18424,17 @@ counterpoint/MDGS
 counterpoise/MGDS
 counterproductive
 counterrevolution/SM
 counterrevolutionary/SM
 countersign/GSMD
 countersignature/MS
 countersink/GSM
 counterspy/SM
+counterstroke/SM
 countersunk
 countertenor/MS
 countervail/GSD
 counterweight/MS
 countess/MS
 countless
 countrified
 country/SM
@@ -18713,16 +18732,17 @@ crispbread/S
 crispiness/M
 crispness/M
 crispy/PRT
 crisscross/GMDS
 criteria
 criterion/M
 critic/SM
 critical/UY
+criticality
 criticism/MS
 criticize/ZGDRS
 criticizer/M
 critique/MGDS
 critter/SM
 croak/SMDG
 croaky/RT
 crochet/SMDRZG
@@ -19418,18 +19438,17 @@ decorator/MS
 decorous/IY
 decorousness/M
 decorum/M
 decoupage/DSMG
 decoy/GMDS
 decreasing/Y
 decree/MDS
 decreeing
-decremented
-decrements
+decrement/DS
 decrepit
 decrepitude/M
 decriminalization/M
 decry/GDS
 decryption
 dedicate/AGDS
 dedication/SM
 dedicator/SM
@@ -20078,16 +20097,17 @@ difficult/Y
 difficulty/SM
 diffidence/M
 diffident/Y
 diffract/GSD
 diffraction/M
 diffuse/DSYGNVP
 diffuseness/M
 diffusion/M
+diffusivity
 dig/SM
 digerati/M
 digest/SMDGV
 digested/U
 digestibility/M
 digestible/I
 digestion/IM
 digestions
@@ -20123,16 +20143,17 @@ dilemma/MS
 dilettante/SM
 dilettantish
 dilettantism/M
 diligence/M
 diligent/Y
 dill/MS
 dilly/SM
 dillydally/DSG
+diluent
 dilute/DSGNX
 diluted/U
 dilution/M
 dim/PSRY
 dime/MS
 dimension/SM
 dimensional
 dimensionless
@@ -21165,16 +21186,17 @@ dyslexia/M
 dyslexic/SM
 dyspepsia/M
 dyspeptic/MS
 dysphagia
 dysphoria
 dysphoric
 dysprosium/M
 dystonia
+dystopia
 dz
 débridement
 débutante/SM
 décolletage/SM
 décolleté
 démodé
 dérailleur/MS
 déshabillé/M
@@ -21264,16 +21286,17 @@ ebullition/M
 eccentric/SM
 eccentrically
 eccentricity/SM
 eccl
 ecclesial
 ecclesiastic/SM
 ecclesiastical/Y
 echelon/SM
+echidna
 echinoderm/SM
 echo's
 echo/ADG
 echoes/A
 echoic
 echolocation/M
 echos
 eclair/SM
@@ -21383,16 +21406,17 @@ efficiency/ISM
 efficient/IY
 effigy/SM
 efflorescence/M
 efflorescent
 effluence/M
 effluent/MS
 effluvia
 effluvium/M
+efflux
 effort/SM
 effortless/YP
 effortlessness/M
 effrontery/M
 effulgence/M
 effulgent
 effuse/DSGNVX
 effusion/M
@@ -21926,16 +21950,17 @@ ensure/ZGDRS
 ensurer/M
 entail/DSGL
 entailment/M
 entangle/EDSLG
 entanglement/EM
 entanglements
 entente/SM
 enter/ASGD
+enteral
 enteric
 enteritis/M
 enterprise/MGS
 enterprising/Y
 entertain/ZGDRSL
 entertainer/M
 entertaining/MY
 entertainment/MS
@@ -21959,16 +21984,17 @@ entity/SM
 entomb/DSGL
 entombment/M
 entomological
 entomologist/MS
 entomology/M
 entourage/SM
 entr'acte
 entrails/M
+entrained
 entrance/LDSMG
 entrancement/M
 entrancing/Y
 entrant/SM
 entrap/LS
 entrapment/M
 entrapped
 entrapping
@@ -22283,16 +22309,17 @@ etymology/SM
 eucalypti
 eucalyptus/MS
 euchre/DSMG
 euclidean
 eugenic/S
 eugenically
 eugenicist/MS
 eugenics/M
+eukaryotes
 eulogist/MS
 eulogistic
 eulogize/ZGDRS
 eulogizer/M
 eulogy/SM
 eunuch/M
 eunuchs
 euphemism/SM
@@ -22312,16 +22339,17 @@ euthanize/DSG
 euthenics/M
 evacuate/XDSGN
 evacuation/M
 evacuee/MS
 evade/DRSZG
 evader/M
 evaluate/AGNVDSX
 evaluation/AM
+evaluator/S
 evanescence/M
 evanescent
 evangelic
 evangelical/SMY
 evangelicalism/M
 evangelism/M
 evangelist/MS
 evangelistic
@@ -22709,17 +22737,17 @@ extolled
 extolling
 extort/SGD
 extortion/MRZ
 extortionate/Y
 extortioner/M
 extortionist/MS
 extra/SM
 extracellular
-extract/MDGS
+extract/MDGVS
 extraction/SM
 extractor/MS
 extracurricular
 extradite/GNBXDS
 extradition/M
 extrajudicial
 extralegal
 extramarital
@@ -22797,16 +22825,17 @@ fabricator/SM
 fabulous/Y
 facade/SM
 face's
 face/ACSDG
 facecloth/M
 facecloths
 faceless
 facelift/SM
+facepalm/SDG
 facet/SMDG
 facetious/YP
 facetiousness/M
 facial/SMY
 facile/Y
 facilitate/GNDS
 facilitation/M
 facilitator/MS
@@ -24110,16 +24139,17 @@ fossilize/GDS
 foster/GSD
 fought
 foul/MDRYTGSP
 foulard/M
 foulmouthed
 foulness/M
 found/FSDG
 foundation/SM
+foundational
 founded/U
 founder/GMDS
 foundling/SM
 foundry/SM
 fount/SM
 fountain/SM
 fountainhead/MS
 four/MHS
@@ -25176,29 +25206,31 @@ glue/MGDS
 glued/U
 gluey
 gluier
 gluiest
 glum/YP
 glummer
 glummest
 glumness/M
+gluon/S
 glut/MNS
 gluten/M
 glutenous
 glutinous/Y
 glutted
 glutting
 glutton/MS
 gluttonous/Y
 gluttony/M
 glycerin/M
 glycerine/M
 glycerol/M
 glycogen/M
+glycol
 glyph
 gm
 gnarl/SMDG
 gnarly/TR
 gnash/MDSG
 gnat/MS
 gnaw/DGS
 gneiss/M
@@ -26244,16 +26276,17 @@ hawk/MDRZGS
 hawker/M
 hawkish/P
 hawkishness/M
 hawser/SM
 hawthorn/MS
 hay/GSMD
 haycock/SM
 hayloft/SM
+haymaker/S
 haymaking
 haymow/SM
 hayrick/MS
 hayride/MS
 hayseed/MS
 haystack/SM
 haywire
 hazard/SMDG
@@ -26550,16 +26583,17 @@ herein
 hereinafter
 hereof
 hereon
 heresy/SM
 heretic/SM
 heretical
 hereto
 heretofore
+hereunder
 hereunto
 hereupon
 herewith
 heritable/I
 heritage/MS
 hermaphrodite/SM
 hermaphroditic
 hermetic
@@ -27318,16 +27352,17 @@ hydrogenation/M
 hydrogenous
 hydrologist/MS
 hydrology/M
 hydrolyses
 hydrolysis/M
 hydrolyze/DSG
 hydrometer/SM
 hydrometry/M
+hydrophilic
 hydrophobia/M
 hydrophobic
 hydrophone/SM
 hydroplane/GDSM
 hydroponic/S
 hydroponically
 hydroponics/M
 hydrosphere/M
@@ -28153,17 +28188,17 @@ infirm
 infirmary/SM
 infirmity/SM
 infix
 inflame/DSG
 inflammable
 inflammation/SM
 inflammatory
 inflatable/SM
-inflate/DSGNB
+inflate/ADSG
 inflation/EM
 inflationary
 inflect/SDG
 inflection/MS
 inflectional
 inflict/SDGV
 infliction/M
 inflight
@@ -28172,16 +28207,17 @@ influence/MGDS
 influenced/U
 influential/Y
 influenza/M
 info/M
 infomercial/SM
 inform/Z
 informal/Y
 informant/SM
+informatics
 information/EM
 informational
 informative/PY
 informativeness/M
 informed/U
 infotainment/M
 infra
 infrared/M
@@ -28291,16 +28327,17 @@ innuendo/SM
 innuendoes
 innumerably
 innumerate
 inoculate/AGDS
 inoculation/MS
 inoperative
 inordinate/Y
 inorganic
+inositol
 inquire/ZGDR
 inquirer/M
 inquiring/Y
 inquiry/SM
 inquisition/MS
 inquisitional
 inquisitive/YP
 inquisitiveness/M
@@ -28684,17 +28721,18 @@ inveigle/ZGDRS
 inveigler/M
 invent/ASGVD
 invention/AMS
 inventive/PY
 inventiveness/M
 inventor/MS
 inventory/DSMG
 inverse/SMY
-invert/SMDG
+invert/SMDRZG
+inverter/M
 invest/ASDGL
 investigate/GNVDSX
 investigation/M
 investigator/SM
 investigatory
 investiture/MS
 investment/AEM
 investor/SM
@@ -28718,16 +28756,17 @@ invite/DSMG
 invited/U
 invitee/SM
 inviting/Y
 invoke/DSG
 involuntariness/M
 involuntary/P
 involution/M
 involve/LDSG
+involved/U
 involvement/SM
 inward/SY
 ioctl
 iodide/SM
 iodine/M
 iodize/DSG
 ion/USM
 ionic
@@ -29310,16 +29349,17 @@ keratitis
 kerbside
 kerchief/SM
 kerfuffle/S
 kernel/SM
 kerosene/M
 kestrel/MS
 ketch/MS
 ketchup/M
+ketone/S
 kettle/SM
 kettledrum/SM
 key/SGMD
 keybinding/S
 keyboard/ZGSMDR
 keyboarder/M
 keyboardist/SM
 keyhole/MS
@@ -30713,16 +30753,17 @@ lumbago/M
 lumbar
 lumber/MDRZGS
 lumberer/M
 lumbering/M
 lumberjack/SM
 lumberman/M
 lumbermen
 lumberyard/SM
+lumen
 luminary/SM
 luminescence/M
 luminescent
 luminosity/M
 luminous/Y
 lummox/MS
 lump/MDNSG
 lumpectomy/S
@@ -30762,16 +30803,17 @@ lustful/Y
 lustily
 lustiness/M
 lustrous/Y
 lusty/PTR
 lutanist/SM
 lute/MS
 lutenist/SM
 lutetium/M
+lux
 luxuriance/M
 luxuriant/Y
 luxuriate/DSGN
 luxuriation/M
 luxurious/PY
 luxuriousness/M
 luxury/SM
 lvi
@@ -31391,16 +31433,17 @@ maw/SM
 mawkish/PY
 mawkishness/M
 max/GMDS
 maxi/MS
 maxilla/M
 maxillae
 maxillary
 maxim/SM
+maxima
 maximal/Y
 maximization/M
 maximize/GDS
 maximum/SM
 may/M
 maybe/SM
 mayday/MS
 mayflower/MS
@@ -32010,16 +32053,17 @@ miniaturize/GDS
 minibar/S
 minibike/SM
 minibus/MS
 minicab/S
 minicam/MS
 minicomputer/SM
 minifloppies
 minim/SM
+minima
 minimal/Y
 minimalism/M
 minimalist/MS
 minimization/M
 minimize/DSG
 minimum/MS
 mining/M
 minion/M
@@ -32245,16 +32289,17 @@ mitochondria
 mitochondrial
 mitochondrion
 mitoses
 mitosis/M
 mitotic
 mitral
 mitt/MNSX
 mitten/M
+mitzvah
 mix/ZGMDRSB
 mixed/U
 mixer/M
 mixture/SM
 mizzen/MS
 mizzenmast/SM
 mkay
 mks
@@ -32769,16 +32814,17 @@ mull/DSG
 mullah/M
 mullahs
 mullein/M
 mullet/MS
 mulligan/SM
 mulligatawny/M
 mullion/SMD
 multi
+multichannel
 multicolored
 multicultural
 multiculturalism/M
 multidimensional
 multidisciplinary
 multifaceted
 multifamily
 multifarious/PY
@@ -32788,16 +32834,17 @@ multigrain
 multilateral/Y
 multilayered
 multilevel
 multilingual
 multilingualism/M
 multimedia/M
 multimillionaire/SM
 multinational/SM
+multipart
 multiparty
 multiplayer/M
 multiple/MS
 multiplex/ZGMDRS
 multiplexer/M
 multiplicand/MS
 multiplication/M
 multiplicative
@@ -32825,16 +32872,17 @@ mumbletypeg/M
 mummer/MS
 mummery/M
 mummification/M
 mummify/GNDS
 mummy/SM
 mumps/M
 mun
 munch/GDS
+munchie/S
 munchies/M
 munchkin/SM
 mundane/SY
 mung/DSG
 municipal/SMY
 municipality/SM
 munificence/M
 munificent/Y
@@ -32906,16 +32954,17 @@ mustard/M
 muster/GMD
 mustily
 mustiness/M
 mustn't
 musty/PTR
 mutability/M
 mutably
 mutagen/MS
+mutagenic
 mutant/MS
 mutate/XGNVDS
 mutation/M
 mutational
 mute/MYTGDRSPB
 muteness/M
 mutilate/DSGNX
 mutilation/M
@@ -33437,16 +33486,17 @@ nisei/M
 nit/SMR
 nite/MS
 niter/M
 nitpick/SZGDR
 nitpicker/M
 nitpicking/M
 nitrate/DSMGN
 nitration/M
+nitric
 nitrification/M
 nitrite/SM
 nitro
 nitrocellulose/M
 nitrogen/M
 nitrogenous
 nitroglycerin/M
 nitroglycerine/M
@@ -34183,16 +34233,17 @@ octal
 octane/MS
 octave/MS
 octavo/MS
 octet/SM
 octogenarian/SM
 octopus/MS
 ocular/MS
 oculist/SM
+oculomotor
 odalisque/SM
 odd/STRYLP
 oddball/SM
 oddity/SM
 oddment/SM
 oddness/M
 odds/M
 ode/SM
@@ -34324,16 +34375,17 @@ omnipotent
 omnipresence/M
 omnipresent
 omniscience/M
 omniscient
 omnivore/MS
 omnivorous/PY
 omnivorousness/M
 on/Y
+onboard
 once/M
 oncogene/SM
 oncologist/SM
 oncology/M
 oncoming
 one/SXMNP
 oneness/M
 onerous/PY
@@ -34475,16 +34527,17 @@ orchestra/MS
 orchestral
 orchestrate/DSXGN
 orchestration/M
 orchid/SM
 ordain/SDLG
 ordainment/M
 ordeal/SM
 order/EAMDGS
+ordered/U
 orderings
 orderliness/EM
 orderly/PSM
 ordinal/SM
 ordinance/SM
 ordinarily
 ordinariness/M
 ordinary/SMP
@@ -34875,16 +34928,17 @@ overhaul/MDSG
 overhead/MS
 overhear/SG
 overheard
 overheat/DSG
 overhung
 overindulge/GDS
 overindulgence/M
 overindulgent
+overinflated
 overjoy/GSD
 overkill/M
 overladen
 overlaid
 overlain
 overland
 overlap/SM
 overlapped
@@ -35032,16 +35086,17 @@ ownership/M
 ox/MN
 oxblood/M
 oxbow/MS
 oxcart/SM
 oxford/SM
 oxidant/MS
 oxidase
 oxidation/M
+oxidative
 oxide/MS
 oxidization/M
 oxidize/ZGDRS
 oxidizer/M
 oxtail/S
 oxyacetylene/M
 oxygen/M
 oxygenate/DSGN
@@ -35316,16 +35371,17 @@ paralysis/M
 paralytic/SM
 paralyze/DSG
 paralyzing/Y
 paramecia
 paramecium/M
 paramedic/MS
 paramedical/MS
 parameter/MS
+parameterize/D
 parametric
 paramilitary/SM
 paramount
 paramountcy
 paramour/SM
 paranoia/M
 paranoiac/MS
 paranoid/SM
@@ -35977,16 +36033,17 @@ perpetrate/DSGN
 perpetration/M
 perpetrator/MS
 perpetual/SMY
 perpetuate/DSGN
 perpetuation/M
 perpetuity/M
 perplex/GDS
 perplexed/Y
+perplexing/Y
 perplexity/SM
 perquisite/SM
 persecute/GNXDS
 persecution/M
 persecutor/SM
 perseverance/M
 persevere/DSG
 persiflage/M
@@ -36323,16 +36380,17 @@ pickle/MGDS
 pickpocket/SM
 pickup/MS
 picky/PTR
 picnic/MS
 picnicked
 picnicker/SM
 picnicking
 picot/SM
+pictogram/S
 pictograph/M
 pictographs
 pictorial/MYS
 picture/MGDS
 picturesque/PY
 picturesqueness/M
 piddle/MGDS
 piddly
@@ -36993,16 +37051,17 @@ popping
 poppy/SM
 poppycock/M
 populace/MS
 popular/Y
 popularity/UM
 popularization/M
 popularize/DSG
 populate/ACGDS
+populated/U
 population/CM
 populations
 populism/M
 populist/MS
 populous/P
 populousness/M
 popup/MS
 porcelain/SM
@@ -37060,17 +37119,17 @@ pose's/A
 pose/CAKEGDS
 poser/EKSM
 poseur/SM
 posh/TR
 posit/DSGV
 position/CKEMS
 positional/K
 positioned/K
-positioning/K
+positioning/AK
 positive/MYPS
 positiveness/M
 positivism
 positivist/S
 positron/MS
 poss
 posse/MS
 possess/AEVGSD
@@ -37389,16 +37448,17 @@ premonition/MS
 premonitory
 prenatal/Y
 prenup/SM
 prenuptial
 preoccupation/SM
 preoccupy/DSG
 preoperative
 preordain/GDS
+preowned
 prep/MS
 prepackage/DSG
 prepacked
 prepaid
 preparation/SM
 preparatory
 prepare/GDS
 prepared/UP
@@ -37627,28 +37687,29 @@ probably
 probate/MN
 probation/ZMR
 probational
 probationary
 probationer/M
 probe/MGDSBJ
 probity/M
 problem/MS
-problematic
+problematic/U
 problematical/Y
 probosces
 proboscis/MS
 procaine/M
 procedural
 procedure/SM
 proceed/GJDS
 proceeding/M
 proceeds/M
 process's
 process/AGDS
+processable
 processed/U
 procession/GD
 processional/MS
 processor/SM
 proclamation/MS
 proclivity/SM
 procrastinate/DSGN
 procrastination/M
@@ -38392,16 +38453,17 @@ quietus/MS
 quiff/S
 quill/SM
 quilt/SMDRZG
 quilter/M
 quilting/M
 quin/S
 quince/SM
 quine/S
+quinidine
 quinine/M
 quinoa
 quinsy/M
 quint/SM
 quintessence/SM
 quintessential/Y
 quintet/SM
 quintuple/MGDS
@@ -38484,16 +38546,17 @@ raconteur/SM
 racquet/SM
 racquetball/SM
 racy/PRT
 rad/SM
 radar/SM
 radarscope/SM
 raddled
 radial/SMY
+radian/S
 radiance/M
 radiant/Y
 radiate/DSGNX
 radiation/M
 radiator/SM
 radical/SMY
 radicalism/M
 radicalization/M
@@ -39255,16 +39318,17 @@ repairman/M
 repairmen
 reparable
 reparation/MS
 reparations/M
 repartee/M
 repatriate/XDSMGN
 repatriation/M
 repeat/SMDRZGB
+repeatability
 repeatable/U
 repeatably
 repeated/Y
 repeater/M
 repeating/M
 repel/S
 repelled
 repellent/SM
@@ -39291,16 +39355,17 @@ repletion/M
 replica/SM
 replicate/DSGNX
 replication/M
 replicator/S
 reportage/M
 reported/Y
 reportorial
 reposeful
+reposition
 repository/SM
 reprehend/DGS
 reprehensibility/M
 reprehensible
 reprehensibly
 reprehension/M
 represent/GDS
 representational
@@ -39350,17 +39415,16 @@ reread/SG
 rerecord/GDS
 rerunning
 resat
 rescind/SDG
 rescission/M
 rescue/DRSMZG
 rescuer/M
 reseal/B
-resell/SG
 resemble/DSG
 resend
 resent/LSDG
 resentful/YP
 resentfulness/M
 resentment/MS
 reserpine/M
 reservation/MS
@@ -39383,16 +39447,17 @@ resigned/Y
 resilience/M
 resiliency/M
 resilient/Y
 resinous
 resist/SMDRZG
 resistance/SM
 resistant/U
 resistible
+resistivity
 resistless
 resistor/MS
 resit/S
 resitting
 resold
 resole/DSG
 resolute/PY
 resoluteness/M
@@ -40852,16 +40917,17 @@ seamless/Y
 seamount/MS
 seamstress/MS
 seamy/RT
 seance/SM
 seaplane/SM
 seaport/MS
 sear/GMDS
 search/AZGMDRS
+searchable/U
 searcher/AM
 searching/Y
 searchlight/MS
 searing/Y
 seascape/SM
 seashell/SM
 seashore/SM
 seasick/P
@@ -41022,18 +41088,19 @@ selenographer/MS
 selenography/M
 self/M
 selfie/SM
 selfish/UYP
 selfishness/UM
 selfless/PY
 selflessness/M
 selfsame
-sell/ZGMRS
-seller/M
+sell's
+sell/AZGRS
+seller's
 selloff/MS
 sellotape/DSG
 sellout/MS
 seltzer/MS
 selvage/MS
 selvedge/MS
 selves
 semantic/S
@@ -43964,16 +44031,17 @@ subconsciousness/M
 subcontinent/SM
 subcontinental
 subcontract/MDSG
 subcontractor/MS
 subculture/MS
 subcutaneous/Y
 subdivide/GDS
 subdivision/SM
+subdomain/MS
 subdominant
 subdue/DSG
 subeditor/S
 subfamily/SM
 subfreezing
 subgroup/MS
 subhead/GJMS
 subheading/M
@@ -44278,16 +44346,17 @@ supercharger/M
 supercilious/PY
 superciliousness/M
 supercity/SM
 supercomputer/MS
 superconducting
 superconductive
 superconductivity/M
 superconductor/SM
+supercritical
 superego/MS
 supererogation/M
 supererogatory
 superficial/Y
 superficiality/M
 superfine
 superfluity/M
 superfluous/YP
@@ -44304,16 +44373,17 @@ superintend/DSG
 superintendence/M
 superintendency/M
 superintendent/SM
 superior/MS
 superiority/M
 superlative/SMY
 superman/M
 supermarket/SM
+supermassive
 supermen
 supermodel/SM
 supermom/MS
 supernal
 supernatural/SY
 supernova/MS
 supernovae
 supernumerary/SM
@@ -44366,17 +44436,17 @@ supply/ZGDRSMXN
 support/MDRSBZGV
 supportable/UI
 supported/U
 supporter/M
 suppose/GDS
 supposed/Y
 supposition/MS
 suppository/SM
-suppress/GDS
+suppress/GVDS
 suppressant/MS
 suppressible
 suppression/M
 suppressor/SM
 suppurate/DSGN
 suppuration/M
 supra
 supranational
@@ -44919,16 +44989,17 @@ tarsus/M
 tart/PTGMDRYS
 tartan/MS
 tartar/MS
 tartaric
 tartness/M
 tarty/T
 taser/GMDS
 task/GMDS
+taskbar
 taskmaster/MS
 taskmistress/MS
 tassel/MDSG
 taste/JMZGDRS
 tasted/U
 tasteful/EPY
 tastefulness/EM
 tasteless/PY
@@ -45391,16 +45462,17 @@ therefor
 therefore
 therefrom
 therein
 theremin/SM
 thereof
 thereon
 thereto
 theretofore
+thereunder
 thereunto
 thereupon
 therewith
 therm/SM
 thermal/MYS
 thermionic
 thermodynamic/S
 thermodynamics/M
@@ -46063,16 +46135,17 @@ toxicology/M
 toxin/SM
 toy/SGMD
 toyboy/S
 tr
 trabecula
 trabecular
 trabecule
 trace/JDRSMZG
+traceability
 traceable/U
 tracer/M
 tracery/SM
 trachea/M
 tracheae
 tracheal
 tracheotomy/SM
 tracing/M
@@ -46846,16 +46919,17 @@ ultimate/MY
 ultimatum/MS
 ultimo
 ultra/SM
 ultraconservative/SM
 ultrahigh
 ultralight/SM
 ultramarine/M
 ultramodern
+ultrashort
 ultrasonic
 ultrasonically
 ultrasound/MS
 ultraviolet/M
 ululate/DSGNX
 ululation/M
 um
 umbel/SM
@@ -46986,16 +47060,17 @@ undergoes
 undergone
 undergrad/S
 undergraduate/SM
 underground/MS
 undergrowth/M
 underhand
 underhanded/PY
 underhandedness/M
+underinflated
 underlain
 underlay/SM
 underlie/S
 underline/MGDS
 underling/MS
 underlip/SM
 underlying
 undermanned
@@ -47238,25 +47313,25 @@ unrelated
 unrelenting/Y
 unrelieved/Y
 unremarkable
 unremitting/Y
 unrepentant
 unreported
 unrepresentative
 unrest/M
+unrevealing
 unripe/TR
 unroll/GDS
 unromantic
 unruliness/M
 unruly/RTP
 unsafe/YTR
 unsavory
 unscathed
-unsearchable
 unseeing/Y
 unseemly/T
 unseen/M
 unsentimental
 unset
 unshakable
 unshakably
 unshakeable
@@ -47815,16 +47890,17 @@ vichyssoise/M
 vicing
 vicinity/M
 vicious/YP
 viciousness/M
 vicissitude/SM
 victim/MS
 victimization/M
 victimize/GDS
+victimless
 victor/MS
 victorious/Y
 victory/SM
 victual/SMDG
 vicuna/MS
 vicuña/MS
 videlicet
 video/GSMD
@@ -48039,16 +48115,17 @@ volleyball/MS
 volt/AMS
 voltage/MS
 voltaic
 voltmeter/SM
 volubility/M
 voluble
 volubly
 volume/SM
+volumetric
 voluminous/YP
 voluminousness/M
 voluntarily/I
 voluntarism/M
 voluntary/SM
 volunteer/SGMD
 volunteerism/M
 voluptuary/SM
@@ -48343,16 +48420,17 @@ waterwheel/SM
 waterworks/M
 watery/PTR
 watt/MS
 wattage/M
 wattle/MGDS
 wave/MZGDRS
 waveband/S
 waveform
+wavefront
 wavelength/M
 wavelengths
 wavelet/SM
 wavelike
 waver/ZGMDR
 waverer/M
 wavering/Y
 waviness/M
@@ -49066,16 +49144,18 @@ workmate/S
 workmen
 workout/SM
 workplace/MS
 workroom/MS
 works/M
 worksheet/MS
 workshop/MS
 workshy
+worksite/S
+workspace
 workstation/MS
 worktable/MS
 worktop/S
 workup/MS
 workweek/SM
 world/SM
 worldlier
 worldliness/UM
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-52388
+52456
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -1327,16 +1327,17 @@ Behan/M
 Behring/M
 Beiderbecke/M
 Beijing/M
 Beirut/M
 Bekesy/M
 Bel/M
 Bela/M
 Belarus/M
+Belarusian
 Belau/M
 Belem/M
 Belfast/M
 Belg
 Belgian/SM
 Belgium/M
 Belgrade/M
 Belinda/M
@@ -1358,16 +1359,17 @@ Beltane/M
 Beltran/M
 Belushi/M
 Belva/M
 Ben/M
 Benacerraf/M
 Benares/M
 Benchley/M
 Bender/M
+Bendictus
 Bendix/M
 Benedetta/M
 Benedetto/M
 Benedick/M
 Benedict/M
 Benedicta/M
 Benedictine/MS
 Benedicto/M
@@ -1766,16 +1768,17 @@ Brenner/M
 Brent/M
 Brenton/M
 Brest/M
 Bret/M
 Breton/M
 Brett/M
 Brewer/M
 Brewster/M
+Brexit
 Brezhnev/M
 Brian/M
 Briana/M
 Brianna/M
 Brianne/M
 Briant/M
 Brice/M
 Bridalveil/M
@@ -1974,17 +1977,17 @@ CAM
 CAP
 CARE
 CATV
 CB
 CBC/M
 CBS/M
 CCTV
 CCU
-CD/M
+CD/SM
 CDC
 CDT
 CEO/SM
 CF
 CFC/SM
 CFO
 CGI
 CIA/M
@@ -7604,16 +7607,17 @@ Magdalene/M
 Magellan/M
 Magellanic/M
 Maggi/M
 Maggie/M
 Maggy/M
 Maghreb/M
 Magi
 Maginot/M
+Magnificat
 Magnitogorsk/M
 Magog/M
 Magoo/M
 Magritte/M
 Magsaysay/M
 Magus
 Magyar/SM
 Mahabharata/M
@@ -10997,16 +11001,17 @@ Secretary
 Seder/MS
 Sedna/M
 Seebeck/M
 Seeger/M
 Sega/M
 Segovia/M
 Segre/M
 Segundo/M
+Segway/S
 Seiko/M
 Seine/M
 Seinfeld/M
 Sejong/M
 Sela/M
 Selassie/M
 Selby/M
 Selectric/M
@@ -13544,16 +13549,17 @@ acetaminophen/M
 acetate/MS
 acetic
 acetone/M
 acetonic
 acetyl
 acetylene/M
 ache/DSMG
 achene/MS
+achievable/U
 achieve/BLZGDRS
 achievement/SM
 achiever/M
 aching/Y
 achoo/M
 achromatic
 achy/TR
 acid/SMY
@@ -14353,16 +14359,17 @@ amicable
 amicably
 amici
 amicus
 amid
 amide/MS
 amidship/S
 amidst
 amigo/MS
+amine/S
 amino
 amir/SM
 amiss
 amity/M
 ammeter/SM
 ammo/M
 ammonia/M
 ammonium
@@ -14415,16 +14422,17 @@ amputation/M
 amputee/MS
 amt
 amuck
 amulet/MS
 amuse/LGDS
 amusement/MS
 amusing/Y
 amylase/M
+amyloid
 an/CS
 anabolism/M
 anachronism/SM
 anachronistic
 anachronistically
 anaconda/SM
 anaerobe/SM
 anaerobic
@@ -14439,20 +14447,19 @@ analogize/GDS
 analogous/YP
 analogousness/M
 analogue/SM
 analogy/SM
 analysand/MS
 analyses/A
 analysis/AM
 analyst/SM
-analytic
+analytic/S
 analytical/Y
 analyticalally
-analytics
 analyzable
 analyze/ADSG
 analyzer/SM
 anapest/SM
 anapestic/MS
 anaphylactic
 anaphylaxes
 anaphylaxis
@@ -14700,32 +14707,35 @@ antiknock/M
 antilabor
 antilogarithm/SM
 antimacassar/MS
 antimalarial
 antimatter/M
 antimicrobial
 antimissile
 antimony/M
+antineutrino/SM
+antineutron/MS
 antinuclear
 antioxidant/MS
 antiparticle/SM
 antipasti
 antipasto/MS
 antipathetic
 antipathy/SM
 antipersonnel
 antiperspirant/SM
 antiphon/SM
 antiphonal/MYS
 antipodal/S
 antipodean/MS
 antipodes/M
 antipollution
 antipoverty
+antiproton/MS
 antiquarian/SM
 antiquarianism/M
 antiquary/SM
 antiquate/GDS
 antique/DSMG
 antiquity/SM
 antirrhinum/S
 antiscience
@@ -15263,17 +15273,17 @@ assignable
 assignation/MS
 assigned/U
 assignee/M
 assigner/MS
 assignment/AMS
 assignor/MS
 assimilate/DSGN
 assimilation/M
-assist/GMDS
+assist/GVMDS
 assistance/M
 assistant/SM
 assisted/U
 assize/MS
 assn
 assoc
 associate's
 associate/EDSGNV
@@ -15831,17 +15841,17 @@ baldric/SM
 baldy/S
 bale/DRSMZG
 baleen/M
 baleful/PY
 balefulness/M
 baler/M
 balk/SGMD
 balkanization
-balkanize/SDG
+balkanize/GDS
 balky/RT
 ball/SGMD
 ballad/SM
 balladeer/MS
 balladry/M
 ballast/GSMD
 ballcock/MS
 ballerina/SM
@@ -17281,16 +17291,17 @@ botanic
 botanical/Y
 botanist/SM
 botany/M
 botch/DRSZGM
 botcher/M
 both
 bother/SMDG
 botheration
+bothered/U
 bothersome
 botnet/SM
 bottle/DRSMZG
 bottleneck/MS
 bottler/M
 bottom/SMDG
 bottomless
 botulinum
@@ -17758,17 +17769,17 @@ bulkhead/MS
 bulkiness/M
 bulky/RTP
 bull/MDGS
 bulldog/SM
 bulldogged
 bulldogging
 bulldoze/ZGDRS
 bulldozer/M
-bullet/SM
+bullet/SMD
 bulletin/MDGS
 bulletproof/SDG
 bullfight/SMRZG
 bullfighter/M
 bullfighting/M
 bullfinch/MS
 bullfrog/MS
 bullhead/MDS
@@ -18666,16 +18677,17 @@ caveat/MS
 caveman/M
 cavemen
 cavern/MS
 cavernous/Y
 caviar/M
 cavil/ZGJMDRS
 caviler/M
 caving/M
+cavitation
 cavity/FSM
 cavort/DGS
 caw/SMDG
 cay/CSM
 cayenne/M
 cayuse/MS
 cc
 cease/CMGDS
@@ -19697,18 +19709,18 @@ clumsily
 clumsiness/M
 clumsy/TRP
 clung
 clunk/SMDRZG
 clunker/M
 clunky/TR
 cluster/MDSG
 clutch/GMDS
-clutter/MDSG
-cluttered/U
+clutter's
+clutter/UDSG
 clvi
 clvii
 clxi
 clxii
 clxiv
 clxix
 clxvi
 clxvii
@@ -19770,17 +19782,17 @@ coccyges
 coccyx/M
 cochineal/M
 cochlea/SM
 cochleae
 cochlear
 cock/MDGS
 cockade/SM
 cockamamie
-cockatiel/SM
+cockatiel/MS
 cockatoo/SM
 cockatrice/SM
 cockchafer/S
 cockcrow/SM
 cockerel/SM
 cockeyed
 cockfight/MGS
 cockfighting/M
@@ -19942,17 +19954,17 @@ collectivization/M
 collectivize/DSG
 collector/MS
 colleen/SM
 college/SM
 collegial
 collegiality/M
 collegian/MS
 collegiate
-collide/DSG
+collide/DRSZG
 collie/RSMZ
 collier/M
 colliery/SM
 collision/SM
 collocate/MGNDSX
 collocation/M
 colloid/SM
 colloidal
@@ -20026,21 +20038,20 @@ combed/U
 comber/M
 combination/SM
 combine's
 combine/ADSG
 combined/U
 combiner/MS
 combings/M
 combo/SM
-combust/DS
+combust/SGVD
 combustibility/M
 combustible/MS
 combustion/M
-combustive
 come/IMZGRS
 comeback/MS
 comedian/MS
 comedic
 comedienne/MS
 comedown/MS
 comedy/SM
 comeliness/M
@@ -20374,16 +20385,17 @@ condense/DRSZG
 condenser/M
 condescending/Y
 condescension/M
 condign
 condiment/MS
 condition's
 condition/AGSD
 conditional/SMY
+conditionality
 conditioned/U
 conditioner/SM
 conditioning/M
 condo/SM
 condolence/SM
 condom/SM
 condominium/MS
 condone/DSG
@@ -20710,16 +20722,17 @@ continuance/EMS
 continuation/EMS
 continue/EGDS
 continuity/ESM
 continuous/EY
 continuum/M
 contort/GD
 contortion/MS
 contortionist/SM
+contra
 contraband/M
 contrabassoon/S
 contraception/M
 contraceptive/SM
 contract/MDG
 contractible
 contractile
 contractility
@@ -21139,16 +21152,17 @@ counterpoint/MDGS
 counterpoise/MGDS
 counterproductive
 counterrevolution/SM
 counterrevolutionary/SM
 countersign/GSMD
 countersignature/MS
 countersink/GSM
 counterspy/SM
+counterstroke/SM
 countersunk
 countertenor/MS
 countervail/GSD
 counterweight/MS
 countess/MS
 countless
 countrified
 country/SM
@@ -21447,16 +21461,17 @@ crispbread/S
 crispiness/M
 crispness/M
 crispy/PRT
 crisscross/GMDS
 criteria
 criterion/M
 critic/SM
 critical/UY
+criticality
 criticism/MS
 criticize/ZGDRS
 criticizer/M
 critique/MGDS
 critter/SM
 croak/SMDG
 croaky/RT
 crochet/SMDRZG
@@ -21584,17 +21599,18 @@ crusty/TRP
 crutch/MS
 crux/MS
 cry/ZGJDRSM
 crybaby/SM
 cryogenic/S
 cryogenics/M
 cryonic/S
 cryosurgery/M
-crypt/SM
+crypt's
+crypt/S
 cryptic
 cryptically
 cryptogram/SM
 cryptographer/SM
 cryptography/M
 cryptologist/MS
 cryptosystem/S
 crystal/SM
@@ -22157,24 +22173,22 @@ decorator/MS
 decorous/IY
 decorousness/M
 decorum/M
 decoupage/DSMG
 decoy/GMDS
 decreasing/Y
 decree/MDS
 decreeing
-decremented
-decrements
+decrement/DS
 decrepit
 decrepitude/M
 decriminalization/M
 decry/GDS
-decrypt/GDS
-decryptable
+decrypt/BSGD
 decryption
 dedicate/AGDS
 dedication/SM
 dedicator/SM
 dedicatory
 deduce/GDS
 deducible
 deduct/GVD
@@ -22822,16 +22836,17 @@ difficult/Y
 difficulty/SM
 diffidence/M
 diffident/Y
 diffract/GSD
 diffraction/M
 diffuse/DSYGNVP
 diffuseness/M
 diffusion/M
+diffusivity
 dig/SM
 digerati/M
 digest/SMDGV
 digested/U
 digestibility/M
 digestible/I
 digestion/IM
 digestions
@@ -22868,16 +22883,17 @@ dilemma/MS
 dilettante/SM
 dilettantish
 dilettantism/M
 diligence/M
 diligent/Y
 dill/MS
 dilly/SM
 dillydally/DSG
+diluent
 dilute/DSGNX
 diluted/U
 dilution/M
 dim/PSRY
 dime/MS
 dimension/SM
 dimensional
 dimensionless
@@ -23018,17 +23034,17 @@ disconnected/PY
 disconnectedness/M
 disconsolate/Y
 discordance/M
 discordant/Y
 discotheque/SM
 discourage/LGDS
 discouragement/SM
 discouraging/Y
-discover/ASDGB
+discover/ABSDG
 discovered/U
 discoverer/MS
 discovery/ASM
 discreet/PRYT
 discreetness/M
 discrepancy/SM
 discrepant
 discrete/PYN
@@ -24016,16 +24032,17 @@ ebullition/M
 eccentric/SM
 eccentrically
 eccentricity/SM
 eccl
 ecclesial
 ecclesiastic/SM
 ecclesiastical/Y
 echelon/SM
+echidna
 echinoderm/SM
 echo's
 echo/ADG
 echoes/A
 echoic
 echolocation/M
 echos
 eclair/SM
@@ -24135,16 +24152,17 @@ efficiency/ISM
 efficient/IY
 effigy/SM
 efflorescence/M
 efflorescent
 effluence/M
 effluent/MS
 effluvia
 effluvium/M
+efflux
 effort/SM
 effortless/YP
 effortlessness/M
 effrontery/M
 effulgence/M
 effulgent
 effuse/DSGNVX
 effusion/M
@@ -24515,19 +24533,18 @@ enchilada/SM
 encipher/SGD
 encircle/DSGL
 encirclement/M
 encl
 enclave/MS
 enclose/GDS
 enclosed/U
 enclosure/SM
-encode/DRSZG
+encode/DRSJZG
 encoder/M
-encodings
 encomium/MS
 encompass/GDS
 encore/DSMG
 encounter/GSMD
 encourage/DSLG
 encouragement/SM
 encouraging/Y
 encroach/GLDS
@@ -24682,16 +24699,17 @@ ensure/ZGDRS
 ensurer/M
 entail/DSGL
 entailment/M
 entangle/EDSLG
 entanglement/EM
 entanglements
 entente/SM
 enter/ASGD
+enteral
 enteric
 enteritis/M
 enterprise/MGS
 enterprising/Y
 entertain/ZGDRSL
 entertainer/M
 entertaining/MY
 entertainment/MS
@@ -24715,16 +24733,17 @@ entity/SM
 entomb/DSGL
 entombment/M
 entomological
 entomologist/MS
 entomology/M
 entourage/SM
 entr'acte
 entrails/M
+entrained
 entrance/LDSMG
 entrancement/M
 entrancing/Y
 entrant/SM
 entrap/LS
 entrapment/M
 entrapped
 entrapping
@@ -25040,16 +25059,17 @@ etymology/SM
 eucalypti
 eucalyptus/MS
 euchre/DSMG
 euclidean
 eugenic/S
 eugenically
 eugenicist/MS
 eugenics/M
+eukaryotes
 eulogist/MS
 eulogistic
 eulogize/ZGDRS
 eulogizer/M
 eulogy/SM
 eunuch/M
 eunuchs
 euphemism/SM
@@ -25069,16 +25089,17 @@ euthanize/DSG
 euthenics/M
 evacuate/XDSGN
 evacuation/M
 evacuee/MS
 evade/DRSZG
 evader/M
 evaluate/AGNVDSX
 evaluation/AM
+evaluator/S
 evanescence/M
 evanescent
 evangelic
 evangelical/SMY
 evangelicalism/M
 evangelism/M
 evangelist/MS
 evangelistic
@@ -25423,17 +25444,17 @@ expressionless/Y
 expressive/PY
 expressiveness/M
 expressway/SM
 expropriate/GNXDS
 expropriation/M
 expropriator/SM
 expulsion/MS
 expunction
-expunge/GDS
+expunge/LGDS
 expungement/S
 expurgate/DSGNX
 expurgated/U
 expurgation/M
 exquisite/YP
 exquisiteness/M
 ext
 extant
@@ -25472,17 +25493,17 @@ extolled
 extolling
 extort/SGD
 extortion/MRZ
 extortionate/Y
 extortioner/M
 extortionist/MS
 extra/SM
 extracellular
-extract/MDGS
+extract/MDGVS
 extraction/SM
 extractor/MS
 extracurricular
 extradite/GNBXDS
 extradition/M
 extrajudicial
 extralegal
 extramarital
@@ -25560,16 +25581,17 @@ fabricator/SM
 fabulous/Y
 facade/SM
 face's
 face/ACSDG
 facecloth/M
 facecloths
 faceless
 facelift/SM
+facepalm/SDG
 facet/SMDG
 facetious/YP
 facetiousness/M
 facial/SMY
 facile/Y
 facilitate/GNDS
 facilitation/M
 facilitator/MS
@@ -27182,17 +27204,17 @@ fuck/SMGDRZ!
 fucker/M!
 fuckhead/SM!
 fuddle/DSMG
 fudge/DSMG
 fuehrer/MS
 fuel's
 fuel/ADGS
 fug
-fugacious/YP
+fugacious/PY
 fugal
 fuggy
 fugitive/MS
 fugue/SM
 fuhrer/SM
 fulcrum/MS
 fulfill/LDGS
 fulfilled/U
@@ -27952,29 +27974,31 @@ glue/MGDS
 glued/U
 gluey
 gluier
 gluiest
 glum/YP
 glummer
 glummest
 glumness/M
+gluon/S
 glut/MNS
 gluten/M
 glutenous
 glutinous/Y
 glutted
 glutting
 glutton/MS
 gluttonous/Y
 gluttony/M
 glycerin/M
 glycerine/M
 glycerol/M
 glycogen/M
+glycol
 glyph
 gm
 gnarl/SMDG
 gnarly/TR
 gnash/MDSG
 gnat/MS
 gnaw/DGS
 gneiss/M
@@ -29026,16 +29050,17 @@ hawk/MDRZGS
 hawker/M
 hawkish/P
 hawkishness/M
 hawser/SM
 hawthorn/MS
 hay/GSMD
 haycock/SM
 hayloft/SM
+haymaker/S
 haymaking
 haymow/SM
 hayrick/MS
 hayride/MS
 hayseed/MS
 haystack/SM
 haywire
 hazard/SMDG
@@ -29333,16 +29358,17 @@ herein
 hereinafter
 hereof
 hereon
 heresy/SM
 heretic/SM
 heretical
 hereto
 heretofore
+hereunder
 hereunto
 hereupon
 herewith
 heritable/I
 heritage/MS
 hermaphrodite/SM
 hermaphroditic
 hermetic
@@ -30105,16 +30131,17 @@ hydrogenation/M
 hydrogenous
 hydrologist/MS
 hydrology/M
 hydrolyses
 hydrolysis/M
 hydrolyze/DSG
 hydrometer/SM
 hydrometry/M
+hydrophilic
 hydrophobia/M
 hydrophobic
 hydrophone/SM
 hydroplane/GDSM
 hydroponic/S
 hydroponically
 hydroponics/M
 hydrosphere/M
@@ -30940,17 +30967,17 @@ infirm
 infirmary/SM
 infirmity/SM
 infix
 inflame/DSG
 inflammable
 inflammation/SM
 inflammatory
 inflatable/SM
-inflate/DSGNB
+inflate/ADSG
 inflation/EM
 inflationary
 inflect/SDG
 inflection/MS
 inflectional
 inflict/SDGV
 infliction/M
 inflight
@@ -30959,16 +30986,17 @@ influence/MGDS
 influenced/U
 influential/Y
 influenza/M
 info/M
 infomercial/SM
 inform/Z
 informal/Y
 informant/SM
+informatics
 information/EM
 informational
 informative/PY
 informativeness/M
 informed/U
 infotainment/M
 infra
 infrared/M
@@ -31079,16 +31107,17 @@ innuendo/SM
 innuendoes
 innumerably
 innumerate
 inoculate/AGDS
 inoculation/MS
 inoperative
 inordinate/Y
 inorganic
+inositol
 inquire/ZGDR
 inquirer/M
 inquiring/Y
 inquiry/SM
 inquisition/MS
 inquisitional
 inquisitive/YP
 inquisitiveness/M
@@ -31482,17 +31511,18 @@ inveigle/ZGDRS
 inveigler/M
 invent/ASGVD
 invention/AMS
 inventive/PY
 inventiveness/M
 inventor/MS
 inventory/DSMG
 inverse/SMY
-invert/SMDGR
+invert/SMDRZG
+inverter/M
 invest/ASDGL
 investigate/GNVDSX
 investigation/M
 investigator/SM
 investigatory
 investiture/MS
 investment/AEM
 investor/SM
@@ -31516,16 +31546,17 @@ invite/DSMG
 invited/U
 invitee/SM
 inviting/Y
 invoke/DSG
 involuntariness/M
 involuntary/P
 involution/M
 involve/LDSG
+involved/U
 involvement/SM
 inward/SY
 ioctl
 iodide/SM
 iodine/M
 iodize/DSG
 ion/USM
 ionic
@@ -32112,16 +32143,17 @@ keratitis
 kerbside
 kerchief/SM
 kerfuffle/S
 kernel/SM
 kerosene/M
 kestrel/MS
 ketch/MS
 ketchup/M
+ketone/S
 kettle/SM
 kettledrum/SM
 key/SGMD
 keybinding/S
 keyboard/ZGSMDR
 keyboarder/M
 keyboardist/SM
 keyhole/MS
@@ -33522,16 +33554,17 @@ lumbago/M
 lumbar
 lumber/MDRZGS
 lumberer/M
 lumbering/M
 lumberjack/SM
 lumberman/M
 lumbermen
 lumberyard/SM
+lumen
 luminary/SM
 luminescence/M
 luminescent
 luminosity/M
 luminous/Y
 lummox/MS
 lump/MDNSG
 lumpectomy/S
@@ -33571,16 +33604,17 @@ lustful/Y
 lustily
 lustiness/M
 lustrous/Y
 lusty/PTR
 lutanist/SM
 lute/MS
 lutenist/SM
 lutetium/M
+lux
 luxuriance/M
 luxuriant/Y
 luxuriate/DSGN
 luxuriation/M
 luxurious/PY
 luxuriousness/M
 luxury/SM
 lvi
@@ -33808,19 +33842,18 @@ malefaction/M
 malefactor/SM
 malefic
 maleficence/M
 maleficent
 maleness/M
 malevolence/M
 malevolent/Y
 malfeasance/M
-malform/S
+malform/SD
 malformation/SM
-malformed
 malfunction/MDSG
 malice/M
 malicious/PY
 maliciousness/M
 malign/DSG
 malignancy/SM
 malignant/Y
 malignity/M
@@ -34204,16 +34237,17 @@ maw/SM
 mawkish/PY
 mawkishness/M
 max/GMDS
 maxi/MS
 maxilla/M
 maxillae
 maxillary
 maxim/SM
+maxima
 maximal/Y
 maximization/M
 maximize/GDS
 maximum/SM
 may/M
 maybe/SM
 mayday/MS
 mayflower/MS
@@ -34290,17 +34324,17 @@ medal/SM
 medalist/MS
 medallion/SM
 meddle/ZGDRS
 meddler/M
 meddlesome
 media/SM
 medial/AY
 median/MS
-mediate/DSGN
+mediate/ADSGN
 mediated/U
 mediation/AM
 mediator/MS
 medic/SM
 medicaid/M
 medical/SMY
 medicament/M
 medicare/M
@@ -34827,16 +34861,17 @@ miniaturize/GDS
 minibar/S
 minibike/SM
 minibus/MS
 minicab/S
 minicam/MS
 minicomputer/SM
 minifloppies
 minim/SM
+minima
 minimal/Y
 minimalism/M
 minimalist/MS
 minimization/M
 minimize/DSG
 minimum/MS
 mining/M
 minion/M
@@ -35065,16 +35100,17 @@ mitochondria
 mitochondrial
 mitochondrion
 mitoses
 mitosis/M
 mitotic
 mitral
 mitt/MNSX
 mitten/M
+mitzvah
 mix/ZGMDRSB
 mixed/U
 mixer/M
 mixture/SM
 mizzen/MS
 mizzenmast/SM
 mkay
 mks
@@ -35593,16 +35629,17 @@ mullah/M
 mullahs
 mullein/M
 mullet/MS
 mulligan/SM
 mulligatawny/M
 mullion/SMD
 multi
 multicast
+multichannel
 multicolored
 multicultural
 multiculturalism/M
 multidimensional
 multidisciplinary
 multifaceted
 multifamily
 multifarious/PY
@@ -35612,16 +35649,17 @@ multigrain
 multilateral/Y
 multilayered
 multilevel
 multilingual
 multilingualism/M
 multimedia/M
 multimillionaire/SM
 multinational/SM
+multipart
 multiparty
 multiplayer/M
 multiple/MS
 multiplex/ZGMDRS
 multiplexer/M
 multiplicand/MS
 multiplication/M
 multiplicative
@@ -35649,16 +35687,17 @@ mumbletypeg/M
 mummer/MS
 mummery/M
 mummification/M
 mummify/GNDS
 mummy/SM
 mumps/M
 mun
 munch/GDS
+munchie/S
 munchies/M
 munchkin/SM
 mundane/SY
 mung/DSG
 municipal/SMY
 municipality/SM
 munificence/M
 munificent/Y
@@ -35732,16 +35771,17 @@ mustard/M
 muster/GMD
 mustily
 mustiness/M
 mustn't
 musty/PTR
 mutability/M
 mutably
 mutagen/MS
+mutagenic
 mutant/MS
 mutate/XGNVDS
 mutation/M
 mutational
 mute/MYTGDRSPB
 muteness/M
 mutilate/DSGNX
 mutilation/M
@@ -36273,16 +36313,17 @@ nisei/M
 nit/SMR
 nite/MS
 niter/M
 nitpick/SZGDR
 nitpicker/M
 nitpicking/M
 nitrate/DSMGN
 nitration/M
+nitric
 nitrification/M
 nitrite/SM
 nitro
 nitrocellulose/M
 nitrogen/M
 nitrogenous
 nitroglycerin/M
 nitroglycerine/M
@@ -37021,16 +37062,17 @@ octane/MS
 octave/MS
 octavo/MS
 octet/SM
 octogenarian/SM
 octopi
 octopus/MS
 ocular/MS
 oculist/SM
+oculomotor
 odalisque/SM
 odd/STRYLP
 oddball/SM
 oddity/SM
 oddment/SM
 oddness/M
 odds/M
 ode/SM
@@ -37163,16 +37205,17 @@ omnipotent
 omnipresence/M
 omnipresent
 omniscience/M
 omniscient
 omnivore/MS
 omnivorous/PY
 omnivorousness/M
 on/Y
+onboard
 once/M
 oncogene/SM
 oncologist/SM
 oncology/M
 oncoming
 one/SXMNP
 oneness/M
 onerous/PY
@@ -37314,16 +37357,17 @@ orchestra/MS
 orchestral
 orchestrate/DSXGN
 orchestration/M
 orchid/SM
 ordain/SDLG
 ordainment/M
 ordeal/SM
 order/EAMDGS
+ordered/U
 orderings
 orderliness/EM
 orderly/PSM
 ordinal/SM
 ordinance/SM
 ordinarily
 ordinariness/M
 ordinary/SMP
@@ -37714,16 +37758,17 @@ overhaul/MDSG
 overhead/MS
 overhear/SG
 overheard
 overheat/DSG
 overhung
 overindulge/GDS
 overindulgence/M
 overindulgent
+overinflated
 overjoy/GSD
 overkill/M
 overladen
 overlaid
 overlain
 overland
 overlap/SM
 overlapped
@@ -37871,16 +37916,17 @@ ownership/M
 ox/MN
 oxblood/M
 oxbow/MS
 oxcart/SM
 oxford/SM
 oxidant/MS
 oxidase
 oxidation/M
+oxidative
 oxide/MS
 oxidization/M
 oxidize/ZGDRS
 oxidizer/M
 oxtail/S
 oxyacetylene/M
 oxygen/M
 oxygenate/DSGN
@@ -38157,16 +38203,17 @@ paralysis/M
 paralytic/SM
 paralyze/DSG
 paralyzing/Y
 paramecia
 paramecium/M
 paramedic/MS
 paramedical/MS
 parameter/MS
+parameterize/D
 parametric
 paramilitary/SM
 paramount
 paramountcy
 paramour/SM
 paranoia/M
 paranoiac/MS
 paranoid/SM
@@ -38256,19 +38303,18 @@ paroxysmal
 parquet/MDSG
 parquetry/M
 parred
 parricidal
 parricide/MS
 parring
 parrot/GMDS
 parry/GDSM
-parse/DSG
+parse/DRSZG
 parsec/MS
-parser/S
 parsimonious/Y
 parsimony/M
 parsley/M
 parsnip/MS
 parson/MS
 parsonage/MS
 part's
 part/CDSG
@@ -38822,16 +38868,17 @@ perpetrate/DSGN
 perpetration/M
 perpetrator/MS
 perpetual/SMY
 perpetuate/DSGN
 perpetuation/M
 perpetuity/M
 perplex/GDS
 perplexed/Y
+perplexing/Y
 perplexity/SM
 perquisite/SM
 persecute/GNXDS
 persecution/M
 persecutor/SM
 perseverance/M
 persevere/DSG
 persiflage/M
@@ -39171,16 +39218,17 @@ pickle/MGDS
 pickpocket/SM
 pickup/MS
 picky/PTR
 picnic/MS
 picnicked
 picnicker/SM
 picnicking
 picot/SM
+pictogram/S
 pictograph/M
 pictographs
 pictorial/MYS
 picture/MGDS
 picturesque/PY
 picturesqueness/M
 piddle/MGDS
 piddly
@@ -39844,16 +39892,17 @@ popping
 poppy/SM
 poppycock/M
 populace/MS
 popular/Y
 popularity/UM
 popularization/M
 popularize/DSG
 populate/ACGDS
+populated/U
 population/CM
 populations
 populism/M
 populist/MS
 populous/P
 populousness/M
 popup/MS
 porcelain/SM
@@ -39911,22 +39960,22 @@ pose's/A
 pose/CAKEGDS
 poser/EKSM
 poseur/SM
 posh/TR
 posit/DSGV
 position/CKEMS
 positional/K
 positioned/K
-positioning/K
+positioning/AK
 positive/MYPS
 positiveness/M
 positivism
 positivist/S
-positivity/MS
+positivity/SM
 positron/MS
 poss
 posse/MS
 possess/AEVGSD
 possession/ASM
 possessive/SMYP
 possessiveness/M
 possessor/SM
@@ -40245,16 +40294,17 @@ premonition/MS
 premonitory
 prenatal/Y
 prenup/SM
 prenuptial
 preoccupation/SM
 preoccupy/DSG
 preoperative
 preordain/GDS
+preowned
 prep/MS
 prepackage/DSG
 prepacked
 prepaid
 preparation/SM
 preparatory
 prepare/GDS
 prepared/UP
@@ -40484,28 +40534,29 @@ probably
 probate/MN
 probation/ZMR
 probational
 probationary
 probationer/M
 probe/MGDSBJ
 probity/M
 problem/MS
-problematic
+problematic/U
 problematical/Y
 probosces
 proboscis/MS
 procaine/M
 procedural
 procedure/SM
 proceed/GJDS
 proceeding/M
 proceeds/M
 process's
 process/AGDS
+processable
 processed/U
 procession/GD
 processional/MS
 processor/SM
 proclamation/MS
 proclivity/SM
 procrastinate/DSGN
 procrastination/M
@@ -41253,16 +41304,17 @@ quietus/MS
 quiff/S
 quill/SM
 quilt/SMDRZG
 quilter/M
 quilting/M
 quin/S
 quince/SM
 quine/S
+quinidine
 quinine/M
 quinoa
 quinsy/M
 quint/SM
 quintessence/SM
 quintessential/Y
 quintet/SM
 quintuple/MGDS
@@ -41346,16 +41398,17 @@ racoon
 racquet/SM
 racquetball/SM
 racy/PRT
 rad/SM
 radar/SM
 radarscope/SM
 raddled
 radial/SMY
+radian/S
 radiance/M
 radiant/Y
 radiate/DSGNX
 radiation/M
 radiator/SM
 radical/SMY
 radicalism/M
 radicalization/M
@@ -42055,17 +42108,16 @@ remain/SGD
 remainder/GMDS
 remand/SGD
 remapping
 remark/B
 remarkableness/M
 remarkably
 remarked/U
 remediable
-remediate/DGS
 remedy/GDSM
 remember/DG
 remembered/U
 remembrance/MS
 reminder/M
 reminisce/GDS
 reminiscence/MS
 reminiscent/Y
@@ -42125,16 +42177,17 @@ repairman/M
 repairmen
 reparable
 reparation/MS
 reparations/M
 repartee/M
 repatriate/XDSMGN
 repatriation/M
 repeat/SMDRZGB
+repeatability
 repeatable/U
 repeatably
 repeated/Y
 repeater/M
 repeating/M
 repel/S
 repelled
 repellent/SM
@@ -42161,16 +42214,17 @@ repletion/M
 replica/SM
 replicate/DSGNX
 replication/M
 replicator/S
 reportage/M
 reported/Y
 reportorial
 reposeful
+reposition
 repository/SM
 reprehend/DGS
 reprehensibility/M
 reprehensible
 reprehensibly
 reprehension/M
 represent/GDS
 representational
@@ -42220,17 +42274,16 @@ reread/SG
 rerecord/GDS
 rerunning
 resat
 rescind/SDG
 rescission/M
 rescue/DRSMZG
 rescuer/M
 reseal/B
-resell/SG
 resemble/DSG
 resend
 resent/LSDG
 resentful/YP
 resentfulness/M
 resentment/MS
 reserpine/M
 reservation/MS
@@ -42253,16 +42306,17 @@ resigned/Y
 resilience/M
 resiliency/M
 resilient/Y
 resinous
 resist/SMDRZG
 resistance/SM
 resistant/U
 resistible
+resistivity
 resistless