Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Tue, 20 Nov 2018 07:12:30 +0200
changeset 503614 7f54ae73fcee59e545d56374080d033b3d2e162c
parent 503613 5224409d073fc69dab28b64679e442e5cd8982c9 (current diff)
parent 503598 74c27e915067b5afc43f4f64fd8fa2b0dc3bc81a (diff)
child 503615 9beb9df486d76e40011e801de1c73be2bf38983b
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
dom/base/nsDocument.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/plugins/test/testaddon/Makefile.in
dom/plugins/test/testaddon/install.rdf
dom/plugins/test/testaddon/moz.build
dom/workers/SharedWorker.cpp
dom/workers/SharedWorker.h
dom/workers/test/test_consoleSharedWorkers.html
toolkit/components/telemetry/tests/addons/dictionary/install.rdf
toolkit/components/telemetry/tests/addons/experiment/install.rdf
toolkit/components/telemetry/tests/addons/system/install.rdf
toolkit/components/telemetry/tests/addons/theme/install.rdf
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1/META-INF/manifest.mf
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1/META-INF/mozilla.rsa
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1/META-INF/mozilla.sf
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1/install.rdf
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2/META-INF/manifest.mf
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2/META-INF/mozilla.rsa
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2/META-INF/mozilla.sf
toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2/install.rdf
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/bootstrap.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/frame-script.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/install.rdf
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/bootstrap.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/frame-script.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/install.rdf
toolkit/mozapps/extensions/test/browser/browser_bug596336.js
toolkit/mozapps/extensions/test/browser/browser_update.js
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_badid.xpi
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_broken.xpi
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_good.xpi
toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_dictionary.json
toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
toolkit/mozapps/extensions/test/xpcshell/test_corruptfile.js
toolkit/mozapps/extensions/test/xpcshell/test_delay_update.js
toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
toolkit/mozapps/extensions/test/xpcshell/test_sourceURI.js
toolkit/mozapps/extensions/test/xpcshell/test_switch_os.js
toolkit/mozapps/extensions/test/xpinstall/amosigned-restart-required.xpi
toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi
toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi
toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi
toolkit/mozapps/extensions/test/xpinstall/signed.xpi
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -102,16 +102,17 @@ media/libogg/.*
 media/libopus/.*
 media/libpng/.*
 media/libsoundtouch/.*
 media/libspeex_resampler/.*
 media/libtheora/.*
 media/libtremor/.*
 media/libvorbis/.*
 media/libvpx/.*
+media/libwebp/.*
 media/libyuv/.*
 media/mtransport/third_party/.*
 media/openmax_dl/.*
 media/webrtc/signaling/src/sdp/sipcc/.*
 media/webrtc/trunk/.*
 mfbt/decimal/.*
 mfbt/double-conversion/double-conversion/.*
 mfbt/lz4.*
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -422,19 +422,18 @@ nsAccessibilityService::CreatePluginAcce
                                                Accessible* aContext)
 {
   // nsPluginFrame means a plugin, so we need to use the accessibility support
   // of the plugin.
   if (aFrame->GetRect().IsEmpty())
     return nullptr;
 
 #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
-  RefPtr<nsNPAPIPluginInstance> pluginInstance;
-  if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) &&
-      pluginInstance) {
+  RefPtr<nsNPAPIPluginInstance> pluginInstance = aFrame->GetPluginInstance();
+  if (pluginInstance) {
 #ifdef XP_WIN
     if (!sPendingPlugins->Contains(aContent) &&
         (Preferences::GetBool("accessibility.delay_plugins") ||
          Compatibility::IsJAWS() || Compatibility::IsWE())) {
       RefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent);
       nsCOMPtr<nsITimer> timer;
       NS_NewTimerWithCallback(getter_AddRefs(timer),
                               cb, Preferences::GetUint("accessibility.delay_plugin_time"),
--- a/browser/base/content/test/sanitize/browser_cookiePermission.js
+++ b/browser/base/content/test/sanitize/browser_cookiePermission.js
@@ -1,12 +1,28 @@
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Sanitizer} = ChromeUtils.import("resource:///modules/Sanitizer.jsm", {});
 const {SiteDataTestUtils} = ChromeUtils.import("resource://testing-common/SiteDataTestUtils.jsm", {});
 
+function checkDataForAboutURL() {
+  return new Promise(resolve => {
+    let data = true;
+    let uri = Services.io.newURI("about:newtab");
+    let principal =
+      Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+    let request = indexedDB.openForPrincipal(principal, "TestDatabase", 1);
+    request.onupgradeneeded = function(e) {
+      data = false;
+    };
+    request.onsuccess = function(e) {
+      resolve(data);
+    };
+  });
+}
+
 function createIndexedDB(host, originAttributes) {
   return SiteDataTestUtils.addToIndexedDB("https://" + host, "foo", "bar",
                                           originAttributes);
 }
 
 function checkIndexedDB(host, originAttributes) {
   return new Promise(resolve => {
     let data = true;
@@ -228,8 +244,78 @@ tests.forEach(methods => {
           cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
           expectedForOrg: true,
           expectedForCom: false,
           fullHost: true,
         });
     });
   });
 });
+
+add_task(async function deleteStorageInAboutURL() {
+  info("Test about:newtab");
+
+  // Let's clean up all the data.
+  await new Promise(resolve => {
+    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
+  });
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["network.cookie.lifetimePolicy", Ci.nsICookieService.ACCEPT_SESSION],
+  ]});
+
+  // Let's create a tab with some data.
+  await SiteDataTestUtils.addToIndexedDB("about:newtab", "foo", "bar", {});
+
+  ok(await checkDataForAboutURL(), "We have data for about:newtab");
+
+  // Cleaning up.
+  await Sanitizer.runSanitizeOnShutdown();
+
+  ok(await checkDataForAboutURL(), "about:newtab data is not deleted.");
+
+  // Clean up.
+  await Sanitizer.sanitize([ "cookies", "offlineApps" ]);
+
+  let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("about:newtab");
+  await new Promise(aResolve => {
+    let req = Services.qms.clearStoragesForPrincipal(principal, null, false);
+    req.callback = () => { aResolve(); };
+  });
+});
+
+add_task(async function deleteStorageOnlyCustomPermissionInAboutURL() {
+  info("Test about:newtab + permissions");
+
+  // Let's clean up all the data.
+  await new Promise(resolve => {
+    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
+  });
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["network.cookie.lifetimePolicy", Ci.nsICookieService.ACCEPT_NORMALLY],
+  ]});
+
+  // Custom permission without considering OriginAttributes
+  let uri = Services.io.newURI("about:newtab");
+  Services.perms.add(uri, "cookie", Ci.nsICookiePermission.ACCESS_SESSION);
+
+  // Let's create a tab with some data.
+  await SiteDataTestUtils.addToIndexedDB("about:newtab", "foo", "bar", {});
+
+  ok(await checkDataForAboutURL(), "We have data for about:newtab");
+
+  // Cleaning up.
+  await Sanitizer.runSanitizeOnShutdown();
+
+  ok(await checkDataForAboutURL(), "about:newtab data is not deleted.");
+
+  // Clean up.
+  await Sanitizer.sanitize([ "cookies", "offlineApps" ]);
+
+  let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("about:newtab");
+  await new Promise(aResolve => {
+    let req = Services.qms.clearStoragesForPrincipal(principal, null, false);
+    req.callback = () => { aResolve(); };
+  });
+
+  Services.perms.remove(uri, "cookie");
+});
--- a/browser/base/content/test/webextensions/browser_extension_sideloading.js
+++ b/browser/base/content/test/webextensions/browser_extension_sideloading.js
@@ -20,42 +20,22 @@ async function createWebExtension(detail
     options.manifest.icons = {"64": details.iconURL};
   }
 
   let xpi = AddonTestUtils.createTempWebExtensionFile(options);
 
   await AddonTestUtils.manuallyInstall(xpi);
 }
 
-async function createXULExtension(details) {
-  let xpi = AddonTestUtils.createTempXPIFile({
-    "install.rdf": {
-      id: details.id,
-      name: details.name,
-      version: "0.1",
-      bootstrap: true,
-      targetApplications: [{
-        id: "toolkit@mozilla.org",
-        minVersion: "0",
-        maxVersion: "*",
-      }],
-    },
-  });
-
-  await AddonTestUtils.manuallyInstall(xpi);
-}
-
 function promiseEvent(eventEmitter, event) {
   return new Promise(resolve => {
     eventEmitter.once(event, resolve);
   });
 }
 
-let cleanup;
-
 add_task(async function() {
   const DEFAULT_ICON_URL = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
 
   await SpecialPowers.pushPrefEnv({
     set: [
       ["xpinstall.signatures.required", false],
       ["extensions.autoDisableScopes", 15],
       ["extensions.ui.ignoreUnsigned", true],
@@ -67,35 +47,29 @@ add_task(async function() {
     id: ID1,
     name: "Test 1",
     userDisabled: true,
     permissions: ["history", "https://*/*"],
     iconURL: "foo-icon.png",
   });
 
   const ID2 = "addon2@tests.mozilla.org";
-  await createXULExtension({
+  await createWebExtension({
     id: ID2,
     name: "Test 2",
+    permissions: ["<all_urls>"],
   });
 
   const ID3 = "addon3@tests.mozilla.org";
   await createWebExtension({
     id: ID3,
     name: "Test 3",
     permissions: ["<all_urls>"],
   });
 
-  const ID4 = "addon4@tests.mozilla.org";
-  await createWebExtension({
-    id: ID4,
-    name: "Test 4",
-    permissions: ["<all_urls>"],
-  });
-
   testCleanup = async function() {
     // clear out ExtensionsUI state about sideloaded extensions so
     // subsequent tests don't get confused.
     ExtensionsUI.sideloaded.clear();
     ExtensionsUI.emit("change");
   };
 
   // Navigate away from the starting page to force about:addons to load
@@ -124,17 +98,17 @@ add_task(async function() {
   // Check for the addons badge on the hamburger menu
   let menuButton = document.getElementById("PanelUI-menu-button");
   is(menuButton.getAttribute("badge-status"), "addon-alert", "Should have addon alert badge");
 
   // Find the menu entries for sideloaded extensions
   await gCUITestUtils.openMainMenu();
 
   let addons = PanelUI.addonNotificationContainer;
-  is(addons.children.length, 4, "Have 4 menu entries for sideloaded extensions");
+  is(addons.children.length, 3, "Have 3 menu entries for sideloaded extensions");
 
   // Click the first sideloaded extension
   let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
   addons.children[0].click();
 
   // The click should hide the main menu. This is currently synchronous.
   ok(PanelUI.panel.state != "open", "Main menu is closed or closing.");
 
@@ -151,73 +125,44 @@ add_task(async function() {
   // Check the contents of the notification, then choose "Cancel"
   checkNotification(panel, /\/foo-icon\.png$/, [
     ["webextPerms.hostDescription.allUrls"],
     ["webextPerms.description.history"],
   ]);
 
   panel.secondaryButton.click();
 
-  let [addon1, addon2, addon3, addon4] = await AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]);
+  let [addon1, addon2, addon3] = await AddonManager.getAddonsByIDs([ID1, ID2, ID3]);
   ok(addon1.seen, "Addon should be marked as seen");
   is(addon1.userDisabled, true, "Addon 1 should still be disabled");
   is(addon2.userDisabled, true, "Addon 2 should still be disabled");
   is(addon3.userDisabled, true, "Addon 3 should still be disabled");
-  is(addon4.userDisabled, true, "Addon 4 should still be disabled");
 
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
-  // Should still have 3 entries in the hamburger menu
-  await gCUITestUtils.openMainMenu();
-
-  addons = PanelUI.addonNotificationContainer;
-  is(addons.children.length, 3, "Have 3 menu entries for sideloaded extensions");
-
-  // Click the second sideloaded extension and wait for the notification
-  popupPromise = promisePopupNotificationShown("addon-webext-permissions");
-  addons.children[0].click();
-  panel = await popupPromise;
-
-  // Again we should be at the extentions list in about:addons
-  is(gBrowser.currentURI.spec, "about:addons", "Foreground tab is at about:addons");
-
-  win = gBrowser.selectedBrowser.contentWindow;
-  ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
-  is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
-
-  // Check the notification contents.
-  checkNotification(panel, DEFAULT_ICON_URL, []);
-
-  // This time accept the install.
-  panel.button.click();
-  await promiseEvent(ExtensionsUI, "sideload-response");
-
-  [addon1, addon2, addon3, addon4] = await AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]);
-  is(addon1.userDisabled, true, "Addon 1 should still be disabled");
-  is(addon2.userDisabled, false, "Addon 2 should now be enabled");
-  is(addon3.userDisabled, true, "Addon 3 should still be disabled");
-  is(addon4.userDisabled, true, "Addon 4 should still be disabled");
-
   // Should still have 2 entries in the hamburger menu
   await gCUITestUtils.openMainMenu();
 
   addons = PanelUI.addonNotificationContainer;
   is(addons.children.length, 2, "Have 2 menu entries for sideloaded extensions");
 
   // Close the hamburger menu and go directly to the addons manager
   await gCUITestUtils.hideMainMenu();
 
   win = await BrowserOpenAddonsMgr(VIEW);
 
   let list = win.document.getElementById("addon-list");
+  if (win.gViewController.isLoading) {
+    await new Promise(resolve => win.document.addEventListener("ViewChanged", resolve, {once: true}));
+  }
 
   // Make sure XBL bindings are applied
   list.clientHeight;
 
-  let item = list.itemChildren.find(_item => _item.value == ID3);
+  let item = Array.from(list.children).find(_item => _item.value == ID2);
   ok(item, "Found entry for sideloaded extension in about:addons");
   item.scrollIntoView({behavior: "instant"});
 
   ok(BrowserTestUtils.is_visible(item._enableBtn), "Enable button is visible for sideloaded extension");
   ok(BrowserTestUtils.is_hidden(item._disableBtn), "Disable button is not visible for sideloaded extension");
 
   // When clicking enable we should see the permissions notification
   popupPromise = promisePopupNotificationShown("addon-webext-permissions");
@@ -225,61 +170,61 @@ add_task(async function() {
                                            gBrowser.selectedBrowser);
   panel = await popupPromise;
   checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
 
   // Accept the permissions
   panel.button.click();
   await promiseEvent(ExtensionsUI, "change");
 
-  addon3 = await AddonManager.getAddonByID(ID3);
-  is(addon3.userDisabled, false, "Addon 3 should be enabled");
+  addon2 = await AddonManager.getAddonByID(ID2);
+  is(addon2.userDisabled, false, "Addon 2 should be enabled");
 
   // Should still have 1 entry in the hamburger menu
   await gCUITestUtils.openMainMenu();
 
   addons = PanelUI.addonNotificationContainer;
   is(addons.children.length, 1, "Have 1 menu entry for sideloaded extensions");
 
   // Close the hamburger menu and go to the detail page for this addon
   await gCUITestUtils.hideMainMenu();
 
-  win = await BrowserOpenAddonsMgr(`addons://detail/${encodeURIComponent(ID4)}`);
+  win = await BrowserOpenAddonsMgr(`addons://detail/${encodeURIComponent(ID3)}`);
   let button = win.document.getElementById("detail-enable-btn");
 
   // When clicking enable we should see the permissions notification
   popupPromise = promisePopupNotificationShown("addon-webext-permissions");
   BrowserTestUtils.synthesizeMouseAtCenter(button, {},
                                            gBrowser.selectedBrowser);
   panel = await popupPromise;
   checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
 
   // Accept the permissions
   panel.button.click();
   await promiseEvent(ExtensionsUI, "change");
 
-  addon4 = await AddonManager.getAddonByID(ID4);
-  is(addon4.userDisabled, false, "Addon 4 should be enabled");
+  addon3 = await AddonManager.getAddonByID(ID3);
+  is(addon3.userDisabled, false, "Addon 3 should be enabled");
 
-  // We should have recorded 1 cancelled followed by 3 accepted sideloads.
-  expectTelemetry(["sideloadRejected", "sideloadAccepted", "sideloadAccepted", "sideloadAccepted"]);
+  // We should have recorded 1 cancelled followed by 2 accepted sideloads.
+  expectTelemetry(["sideloadRejected", "sideloadAccepted", "sideloadAccepted"]);
 
   isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge");
 
   await new Promise(resolve => setTimeout(resolve, 100));
 
-  for (let addon of [addon1, addon2, addon3, addon4]) {
+  for (let addon of [addon1, addon2, addon3]) {
     await addon.uninstall();
   }
 
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
   // Assert that the expected AddonManager telemetry are being recorded.
   const expectedExtra = {source: "app-profile", method: "sideload"};
-  const noPermissionsExtra = {...expectedExtra, num_perms: "0", num_origins: "0"};
+
   const baseEvent = {object: "extension", extra: expectedExtra};
   const createBaseEventAddon = (n) => ({...baseEvent, value: `addon${n}@tests.mozilla.org`});
   const getEventsForAddonId = (events, addonId) => events.filter(ev => ev.value === addonId);
 
   const amEvents = AddonTestUtils.getAMTelemetryEvents();
 
   // Test telemetry events for addon1 (1 permission and 1 origin).
   info("Test telemetry events collected for addon1");
@@ -298,51 +243,28 @@ add_task(async function() {
   for (let event of collectedEventsAddon1) {
     Assert.deepEqual(event, expectedEventsAddon1[i++],
                      "Got the expected telemetry event");
   }
 
   is(collectedEventsAddon1.length, expectedEventsAddon1.length,
      "Got the expected number of telemetry events for addon1");
 
-  // Test telemetry events for addon2 (no permissions).
-  info("Test telemetry events collected for addon2");
-
   const baseEventAddon2 = createBaseEventAddon(2);
   const collectedEventsAddon2 = getEventsForAddonId(amEvents, baseEventAddon2.value);
   const expectedEventsAddon2 = [
-    {...baseEventAddon2, method: "sideload_prompt", extra: {...noPermissionsExtra}},
+    {
+      ...baseEventAddon2, method: "sideload_prompt",
+      extra: {...expectedExtra, num_perms: "0", num_origins: "1"},
+    },
     {...baseEventAddon2, method: "enable"},
     {...baseEventAddon2, method: "uninstall"},
   ];
 
   i = 0;
   for (let event of collectedEventsAddon2) {
     Assert.deepEqual(event, expectedEventsAddon2[i++],
                      "Got the expected telemetry event");
   }
 
   is(collectedEventsAddon2.length, expectedEventsAddon2.length,
      "Got the expected number of telemetry events for addon2");
-
-  // Test telemetry events for addon3 (no permissions and 1 origin).
-  info("Test telemetry events collected for addon2");
-
-  const baseEventAddon3 = createBaseEventAddon(3);
-  const collectedEventsAddon3 = getEventsForAddonId(amEvents, baseEventAddon3.value);
-  const expectedEventsAddon3 = [
-    {
-      ...baseEventAddon3, method: "sideload_prompt",
-      extra: {...expectedExtra, num_perms: "0", num_origins: "1"},
-    },
-    {...baseEventAddon3, method: "enable"},
-    {...baseEventAddon3, method: "uninstall"},
-  ];
-
-  i = 0;
-  for (let event of collectedEventsAddon3) {
-    Assert.deepEqual(event, expectedEventsAddon3[i++],
-                     "Got the expected telemetry event");
-  }
-
-  is(collectedEventsAddon3.length, expectedEventsAddon3.length,
-     "Got the expected number of telemetry events for addon3");
 });
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -501,17 +501,18 @@ function openLinkIn(url, where, params) 
          (doGetProtocolFlags(uriObj) & URI_INHERITS_SECURITY_CONTEXT))) {
       // Unless we know for sure we're not inheriting principals,
       // force the about:blank viewer to have the right principal:
       targetBrowser.createAboutBlankContentViewer(aPrincipal);
     }
 
     // When navigating a recording tab, use a new content process in order to
     // start a new recording.
-    if (targetBrowser.hasAttribute("recordExecution")) {
+    if (targetBrowser.hasAttribute("recordExecution") &&
+        targetBrowser.currentURI.spec != "about:blank") {
       w.gBrowser.updateBrowserRemoteness(targetBrowser, true,
                                          { recordExecution: "*", newFrameloader: true });
     }
 
     targetBrowser.loadURI(url, {
       triggeringPrincipal: aTriggeringPrincipal,
       flags,
       referrerURI: aNoReferrer ? null : aReferrerURI,
index 3113d1fa5da0482256cef2fd3edf78ad2f6e7bc2..cc4da1fa837eb7ee1ed93bce42ebaca7fb46317d
GIT binary patch
literal 793
zc$^FHW@h1H0D(n*;lBEub%Ec2Y!K#UkYUJ8%*#wmEiTc^D$dUf4dG;9ejj)~S~BQ-
zbZG@Q10%~<Mg|5J5uoB~E(HZ8nCkel)S}|d{5&Nq1tT3UkW5};ZYq$c6p){jS)8Gy
z0}@L~Elw`VEGU5}M3F-1S2ENy&@(bHG&3+VvQUB;mXeta(v(<~nOY1~0<sz?T95-$
zUXY^)lvV-?)j|{}78K-UCMSY4ASq5yP0r4TbAbYxDG=Qb$cF1BrlbJ1>E-5EW#;50
z>g5-uD}goCg3RZt<qCiYo^qy-Z;OptXe5vg!fe361G*(KEe#xMN&gRE3$<X^5CzX*
ze+vs!OI;(bkf2C~#LWEEs=T7|<jUfLlI+}+&80b68`G0AUTu5!d4Jl+J!ORzj-LLm
zQGP+;&XK_ZA>O_&i$i_97P>omoLYA5@_M(6Yr+B}kQ}A~bQt@>S9h6!Y$k-mfZhZ<
zEE~JS5`iW#GRZOHN*NLiFtDT%M53h=R!BNQGZfiK%<w`s(iW%%7J96Z(8FUErWcXT
dx&|=|>|s`jhcV1zWdo^Y2Ex}sS^{JU0|2mL#3=v(
--- 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.1.52
+Current extension version is: 2.1.70
 
-Taken from upstream commit: 4724ebbc
+Taken from upstream commit: 6ebdbb24
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.1.52';
-var pdfjsBuild = '4724ebbc';
+var pdfjsVersion = '2.1.70';
+var pdfjsBuild = '6ebdbb24';
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 var pdfjsDisplayAPI = __w_pdfjs_require__(7);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(19);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(20);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(8);
 var pdfjsDisplaySVG = __w_pdfjs_require__(21);
 let pdfjsDisplayWorkerOptions = __w_pdfjs_require__(13);
 let pdfjsDisplayAPICompatibility = __w_pdfjs_require__(10);
@@ -4080,53 +4080,53 @@ var _webgl = __w_pdfjs_require__(18);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 const DEFAULT_RANGE_CHUNK_SIZE = 65536;
 let isWorkerDisabled = false;
 let fallbackWorkerSrc;
 let fakeWorkerFilesLoader = null;
 ;
-var createPDFNetworkStream;
+let createPDFNetworkStream;
 function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) {
   createPDFNetworkStream = pdfNetworkStreamFactory;
 }
 function getDocument(src) {
-  var task = new PDFDocumentLoadingTask();
-  var source;
+  const task = new PDFDocumentLoadingTask();
+  let source;
   if (typeof src === 'string') {
     source = { url: src };
   } else if ((0, _util.isArrayBuffer)(src)) {
     source = { data: src };
   } else if (src instanceof PDFDataRangeTransport) {
     source = { range: src };
   } else {
     if (typeof src !== 'object') {
       throw new Error('Invalid parameter in getDocument, ' + 'need either Uint8Array, string or a parameter object');
     }
     if (!src.url && !src.data && !src.range) {
       throw new Error('Invalid parameter object: need either .data, .range or .url');
     }
     source = src;
   }
-  let params = Object.create(null);
-  var rangeTransport = null;
-  let worker = null;
-  for (var key in source) {
+  const params = Object.create(null);
+  let rangeTransport = null,
+      worker = null;
+  for (const key in source) {
     if (key === 'url' && typeof window !== 'undefined') {
       params[key] = new _util.URL(source[key], window.location).href;
       continue;
     } else if (key === 'range') {
       rangeTransport = source[key];
       continue;
     } else if (key === 'worker') {
       worker = source[key];
       continue;
     } else if (key === 'data' && !(source[key] instanceof Uint8Array)) {
-      var pdfBytes = source[key];
+      const pdfBytes = source[key];
       if (typeof pdfBytes === 'string') {
         params[key] = (0, _util.stringToBytes)(pdfBytes);
       } else if (typeof pdfBytes === 'object' && pdfBytes !== null && !isNaN(pdfBytes.length)) {
         params[key] = new Uint8Array(pdfBytes);
       } else if ((0, _util.isArrayBuffer)(pdfBytes)) {
         params[key] = new Uint8Array(pdfBytes);
       } else {
         throw new Error('Invalid PDF binary data: either typed array, ' + 'string or array-like object is expected in the ' + 'data property.');
@@ -4163,28 +4163,23 @@ function getDocument(src) {
   }
   if (typeof params.disableCreateObjectURL !== 'boolean') {
     params.disableCreateObjectURL = _api_compatibility.apiCompatibilityParams.disableCreateObjectURL || false;
   }
   (0, _util.setVerbosityLevel)(params.verbosity);
   if (!worker) {
     const workerParams = {
       postMessageTransfers: params.postMessageTransfers,
-      verbosity: params.verbosity
+      verbosity: params.verbosity,
+      port: _worker_options.GlobalWorkerOptions.workerPort
     };
-    let workerPort = _worker_options.GlobalWorkerOptions.workerPort;
-    if (workerPort) {
-      workerParams.port = workerPort;
-      worker = PDFWorker.fromPort(workerParams);
-    } else {
-      worker = new PDFWorker(workerParams);
-    }
+    worker = workerParams.port ? PDFWorker.fromPort(workerParams) : new PDFWorker(workerParams);
     task._worker = worker;
   }
-  var docId = task.docId;
+  const docId = task.docId;
   worker.promise.then(function () {
     if (task.destroyed) {
       throw new Error('Loading aborted');
     }
     return _fetchDocument(worker, params, rangeTransport, docId).then(function (workerId) {
       if (task.destroyed) {
         throw new Error('Loading aborted');
       }
@@ -4202,36 +4197,36 @@ function getDocument(src) {
           length: params.length,
           httpHeaders: params.httpHeaders,
           withCredentials: params.withCredentials,
           rangeChunkSize: params.rangeChunkSize,
           disableRange: params.disableRange,
           disableStream: params.disableStream
         });
       }
-      var messageHandler = new _message_handler.MessageHandler(docId, workerId, worker.port);
+      const messageHandler = new _message_handler.MessageHandler(docId, workerId, worker.port);
       messageHandler.postMessageTransfers = worker.postMessageTransfers;
-      var transport = new WorkerTransport(messageHandler, task, networkStream, params);
+      const transport = new WorkerTransport(messageHandler, task, networkStream, params);
       task._transport = transport;
       messageHandler.send('Ready', null);
     });
   }).catch(task._capability.reject);
   return task;
 }
 function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
   if (worker.destroyed) {
     return Promise.reject(new Error('Worker was destroyed'));
   }
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.1.52',
+    apiVersion: '2.1.70',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -4245,47 +4240,48 @@ function _fetchDocument(worker, source, 
     isEvalSupported: source.isEvalSupported
   }).then(function (workerId) {
     if (worker.destroyed) {
       throw new Error('Worker was destroyed');
     }
     return workerId;
   });
 }
-var PDFDocumentLoadingTask = function PDFDocumentLoadingTaskClosure() {
-  var nextDocumentId = 0;
-  function PDFDocumentLoadingTask() {
-    this._capability = (0, _util.createPromiseCapability)();
-    this._transport = null;
-    this._worker = null;
-    this.docId = 'd' + nextDocumentId++;
-    this.destroyed = false;
-    this.onPassword = null;
-    this.onProgress = null;
-    this.onUnsupportedFeature = null;
-  }
-  PDFDocumentLoadingTask.prototype = {
+const PDFDocumentLoadingTask = function PDFDocumentLoadingTaskClosure() {
+  let nextDocumentId = 0;
+  class PDFDocumentLoadingTask {
+    constructor() {
+      this._capability = (0, _util.createPromiseCapability)();
+      this._transport = null;
+      this._worker = null;
+      this.docId = 'd' + nextDocumentId++;
+      this.destroyed = false;
+      this.onPassword = null;
+      this.onProgress = null;
+      this.onUnsupportedFeature = null;
+    }
     get promise() {
       return this._capability.promise;
-    },
+    }
     destroy() {
       this.destroyed = true;
-      var transportDestroyed = !this._transport ? Promise.resolve() : this._transport.destroy();
+      const transportDestroyed = !this._transport ? Promise.resolve() : this._transport.destroy();
       return transportDestroyed.then(() => {
         this._transport = null;
         if (this._worker) {
           this._worker.destroy();
           this._worker = null;
         }
       });
-    },
-    then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) {
+    }
+    then(onFulfilled, onRejected) {
+      (0, _util.deprecated)('PDFDocumentLoadingTask.then method, ' + 'use the `promise` getter instead.');
       return this.promise.then.apply(this.promise, arguments);
     }
-  };
+  }
   return PDFDocumentLoadingTask;
 }();
 class PDFDataRangeTransport {
   constructor(length, initialData) {
     this.length = length;
     this.initialData = initialData;
     this._rangeListeners = [];
     this._progressListeners = [];
@@ -4387,296 +4383,307 @@ class PDFDocumentProxy {
   }
   destroy() {
     return this.loadingTask.destroy();
   }
   get loadingParams() {
     return this._transport.loadingParams;
   }
 }
-var PDFPageProxy = function PDFPageProxyClosure() {
-  function PDFPageProxy(pageIndex, pageInfo, transport, pdfBug = false) {
+class PDFPageProxy {
+  constructor(pageIndex, pageInfo, transport, pdfBug = false) {
     this.pageIndex = pageIndex;
     this._pageInfo = pageInfo;
-    this.transport = transport;
+    this._transport = transport;
     this._stats = pdfBug ? new _dom_utils.StatTimer() : _dom_utils.DummyStatTimer;
     this._pdfBug = pdfBug;
     this.commonObjs = transport.commonObjs;
     this.objs = new PDFObjects();
     this.cleanupAfterRender = false;
     this.pendingCleanup = false;
     this.intentStates = Object.create(null);
     this.destroyed = false;
   }
-  PDFPageProxy.prototype = {
-    get pageNumber() {
-      return this.pageIndex + 1;
-    },
-    get rotate() {
-      return this._pageInfo.rotate;
-    },
-    get ref() {
-      return this._pageInfo.ref;
-    },
-    get userUnit() {
-      return this._pageInfo.userUnit;
-    },
-    get view() {
-      return this._pageInfo.view;
-    },
-    getViewport(scale, rotate = this.rotate, dontFlip = false) {
-      return new _dom_utils.PageViewport({
-        viewBox: this.view,
-        scale,
-        rotation: rotate,
-        dontFlip
+  get pageNumber() {
+    return this.pageIndex + 1;
+  }
+  get rotate() {
+    return this._pageInfo.rotate;
+  }
+  get ref() {
+    return this._pageInfo.ref;
+  }
+  get userUnit() {
+    return this._pageInfo.userUnit;
+  }
+  get view() {
+    return this._pageInfo.view;
+  }
+  getViewport(scale, rotate = this.rotate, dontFlip = false) {
+    return new _dom_utils.PageViewport({
+      viewBox: this.view,
+      scale,
+      rotation: rotate,
+      dontFlip
+    });
+  }
+  getAnnotations({
+    intent = null
+  } = {}) {
+    if (!this.annotationsPromise || this.annotationsIntent !== intent) {
+      this.annotationsPromise = this._transport.getAnnotations(this.pageIndex, intent);
+      this.annotationsIntent = intent;
+    }
+    return this.annotationsPromise;
+  }
+  render({ canvasContext, viewport, intent = 'display', enableWebGL = false, renderInteractiveForms = false, transform = null, imageLayer = null, canvasFactory = null, background = null }) {
+    const stats = this._stats;
+    stats.time('Overall');
+    this.pendingCleanup = false;
+    const renderingIntent = intent === 'print' ? 'print' : 'display';
+    const canvasFactoryInstance = canvasFactory || new _dom_utils.DOMCanvasFactory();
+    const webGLContext = new _webgl.WebGLContext({ enable: enableWebGL });
+    if (!this.intentStates[renderingIntent]) {
+      this.intentStates[renderingIntent] = Object.create(null);
+    }
+    const intentState = this.intentStates[renderingIntent];
+    if (!intentState.displayReadyCapability) {
+      intentState.receivingOperatorList = true;
+      intentState.displayReadyCapability = (0, _util.createPromiseCapability)();
+      intentState.operatorList = {
+        fnArray: [],
+        argsArray: [],
+        lastChunk: false
+      };
+      stats.time('Page Request');
+      this._transport.messageHandler.send('RenderPageRequest', {
+        pageIndex: this.pageNumber - 1,
+        intent: renderingIntent,
+        renderInteractiveForms: renderInteractiveForms === true
       });
-    },
-    getAnnotations: function PDFPageProxy_getAnnotations(params) {
-      var intent = params && params.intent || null;
-      if (!this.annotationsPromise || this.annotationsIntent !== intent) {
-        this.annotationsPromise = this.transport.getAnnotations(this.pageIndex, intent);
-        this.annotationsIntent = intent;
-      }
-      return this.annotationsPromise;
-    },
-    render: function PDFPageProxy_render(params) {
-      let stats = this._stats;
-      stats.time('Overall');
-      this.pendingCleanup = false;
-      var renderingIntent = params.intent === 'print' ? 'print' : 'display';
-      var canvasFactory = params.canvasFactory || new _dom_utils.DOMCanvasFactory();
-      let webGLContext = new _webgl.WebGLContext({ enable: params.enableWebGL });
-      if (!this.intentStates[renderingIntent]) {
-        this.intentStates[renderingIntent] = Object.create(null);
-      }
-      var intentState = this.intentStates[renderingIntent];
-      if (!intentState.displayReadyCapability) {
-        intentState.receivingOperatorList = true;
-        intentState.displayReadyCapability = (0, _util.createPromiseCapability)();
-        intentState.operatorList = {
-          fnArray: [],
-          argsArray: [],
-          lastChunk: false
-        };
-        stats.time('Page Request');
-        this.transport.messageHandler.send('RenderPageRequest', {
-          pageIndex: this.pageNumber - 1,
-          intent: renderingIntent,
-          renderInteractiveForms: params.renderInteractiveForms === true
-        });
-      }
-      var complete = error => {
-        var i = intentState.renderTasks.indexOf(internalRenderTask);
+    }
+    const complete = error => {
+      const i = intentState.renderTasks.indexOf(internalRenderTask);
+      if (i >= 0) {
+        intentState.renderTasks.splice(i, 1);
+      }
+      if (this.cleanupAfterRender) {
+        this.pendingCleanup = true;
+      }
+      this._tryCleanup();
+      if (error) {
+        internalRenderTask.capability.reject(error);
+      } else {
+        internalRenderTask.capability.resolve();
+      }
+      stats.timeEnd('Rendering');
+      stats.timeEnd('Overall');
+    };
+    const internalRenderTask = new InternalRenderTask({
+      callback: complete,
+      params: {
+        canvasContext,
+        viewport,
+        transform,
+        imageLayer,
+        background
+      },
+      objs: this.objs,
+      commonObjs: this.commonObjs,
+      operatorList: intentState.operatorList,
+      pageNumber: this.pageNumber,
+      canvasFactory: canvasFactoryInstance,
+      webGLContext,
+      useRequestAnimationFrame: renderingIntent !== 'print',
+      pdfBug: this._pdfBug
+    });
+    if (!intentState.renderTasks) {
+      intentState.renderTasks = [];
+    }
+    intentState.renderTasks.push(internalRenderTask);
+    const renderTask = internalRenderTask.task;
+    intentState.displayReadyCapability.promise.then(transparency => {
+      if (this.pendingCleanup) {
+        complete();
+        return;
+      }
+      stats.time('Rendering');
+      internalRenderTask.initializeGraphics(transparency);
+      internalRenderTask.operatorListChanged();
+    }).catch(complete);
+    return renderTask;
+  }
+  getOperatorList() {
+    function operatorListChanged() {
+      if (intentState.operatorList.lastChunk) {
+        intentState.opListReadCapability.resolve(intentState.operatorList);
+        const i = intentState.renderTasks.indexOf(opListTask);
         if (i >= 0) {
           intentState.renderTasks.splice(i, 1);
         }
-        if (this.cleanupAfterRender) {
-          this.pendingCleanup = true;
-        }
-        this._tryCleanup();
-        if (error) {
-          internalRenderTask.capability.reject(error);
-        } else {
-          internalRenderTask.capability.resolve();
-        }
-        stats.timeEnd('Rendering');
-        stats.timeEnd('Overall');
+      }
+    }
+    const renderingIntent = 'oplist';
+    if (!this.intentStates[renderingIntent]) {
+      this.intentStates[renderingIntent] = Object.create(null);
+    }
+    const intentState = this.intentStates[renderingIntent];
+    let opListTask;
+    if (!intentState.opListReadCapability) {
+      opListTask = {};
+      opListTask.operatorListChanged = operatorListChanged;
+      intentState.receivingOperatorList = true;
+      intentState.opListReadCapability = (0, _util.createPromiseCapability)();
+      intentState.renderTasks = [];
+      intentState.renderTasks.push(opListTask);
+      intentState.operatorList = {
+        fnArray: [],
+        argsArray: [],
+        lastChunk: false
       };
-      var internalRenderTask = new InternalRenderTask(complete, params, this.objs, this.commonObjs, intentState.operatorList, this.pageNumber, canvasFactory, webGLContext, this._pdfBug);
-      internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print';
-      if (!intentState.renderTasks) {
-        intentState.renderTasks = [];
-      }
-      intentState.renderTasks.push(internalRenderTask);
-      var renderTask = internalRenderTask.task;
-      intentState.displayReadyCapability.promise.then(transparency => {
-        if (this.pendingCleanup) {
-          complete();
-          return;
-        }
-        stats.time('Rendering');
-        internalRenderTask.initializeGraphics(transparency);
-        internalRenderTask.operatorListChanged();
-      }).catch(complete);
-      return renderTask;
-    },
-    getOperatorList: function PDFPageProxy_getOperatorList() {
-      function operatorListChanged() {
-        if (intentState.operatorList.lastChunk) {
-          intentState.opListReadCapability.resolve(intentState.operatorList);
-          var i = intentState.renderTasks.indexOf(opListTask);
-          if (i >= 0) {
-            intentState.renderTasks.splice(i, 1);
-          }
-        }
-      }
-      var renderingIntent = 'oplist';
-      if (!this.intentStates[renderingIntent]) {
-        this.intentStates[renderingIntent] = Object.create(null);
-      }
-      var intentState = this.intentStates[renderingIntent];
-      var opListTask;
-      if (!intentState.opListReadCapability) {
-        opListTask = {};
-        opListTask.operatorListChanged = operatorListChanged;
-        intentState.receivingOperatorList = true;
-        intentState.opListReadCapability = (0, _util.createPromiseCapability)();
-        intentState.renderTasks = [];
-        intentState.renderTasks.push(opListTask);
-        intentState.operatorList = {
-          fnArray: [],
-          argsArray: [],
-          lastChunk: false
-        };
-        this._stats.time('Page Request');
-        this.transport.messageHandler.send('RenderPageRequest', {
-          pageIndex: this.pageIndex,
-          intent: renderingIntent
-        });
-      }
-      return intentState.opListReadCapability.promise;
-    },
-    streamTextContent(params = {}) {
-      const TEXT_CONTENT_CHUNK_SIZE = 100;
-      return this.transport.messageHandler.sendWithStream('GetTextContent', {
-        pageIndex: this.pageNumber - 1,
-        normalizeWhitespace: params.normalizeWhitespace === true,
-        combineTextItems: params.disableCombineTextItems !== true
-      }, {
-        highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
-        size(textContent) {
-          return textContent.items.length;
-        }
+      this._stats.time('Page Request');
+      this._transport.messageHandler.send('RenderPageRequest', {
+        pageIndex: this.pageIndex,
+        intent: renderingIntent
       });
-    },
-    getTextContent: function PDFPageProxy_getTextContent(params) {
-      params = params || {};
-      let readableStream = this.streamTextContent(params);
-      return new Promise(function (resolve, reject) {
-        function pump() {
-          reader.read().then(function ({ value, done }) {
-            if (done) {
-              resolve(textContent);
-              return;
-            }
-            Object.assign(textContent.styles, value.styles);
-            textContent.items.push(...value.items);
-            pump();
-          }, reject);
-        }
-        let reader = readableStream.getReader();
-        let textContent = {
-          items: [],
-          styles: Object.create(null)
-        };
-        pump();
+    }
+    return intentState.opListReadCapability.promise;
+  }
+  streamTextContent({ normalizeWhitespace = false, disableCombineTextItems = false } = {}) {
+    const TEXT_CONTENT_CHUNK_SIZE = 100;
+    return this._transport.messageHandler.sendWithStream('GetTextContent', {
+      pageIndex: this.pageNumber - 1,
+      normalizeWhitespace: normalizeWhitespace === true,
+      combineTextItems: disableCombineTextItems !== true
+    }, {
+      highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
+      size(textContent) {
+        return textContent.items.length;
+      }
+    });
+  }
+  getTextContent(params = {}) {
+    const readableStream = this.streamTextContent(params);
+    return new Promise(function (resolve, reject) {
+      function pump() {
+        reader.read().then(function ({ value, done }) {
+          if (done) {
+            resolve(textContent);
+            return;
+          }
+          Object.assign(textContent.styles, value.styles);
+          textContent.items.push(...value.items);
+          pump();
+        }, reject);
+      }
+      const reader = readableStream.getReader();
+      const textContent = {
+        items: [],
+        styles: Object.create(null)
+      };
+      pump();
+    });
+  }
+  _destroy() {
+    this.destroyed = true;
+    this._transport.pageCache[this.pageIndex] = null;
+    const waitOn = [];
+    Object.keys(this.intentStates).forEach(function (intent) {
+      if (intent === 'oplist') {
+        return;
+      }
+      const intentState = this.intentStates[intent];
+      intentState.renderTasks.forEach(function (renderTask) {
+        const renderCompleted = renderTask.capability.promise.catch(function () {});
+        waitOn.push(renderCompleted);
+        renderTask.cancel();
       });
-    },
-    _destroy: function PDFPageProxy_destroy() {
-      this.destroyed = true;
-      this.transport.pageCache[this.pageIndex] = null;
-      var waitOn = [];
-      Object.keys(this.intentStates).forEach(function (intent) {
-        if (intent === 'oplist') {
-          return;
-        }
-        var intentState = this.intentStates[intent];
-        intentState.renderTasks.forEach(function (renderTask) {
-          var renderCompleted = renderTask.capability.promise.catch(function () {});
-          waitOn.push(renderCompleted);
-          renderTask.cancel();
-        });
-      }, this);
-      this.objs.clear();
-      this.annotationsPromise = null;
-      this.pendingCleanup = false;
-      return Promise.all(waitOn);
-    },
-    cleanup(resetStats = false) {
-      this.pendingCleanup = true;
-      this._tryCleanup(resetStats);
-    },
-    _tryCleanup(resetStats = false) {
-      if (!this.pendingCleanup || Object.keys(this.intentStates).some(function (intent) {
-        var intentState = this.intentStates[intent];
-        return intentState.renderTasks.length !== 0 || intentState.receivingOperatorList;
-      }, this)) {
-        return;
-      }
-      Object.keys(this.intentStates).forEach(function (intent) {
-        delete this.intentStates[intent];
-      }, this);
-      this.objs.clear();
-      this.annotationsPromise = null;
-      if (resetStats && this._stats instanceof _dom_utils.StatTimer) {
-        this._stats = new _dom_utils.StatTimer();
-      }
-      this.pendingCleanup = false;
-    },
-    _startRenderPage: function PDFPageProxy_startRenderPage(transparency, intent) {
-      var intentState = this.intentStates[intent];
-      if (intentState.displayReadyCapability) {
-        intentState.displayReadyCapability.resolve(transparency);
-      }
-    },
-    _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk, intent) {
-      var intentState = this.intentStates[intent];
-      var i, ii;
-      for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
-        intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
-        intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
-      }
-      intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
-      for (i = 0; i < intentState.renderTasks.length; i++) {
-        intentState.renderTasks[i].operatorListChanged();
-      }
-      if (operatorListChunk.lastChunk) {
-        intentState.receivingOperatorList = false;
-        this._tryCleanup();
-      }
-    },
-    get stats() {
-      return this._stats instanceof _dom_utils.StatTimer ? this._stats : null;
-    }
-  };
-  return PDFPageProxy;
-}();
+    }, this);
+    this.objs.clear();
+    this.annotationsPromise = null;
+    this.pendingCleanup = false;
+    return Promise.all(waitOn);
+  }
+  cleanup(resetStats = false) {
+    this.pendingCleanup = true;
+    this._tryCleanup(resetStats);
+  }
+  _tryCleanup(resetStats = false) {
+    if (!this.pendingCleanup || Object.keys(this.intentStates).some(function (intent) {
+      const intentState = this.intentStates[intent];
+      return intentState.renderTasks.length !== 0 || intentState.receivingOperatorList;
+    }, this)) {
+      return;
+    }
+    Object.keys(this.intentStates).forEach(function (intent) {
+      delete this.intentStates[intent];
+    }, this);
+    this.objs.clear();
+    this.annotationsPromise = null;
+    if (resetStats && this._stats instanceof _dom_utils.StatTimer) {
+      this._stats = new _dom_utils.StatTimer();
+    }
+    this.pendingCleanup = false;
+  }
+  _startRenderPage(transparency, intent) {
+    const intentState = this.intentStates[intent];
+    if (intentState.displayReadyCapability) {
+      intentState.displayReadyCapability.resolve(transparency);
+    }
+  }
+  _renderPageChunk(operatorListChunk, intent) {
+    const intentState = this.intentStates[intent];
+    for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
+      intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
+      intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
+    }
+    intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
+    for (let i = 0; i < intentState.renderTasks.length; i++) {
+      intentState.renderTasks[i].operatorListChanged();
+    }
+    if (operatorListChunk.lastChunk) {
+      intentState.receivingOperatorList = false;
+      this._tryCleanup();
+    }
+  }
+  get stats() {
+    return this._stats instanceof _dom_utils.StatTimer ? this._stats : null;
+  }
+}
 class LoopbackPort {
   constructor(defer = true) {
     this._listeners = [];
     this._defer = defer;
     this._deferred = Promise.resolve(undefined);
   }
   postMessage(obj, transfers) {
     function cloneValue(value) {
       if (typeof value !== 'object' || value === null) {
         return value;
       }
       if (cloned.has(value)) {
         return cloned.get(value);
       }
-      var result;
-      var buffer;
+      let buffer, result;
       if ((buffer = value.buffer) && (0, _util.isArrayBuffer)(buffer)) {
-        var transferable = transfers && transfers.includes(buffer);
+        const transferable = transfers && transfers.includes(buffer);
         if (value === buffer) {
           result = value;
         } else if (transferable) {
           result = new value.constructor(buffer, value.byteOffset, value.byteLength);
         } else {
           result = new value.constructor(value);
         }
         cloned.set(value, result);
         return result;
       }
       result = Array.isArray(value) ? [] : {};
       cloned.set(value, result);
-      for (var i in value) {
-        var desc,
+      for (const i in value) {
+        let desc,
             p = value;
         while (!(desc = Object.getOwnPropertyDescriptor(p, i))) {
           p = Object.getPrototypeOf(p);
         }
         if (typeof desc.value === 'undefined' || typeof desc.value === 'function') {
           continue;
         }
         result[i] = cloneValue(desc.value);
@@ -4684,37 +4691,39 @@ class LoopbackPort {
       return result;
     }
     if (!this._defer) {
       this._listeners.forEach(function (listener) {
         listener.call(this, { data: obj });
       }, this);
       return;
     }
-    var cloned = new WeakMap();
-    var e = { data: cloneValue(obj) };
+    const cloned = new WeakMap();
+    const e = { data: cloneValue(obj) };
     this._deferred.then(() => {
       this._listeners.forEach(function (listener) {
         listener.call(this, e);
       }, this);
     });
   }
   addEventListener(name, listener) {
     this._listeners.push(listener);
   }
   removeEventListener(name, listener) {
-    var i = this._listeners.indexOf(listener);
+    const i = this._listeners.indexOf(listener);
     this._listeners.splice(i, 1);
   }
   terminate() {
     this._listeners = [];
   }
 }
-var PDFWorker = function PDFWorkerClosure() {
+const PDFWorker = function PDFWorkerClosure() {
+  const pdfWorkerPorts = new WeakMap();
   let nextFakeWorkerId = 0;
+  let fakeWorkerFilesLoadedCapability;
   function getWorkerSrc() {
     if (_worker_options.GlobalWorkerOptions.workerSrc) {
       return _worker_options.GlobalWorkerOptions.workerSrc;
     }
     if (typeof fallbackWorkerSrc !== 'undefined') {
       return fallbackWorkerSrc;
     }
     throw new Error('No "GlobalWorkerOptions.workerSrc" specified.');
@@ -4722,92 +4731,90 @@ var PDFWorker = function PDFWorkerClosur
   function getMainThreadWorkerMessageHandler() {
     try {
       if (typeof window !== 'undefined') {
         return window.pdfjsWorker && window.pdfjsWorker.WorkerMessageHandler;
       }
     } catch (ex) {}
     return null;
   }
-  let fakeWorkerFilesLoadedCapability;
   function setupFakeWorkerGlobal() {
     if (fakeWorkerFilesLoadedCapability) {
       return fakeWorkerFilesLoadedCapability.promise;
     }
     fakeWorkerFilesLoadedCapability = (0, _util.createPromiseCapability)();
-    let mainWorkerMessageHandler = getMainThreadWorkerMessageHandler();
+    const mainWorkerMessageHandler = getMainThreadWorkerMessageHandler();
     if (mainWorkerMessageHandler) {
       fakeWorkerFilesLoadedCapability.resolve(mainWorkerMessageHandler);
       return fakeWorkerFilesLoadedCapability.promise;
     }
     const loader = fakeWorkerFilesLoader || function () {
       return (0, _dom_utils.loadScript)(getWorkerSrc()).then(function () {
         return window.pdfjsWorker.WorkerMessageHandler;
       });
     };
     loader().then(fakeWorkerFilesLoadedCapability.resolve, fakeWorkerFilesLoadedCapability.reject);
     return fakeWorkerFilesLoadedCapability.promise;
   }
   function createCDNWrapper(url) {
-    var wrapper = 'importScripts(\'' + url + '\');';
+    const wrapper = 'importScripts(\'' + url + '\');';
     return _util.URL.createObjectURL(new Blob([wrapper]));
   }
-  let pdfWorkerPorts = new WeakMap();
-  function PDFWorker({ name = null, port = null, postMessageTransfers = true, verbosity = (0, _util.getVerbosityLevel)() } = {}) {
-    if (port && pdfWorkerPorts.has(port)) {
-      throw new Error('Cannot use more than one PDFWorker per port');
-    }
-    this.name = name;
-    this.destroyed = false;
-    this.postMessageTransfers = postMessageTransfers !== false;
-    this.verbosity = verbosity;
-    this._readyCapability = (0, _util.createPromiseCapability)();
-    this._port = null;
-    this._webWorker = null;
-    this._messageHandler = null;
-    if (port) {
-      pdfWorkerPorts.set(port, this);
-      this._initializeFromPort(port);
-      return;
-    }
-    this._initialize();
-  }
-  PDFWorker.prototype = {
+  class PDFWorker {
+    constructor({ name = null, port = null, postMessageTransfers = true, verbosity = (0, _util.getVerbosityLevel)() } = {}) {
+      if (port && pdfWorkerPorts.has(port)) {
+        throw new Error('Cannot use more than one PDFWorker per port');
+      }
+      this.name = name;
+      this.destroyed = false;
+      this.postMessageTransfers = postMessageTransfers !== false;
+      this.verbosity = verbosity;
+      this._readyCapability = (0, _util.createPromiseCapability)();
+      this._port = null;
+      this._webWorker = null;
+      this._messageHandler = null;
+      if (port) {
+        pdfWorkerPorts.set(port, this);
+        this._initializeFromPort(port);
+        return;
+      }
+      this._initialize();
+    }
     get promise() {
       return this._readyCapability.promise;
-    },
+    }
     get port() {
       return this._port;
-    },
+    }
     get messageHandler() {
       return this._messageHandler;
-    },
-    _initializeFromPort: function PDFWorker_initializeFromPort(port) {
+    }
+    _initializeFromPort(port) {
       this._port = port;
       this._messageHandler = new _message_handler.MessageHandler('main', 'worker', port);
       this._messageHandler.on('ready', function () {});
       this._readyCapability.resolve();
-    },
-    _initialize: function PDFWorker_initialize() {
+    }
+    _initialize() {
       if (typeof Worker !== 'undefined' && !isWorkerDisabled && !getMainThreadWorkerMessageHandler()) {
         let workerSrc = getWorkerSrc();
         try {
-          var worker = new Worker(workerSrc);
-          var messageHandler = new _message_handler.MessageHandler('main', 'worker', worker);
-          var terminateEarly = () => {
+          const worker = new Worker(workerSrc);
+          const messageHandler = new _message_handler.MessageHandler('main', 'worker', worker);
+          const terminateEarly = () => {
             worker.removeEventListener('error', onWorkerError);
             messageHandler.destroy();
             worker.terminate();
             if (this.destroyed) {
               this._readyCapability.reject(new Error('Worker was destroyed'));
             } else {
               this._setupFakeWorker();
             }
           };
-          var onWorkerError = () => {
+          const onWorkerError = () => {
             if (!this._webWorker) {
               terminateEarly();
             }
           };
           worker.addEventListener('error', onWorkerError);
           messageHandler.on('test', data => {
             worker.removeEventListener('error', onWorkerError);
             if (this.destroyed) {
@@ -4853,65 +4860,65 @@ var PDFWorker = function PDFWorkerClosur
           };
           sendTest();
           return;
         } catch (e) {
           (0, _util.info)('The worker has been disabled.');
         }
       }
       this._setupFakeWorker();
-    },
-    _setupFakeWorker: function PDFWorker_setupFakeWorker() {
+    }
+    _setupFakeWorker() {
       if (!isWorkerDisabled) {
         (0, _util.warn)('Setting up fake worker.');
         isWorkerDisabled = true;
       }
       setupFakeWorkerGlobal().then(WorkerMessageHandler => {
         if (this.destroyed) {
           this._readyCapability.reject(new Error('Worker was destroyed'));
           return;
         }
-        let port = new LoopbackPort();
+        const port = new LoopbackPort();
         this._port = port;
-        var id = 'fake' + nextFakeWorkerId++;
-        var workerHandler = new _message_handler.MessageHandler(id + '_worker', id, port);
+        const id = 'fake' + nextFakeWorkerId++;
+        const workerHandler = new _message_handler.MessageHandler(id + '_worker', id, port);
         WorkerMessageHandler.setup(workerHandler, port);
-        var messageHandler = new _message_handler.MessageHandler(id, id + '_worker', port);
+        const messageHandler = new _message_handler.MessageHandler(id, id + '_worker', port);
         this._messageHandler = messageHandler;
         this._readyCapability.resolve();
       }).catch(reason => {
         this._readyCapability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`));
       });
-    },
-    destroy: function PDFWorker_destroy() {
+    }
+    destroy() {
       this.destroyed = true;
       if (this._webWorker) {
         this._webWorker.terminate();
         this._webWorker = null;
       }
       pdfWorkerPorts.delete(this._port);
       this._port = null;
       if (this._messageHandler) {
         this._messageHandler.destroy();
         this._messageHandler = null;
       }
     }
-  };
-  PDFWorker.fromPort = function (params) {
-    if (!params || !params.port) {
-      throw new Error('PDFWorker.fromPort - invalid method signature.');
-    }
-    if (pdfWorkerPorts.has(params.port)) {
-      return pdfWorkerPorts.get(params.port);
-    }
-    return new PDFWorker(params);
-  };
-  PDFWorker.getWorkerSrc = function () {
-    return getWorkerSrc();
-  };
+    static fromPort(params) {
+      if (!params || !params.port) {
+        throw new Error('PDFWorker.fromPort - invalid method signature.');
+      }
+      if (pdfWorkerPorts.has(params.port)) {
+        return pdfWorkerPorts.get(params.port);
+      }
+      return new PDFWorker(params);
+    }
+    static getWorkerSrc() {
+      return getWorkerSrc();
+    }
+  }
   return PDFWorker;
 }();
 class WorkerTransport {
   constructor(messageHandler, loadingTask, networkStream, params) {
     this.messageHandler = messageHandler;
     this.loadingTask = loadingTask;
     this.commonObjs = new PDFObjects();
     this.fontLoader = new _font_loader.FontLoader(loadingTask.docId);
@@ -5393,161 +5400,154 @@ class PDFObjects {
     obj.resolved = true;
     obj.data = data;
     obj.capability.resolve(data);
   }
   clear() {
     this._objs = Object.create(null);
   }
 }
-var RenderTask = function RenderTaskClosure() {
-  function RenderTask(internalRenderTask) {
+class RenderTask {
+  constructor(internalRenderTask) {
     this._internalRenderTask = internalRenderTask;
     this.onContinue = null;
   }
-  RenderTask.prototype = {
-    get promise() {
-      return this._internalRenderTask.capability.promise;
-    },
-    cancel: function RenderTask_cancel() {
-      this._internalRenderTask.cancel();
-    },
-    then: function RenderTask_then(onFulfilled, onRejected) {
-      return this.promise.then.apply(this.promise, arguments);
-    }
-  };
-  return RenderTask;
-}();
-var InternalRenderTask = function InternalRenderTaskClosure() {
-  let canvasInRendering = new WeakSet();
-  function InternalRenderTask(callback, params, objs, commonObjs, operatorList, pageNumber, canvasFactory, webGLContext, pdfBug = false) {
-    this.callback = callback;
-    this.params = params;
-    this.objs = objs;
-    this.commonObjs = commonObjs;
-    this.operatorListIdx = null;
-    this.operatorList = operatorList;
-    this.pageNumber = pageNumber;
-    this.canvasFactory = canvasFactory;
-    this.webGLContext = webGLContext;
-    this._pdfBug = pdfBug;
-    this.running = false;
-    this.graphicsReadyCallback = null;
-    this.graphicsReady = false;
-    this.useRequestAnimationFrame = false;
-    this.cancelled = false;
-    this.capability = (0, _util.createPromiseCapability)();
-    this.task = new RenderTask(this);
-    this._continueBound = this._continue.bind(this);
-    this._scheduleNextBound = this._scheduleNext.bind(this);
-    this._nextBound = this._next.bind(this);
-    this._canvas = params.canvasContext.canvas;
-  }
-  InternalRenderTask.prototype = {
-    initializeGraphics(transparency) {
+  get promise() {
+    return this._internalRenderTask.capability.promise;
+  }
+  cancel() {
+    this._internalRenderTask.cancel();
+  }
+  then(onFulfilled, onRejected) {
+    (0, _util.deprecated)('RenderTask.then method, use the `promise` getter instead.');
+    return this.promise.then.apply(this.promise, arguments);
+  }
+}
+const InternalRenderTask = function InternalRenderTaskClosure() {
+  const canvasInRendering = new WeakSet();
+  class InternalRenderTask {
+    constructor({ callback, params, objs, commonObjs, operatorList, pageNumber, canvasFactory, webGLContext, useRequestAnimationFrame = false, pdfBug = false }) {
+      this.callback = callback;
+      this.params = params;
+      this.objs = objs;
+      this.commonObjs = commonObjs;
+      this.operatorListIdx = null;
+      this.operatorList = operatorList;
+      this.pageNumber = pageNumber;
+      this.canvasFactory = canvasFactory;
+      this.webGLContext = webGLContext;
+      this._pdfBug = pdfBug;
+      this.running = false;
+      this.graphicsReadyCallback = null;
+      this.graphicsReady = false;
+      this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== 'undefined';
+      this.cancelled = false;
+      this.capability = (0, _util.createPromiseCapability)();
+      this.task = new RenderTask(this);
+      this._continueBound = this._continue.bind(this);
+      this._scheduleNextBound = this._scheduleNext.bind(this);
+      this._nextBound = this._next.bind(this);
+      this._canvas = params.canvasContext.canvas;
+    }
+    initializeGraphics(transparency = false) {
       if (this.cancelled) {
         return;
       }
       if (this._canvas) {
         if (canvasInRendering.has(this._canvas)) {
           throw new Error('Cannot use the same canvas during multiple render() operations. ' + 'Use different canvas or ensure previous operations were ' + 'cancelled or completed.');
         }
         canvasInRendering.add(this._canvas);
       }
       if (this._pdfBug && _global_scope2.default.StepperManager && _global_scope2.default.StepperManager.enabled) {
         this.stepper = _global_scope2.default.StepperManager.create(this.pageNumber - 1);
         this.stepper.init(this.operatorList);
         this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
       }
-      var params = this.params;
-      this.gfx = new _canvas.CanvasGraphics(params.canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.webGLContext, params.imageLayer);
+      const { canvasContext, viewport, transform, imageLayer, background } = this.params;
+      this.gfx = new _canvas.CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.webGLContext, imageLayer);
       this.gfx.beginDrawing({
-        transform: params.transform,
-        viewport: params.viewport,
+        transform,
+        viewport,
         transparency,
-        background: params.background
+        background
       });
       this.operatorListIdx = 0;
       this.graphicsReady = true;
       if (this.graphicsReadyCallback) {
         this.graphicsReadyCallback();
       }
-    },
-    cancel: function InternalRenderTask_cancel() {
+    }
+    cancel() {
       this.running = false;
       this.cancelled = true;
       if (this.gfx) {
         this.gfx.endDrawing();
       }
       if (this._canvas) {
         canvasInRendering.delete(this._canvas);
       }
       this.callback(new _dom_utils.RenderingCancelledException('Rendering cancelled, page ' + this.pageNumber, 'canvas'));
-    },
-    operatorListChanged: function InternalRenderTask_operatorListChanged() {
+    }
+    operatorListChanged() {
       if (!this.graphicsReady) {
         if (!this.graphicsReadyCallback) {
           this.graphicsReadyCallback = this._continueBound;
         }
         return;
       }
       if (this.stepper) {
         this.stepper.updateOperatorList(this.operatorList);
       }
       if (this.running) {
         return;
       }
       this._continue();
-    },
-    _continue: function InternalRenderTask__continue() {
+    }
+    _continue() {
       this.running = true;
       if (this.cancelled) {
         return;
       }
       if (this.task.onContinue) {
         this.task.onContinue(this._scheduleNextBound);
       } else {
         this._scheduleNext();
       }
-    },
-    _scheduleNext: function InternalRenderTask__scheduleNext() {
-      if (this.useRequestAnimationFrame && typeof window !== 'undefined') {
+    }
+    _scheduleNext() {
+      if (this._useRequestAnimationFrame) {
         window.requestAnimationFrame(() => {
           this._nextBound().catch(this.callback);
         });
       } else {
         Promise.resolve().then(this._nextBound).catch(this.callback);
       }
-    },
-    _next: function InternalRenderTask__next() {
-      return new Promise(() => {
-        if (this.cancelled) {
-          return;
-        }
-        this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper);
-        if (this.operatorListIdx === this.operatorList.argsArray.length) {
-          this.running = false;
-          if (this.operatorList.lastChunk) {
-            this.gfx.endDrawing();
-            if (this._canvas) {
-              canvasInRendering.delete(this._canvas);
-            }
-            this.callback();
+    }
+    async _next() {
+      if (this.cancelled) {
+        return;
+      }
+      this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper);
+      if (this.operatorListIdx === this.operatorList.argsArray.length) {
+        this.running = false;
+        if (this.operatorList.lastChunk) {
+          this.gfx.endDrawing();
+          if (this._canvas) {
+            canvasInRendering.delete(this._canvas);
           }
-        }
-      });
-    }
-  };
+          this.callback();
+        }
+      }
+    }
+  }
   return InternalRenderTask;
 }();
-var version, build;
-{
-  exports.version = version = '2.1.52';
-  exports.build = build = '4724ebbc';
-}
+const version = '2.1.70';
+const build = '6ebdbb24';
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamFactory = setPDFNetworkStreamFactory;
 exports.version = version;
@@ -6650,17 +6650,17 @@ var CanvasGraphics = function CanvasGrap
     genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height, smask.subtype, backdrop, smask.transferMap);
     ctx.drawImage(mask, 0, 0);
   }
   var LINE_CAP_STYLES = ['butt', 'round', 'square'];
   var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
   var NORMAL_CLIP = {};
   var EO_CLIP = {};
   CanvasGraphics.prototype = {
-    beginDrawing({ transform, viewport, transparency, background = null }) {
+    beginDrawing({ transform, viewport, transparency = false, background = null }) {
       var width = this.ctx.canvas.width;
       var height = this.ctx.canvas.height;
       this.ctx.save();
       this.ctx.fillStyle = background || 'rgb(255, 255, 255)';
       this.ctx.fillRect(0, 0, width, height);
       this.ctx.restore();
       if (transparency) {
         var transparentCanvas = this.cachedCanvases.getCanvas('transparent', width, height, true);
@@ -9687,17 +9687,17 @@ function _interopRequireDefault(obj) { r
 var renderTextLayer = function renderTextLayerClosure() {
   var MAX_TEXT_DIVS_TO_RENDER = 100000;
   var NonWhitespaceRegexp = /\S/;
   function isAllWhitespace(str) {
     return !NonWhitespaceRegexp.test(str);
   }
   var styleBuf = ['left: ', 0, 'px; top: ', 0, 'px; font-size: ', 0, 'px; font-family: ', '', ';'];
   function appendText(task, geom, styles) {
-    var textDiv = document.createElement('div');
+    var textDiv = document.createElement('span');
     var textDivProperties = {
       style: null,
       angle: 0,
       canvasWidth: 0,
       isWhitespace: false,
       originalTransform: null,
       paddingBottom: 0,
       paddingLeft: 0,
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.1.52';
-var pdfjsBuild = '4724ebbc';
+var pdfjsVersion = '2.1.70';
+var pdfjsBuild = '6ebdbb24';
 var pdfjsCoreWorker = __w_pdfjs_require__(1);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -321,17 +321,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.1.52';
+    let workerVersion = '2.1.70';
     if (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 _message_handler.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -19,17 +19,17 @@
   top: 0;
   right: 0;
   bottom: 0;
   overflow: hidden;
   opacity: 0.2;
   line-height: 1.0;
 }
 
-.textLayer > div {
+.textLayer > span {
   color: transparent;
   position: absolute;
   white-space: pre;
   cursor: text;
   transform-origin: 0% 0%;
 }
 
 .textLayer .highlight {
@@ -441,26 +441,26 @@ select {
 .pdfPresentationMode:-moz-full-screen a:not(.internalLink) {
   display: none;
 }
 
 .pdfPresentationMode:fullscreen a:not(.internalLink) {
   display: none;
 }
 
-.pdfPresentationMode:-moz-full-screen .textLayer > div {
+.pdfPresentationMode:-moz-full-screen .textLayer > span {
   cursor: none;
 }
 
-.pdfPresentationMode:fullscreen .textLayer > div {
+.pdfPresentationMode:fullscreen .textLayer > span {
   cursor: none;
 }
 
 .pdfPresentationMode.pdfPresentationModeControls > *,
-.pdfPresentationMode.pdfPresentationModeControls .textLayer > div {
+.pdfPresentationMode.pdfPresentationModeControls .textLayer > span {
   cursor: default;
 }
 
 #outerContainer {
   width: 100%;
   height: 100%;
   position: relative;
 }
@@ -1877,29 +1877,29 @@ html[dir='rtl'] #documentPropertiesOverl
 #viewer.textLayer-visible .canvasWrapper {
   background-color: rgb(128,255,128);
 }
 
 #viewer.textLayer-visible .canvasWrapper canvas {
   mix-blend-mode: screen;
 }
 
-#viewer.textLayer-visible .textLayer > div {
+#viewer.textLayer-visible .textLayer > span {
   background-color: rgba(255, 255, 0, 0.1);
   color: black;
   border: solid 1px rgba(255, 0, 0, 0.5);
   box-sizing: border-box;
 }
 
-#viewer.textLayer-hover .textLayer > div:hover {
+#viewer.textLayer-hover .textLayer > span:hover {
   background-color: white;
   color: black;
 }
 
-#viewer.textLayer-shadow .textLayer > div {
+#viewer.textLayer-shadow .textLayer > span {
   background-color: rgba(255,255,255, .6);
   color: black;
 }
 
 .grab-to-pan-grab {
   cursor: url("images/grab.cur"), move !important;
   cursor: grab !important;
 }
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -1490,17 +1490,19 @@ function webViewerPreviousPage() {
 function webViewerZoomIn() {
   PDFViewerApplication.zoomIn();
 }
 function webViewerZoomOut() {
   PDFViewerApplication.zoomOut();
 }
 function webViewerPageNumberChanged(evt) {
   let pdfViewer = PDFViewerApplication.pdfViewer;
-  pdfViewer.currentPageLabel = evt.value;
+  if (evt.value !== '') {
+    pdfViewer.currentPageLabel = evt.value;
+  }
   if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) {
     PDFViewerApplication.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);
   }
 }
 function webViewerScaleChanged(evt) {
   PDFViewerApplication.pdfViewer.currentScaleValue = evt.value;
 }
 function webViewerRotateCw() {
@@ -6629,58 +6631,65 @@ class BaseViewer {
   }
   set currentPageNumber(val) {
     if (!Number.isInteger(val)) {
       throw new Error('Invalid page number.');
     }
     if (!this.pdfDocument) {
       return;
     }
-    this._setCurrentPageNumber(val, true);
+    if (!this._setCurrentPageNumber(val, true)) {
+      console.error(`${this._name}.currentPageNumber: "${val}" is not a valid page.`);
+    }
   }
   _setCurrentPageNumber(val, resetCurrentPageView = false) {
     if (this._currentPageNumber === val) {
       if (resetCurrentPageView) {
         this._resetCurrentPageView();
       }
-      return;
+      return true;
     }
     if (!(0 < val && val <= this.pagesCount)) {
-      console.error(`${this._name}._setCurrentPageNumber: "${val}" is out of bounds.`);
-      return;
+      return false;
     }
     this._currentPageNumber = val;
     this.eventBus.dispatch('pagechanging', {
       source: this,
       pageNumber: val,
       pageLabel: this._pageLabels && this._pageLabels[val - 1]
     });
     if (resetCurrentPageView) {
       this._resetCurrentPageView();
     }
+    return true;
   }
   get currentPageLabel() {
     return this._pageLabels && this._pageLabels[this._currentPageNumber - 1];
   }
   set currentPageLabel(val) {
-    let pageNumber = val | 0;
+    if (!this.pdfDocument) {
+      return;
+    }
+    let page = val | 0;
     if (this._pageLabels) {
       let i = this._pageLabels.indexOf(val);
       if (i >= 0) {
-        pageNumber = i + 1;
-      }
-    }
-    this.currentPageNumber = pageNumber;
+        page = i + 1;
+      }
+    }
+    if (!this._setCurrentPageNumber(page, true)) {
+      console.error(`${this._name}.currentPageLabel: "${val}" is not a valid page.`);
+    }
   }
   get currentScale() {
     return this._currentScale !== _ui_utils.UNKNOWN_SCALE ? this._currentScale : _ui_utils.DEFAULT_SCALE;
   }
   set currentScale(val) {
     if (isNaN(val)) {
-      throw new Error('Invalid numeric scale');
+      throw new Error('Invalid numeric scale.');
     }
     if (!this.pdfDocument) {
       return;
     }
     this._setScale(val, false);
   }
   get currentScaleValue() {
     return this._currentScaleValue;
@@ -6960,17 +6969,17 @@ class BaseViewer {
     this._scrollIntoView({ pageDiv: pageView.div });
   }
   scrollPageIntoView({ pageNumber, destArray = null, allowNegativeOffset = false }) {
     if (!this.pdfDocument) {
       return;
     }
     const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1];
     if (!pageView) {
-      console.error(`${this._name}.scrollPageIntoView: Invalid "pageNumber" parameter.`);
+      console.error(`${this._name}.scrollPageIntoView: ` + `"${pageNumber}" is not a valid pageNumber parameter.`);
       return;
     }
     if (this.isInPresentationMode || !destArray) {
       this._setCurrentPageNumber(pageNumber, true);
       return;
     }
     let x = 0,
         y = 0;
@@ -8038,23 +8047,25 @@ class TextLayerBuilder {
       i1 = matches.length;
     } else if (!isSelectedPage) {
       return;
     }
     for (let i = i0; i < i1; i++) {
       let match = matches[i];
       let begin = match.begin;
       let end = match.end;
-      let isSelected = isSelectedPage && i === selectedMatchIdx;
-      let highlightSuffix = isSelected ? ' selected' : '';
-      findController.scrollMatchIntoView({
-        element: textDivs[begin.divIdx],
-        pageIndex: pageIdx,
-        matchIndex: i
-      });
+      const isSelected = isSelectedPage && i === selectedMatchIdx;
+      const highlightSuffix = isSelected ? ' selected' : '';
+      if (isSelected) {
+        findController.scrollMatchIntoView({
+          element: textDivs[begin.divIdx],
+          pageIndex: pageIdx,
+          matchIndex: selectedMatchIdx
+        });
+      }
       if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
         if (prevEnd !== null) {
           appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
         }
         beginText(begin);
       } else {
         appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
       }
--- a/browser/extensions/pdfjs/moz.yaml
+++ b/browser/extensions/pdfjs/moz.yaml
@@ -15,15 +15,15 @@ origin:
   description: Portable Document Format (PDF) viewer that is built with HTML5
 
   # Full URL for the package's homepage/etc
   # Usually different from repository url
   url: https://github.com/mozilla/pdf.js
 
   # Human-readable identifier for this version/release
   # Generally "version NNN", "tag SSS", "bookmark SSS"
-  release: version 2.1.52
+  release: version 2.1.70
 
   # The package's license, where possible using the mnemonic from
   # https://spdx.org/licenses/
   # Multiple licenses can be specified (as a YAML list)
   # A "LICENSE" file must exist containing the full license text
   license: Apache-2.0
--- a/browser/modules/Sanitizer.jsm
+++ b/browser/modules/Sanitizer.jsm
@@ -686,25 +686,33 @@ async function sanitizeOnShutdown(progre
                                 Ci.nsICookieService.ACCEPT_NORMALLY) == Ci.nsICookieService.ACCEPT_SESSION) {
     let principals = await getAllPrincipals();
     await maybeSanitizeSessionPrincipals(principals);
   }
 
 
   // Let's see if we have to forget some particular site.
   for (let permission of Services.perms.enumerator) {
-    if (permission.type == "cookie" && permission.capability == Ci.nsICookiePermission.ACCESS_SESSION) {
-      // We use just the URI here, because permissions ignore OriginAttributes.
-      let principals = await getAllPrincipals(permission.principal.URI);
-      let promises = [];
-      principals.forEach(principal => {
-        promises.push(sanitizeSessionPrincipal(principal));
-      });
-      await Promise.all(promises);
+    if (permission.type != "cookie" ||
+        permission.capability != Ci.nsICookiePermission.ACCESS_SESSION) {
+      continue;
+    }
+
+    // We consider just permissions set for http, https and file URLs.
+    if (!isSupportedURI(permission.principal.URI)) {
+      continue;
     }
+
+    // We use just the URI here, because permissions ignore OriginAttributes.
+    let principals = await getAllPrincipals(permission.principal.URI);
+    let promises = [];
+    principals.forEach(principal => {
+      promises.push(sanitizeSessionPrincipal(principal));
+    });
+    await Promise.all(promises);
   }
 
   if (Sanitizer.shouldSanitizeNewTabContainer) {
     sanitizeNewTabSegregation();
     removePendingSanitization("newtab-container");
   }
 
   if (Sanitizer.shouldSanitizeOnShutdown) {
@@ -727,29 +735,33 @@ async function getAllPrincipals(matchUri
         resolve([]);
         return;
       }
 
       let list = [];
       for (let item of request.result) {
         let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
         let uri = principal.URI;
-        if ((!matchUri || Services.eTLD.hasRootDomain(matchUri.host, uri.host)) &&
-            (uri.scheme == "http" || uri.scheme == "https" || uri.scheme == "file")) {
+        if (!isSupportedURI(uri)) {
+          continue;
+        }
+
+        if (!matchUri || Services.eTLD.hasRootDomain(matchUri.host, uri.host)) {
           list.push(principal);
         }
       }
       resolve(list);
     });
   }).catch(() => []);
 
   let serviceWorkers = serviceWorkerManager.getAllRegistrations();
   for (let i = 0; i < serviceWorkers.length; i++) {
     let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
     let uri = sw.principal.URI;
+    // We don't need to check the scheme. SW are just exposed to http/https URLs.
     if (!matchUri || Services.eTLD.hasRootDomain(matchUri.host, uri.host)) {
       principals.push(sw.principal);
     }
   }
 
   // Let's take the list of unique hosts+OA from cookies.
   let enumerator = Services.cookies.enumerator;
   let hosts = new Set();
@@ -798,16 +810,21 @@ function cookiesAllowedForDomainOrSubDom
     return false;
   }
 
   for (let perm of Services.perms.enumerator) {
     if (perm.type != "cookie") {
       continue;
     }
 
+    // We consider just permissions set for http, https and file URLs.
+    if (!isSupportedURI(perm.principal.URI)) {
+      continue;
+    }
+
     // We don't care about scheme, port, and anything else.
     if (Services.eTLD.hasRootDomain(perm.principal.URI.host,
                                     principal.URI.host)) {
       return cookiesAllowedForDomainOrSubDomain(perm.principal);
     }
   }
 
   return false;
@@ -854,30 +871,33 @@ function getItemsToClearFromPrefBranch(b
  * @param options The Sanitize options
  */
 function addPendingSanitization(id, itemsToClear, options) {
   let pendingSanitizations = safeGetPendingSanitizations();
   pendingSanitizations.push({id, itemsToClear, options});
   Services.prefs.setStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS,
                                JSON.stringify(pendingSanitizations));
 }
+
 function removePendingSanitization(id) {
   let pendingSanitizations = safeGetPendingSanitizations();
   let i = pendingSanitizations.findIndex(s => s.id == id);
   let [s] = pendingSanitizations.splice(i, 1);
   Services.prefs.setStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS,
     JSON.stringify(pendingSanitizations));
   return s;
 }
+
 function getAndClearPendingSanitizations() {
   let pendingSanitizations = safeGetPendingSanitizations();
   if (pendingSanitizations.length)
     Services.prefs.clearUserPref(Sanitizer.PREF_PENDING_SANITIZATIONS);
   return pendingSanitizations;
 }
+
 function safeGetPendingSanitizations() {
   try {
     return JSON.parse(
       Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]"));
   } catch (ex) {
     Cu.reportError("Invalid JSON value for pending sanitizations: " + ex);
     return [];
   }
@@ -890,8 +910,14 @@ async function clearData(range, flags) {
                                                flags, resolve);
     });
   } else {
     await new Promise(resolve => {
       Services.clearData.deleteData(flags, resolve);
     });
   }
 }
+
+function isSupportedURI(uri) {
+  return uri.scheme == "http" ||
+         uri.scheme == "https" ||
+         uri.scheme == "file";
+}
--- a/browser/themes/windows/compacttheme.css
+++ b/browser/themes/windows/compacttheme.css
@@ -4,16 +4,19 @@
 
 %include ../shared/compacttheme.inc.css
 
 @media (-moz-windows-accent-color-in-titlebar) {
   :root[tabsintitlebar]:not(:-moz-window-inactive) {
     background-color: -moz-win-accentcolor;
     color: -moz-win-accentcolortext;
   }
+  :root[tabsintitlebar] #titlebar {
+    --lwt-toolbarbutton-icon-fill: currentColor;
+  }
 }
 
 /* The window background is white due to no accentcolor in the lightweight
    theme. It can't be changed to transparent when there is no compositor
    (Win 7 in classic / basic theme), or else dragging and focus become
    broken. So instead just show the normal titlebar in that case, and override
    the window color as transparent when the compositor is available. */
 @media (-moz-windows-compositor: 0) {
--- a/caps/ContentPrincipal.cpp
+++ b/caps/ContentPrincipal.cpp
@@ -334,23 +334,22 @@ ContentPrincipal::MayLoadInternal(nsIURI
       NS_URIIsLocalFile(aURI) &&
       NS_RelaxStrictFileOriginPolicy(aURI, mCodebase)) {
     return true;
   }
 
   return false;
 }
 
-NS_IMETHODIMP
-ContentPrincipal::GetHashValue(uint32_t* aValue)
+uint32_t
+ContentPrincipal::GetHashValue()
 {
   MOZ_ASSERT(mCodebase, "Need a codebase");
 
-  *aValue = nsScriptSecurityManager::HashPrincipalByOrigin(this);
-  return NS_OK;
+  return nsScriptSecurityManager::HashPrincipalByOrigin(this);
 }
 
 NS_IMETHODIMP
 ContentPrincipal::GetDomain(nsIURI** aDomain)
 {
   if (!mDomain) {
     *aDomain = nullptr;
     return NS_OK;
--- a/caps/ContentPrincipal.h
+++ b/caps/ContentPrincipal.h
@@ -18,17 +18,17 @@
 
 namespace mozilla {
 
 class ContentPrincipal final : public BasePrincipal
 {
 public:
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
-  NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
+  uint32_t GetHashValue() override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
   NS_IMETHOD GetSiteOrigin(nsACString& aSiteOrigin) override;
   bool IsCodebasePrincipal() const override { return true; }
 
--- a/caps/DomainPolicy.cpp
+++ b/caps/DomainPolicy.cpp
@@ -234,23 +234,16 @@ DomainSet::ContainsSuperDomain(nsIURI* a
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // No match.
     return NS_OK;
 
 }
 
-NS_IMETHODIMP
-DomainSet::GetType(uint32_t* aType)
-{
-    *aType = mType;
-    return NS_OK;
-}
-
 void
 DomainSet::CloneSet(InfallibleTArray<URIParams>* aDomains)
 {
     for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
         nsIURI* key = iter.Get()->GetKey();
 
         URIParams uri;
         SerializeURI(key, uri);
--- a/caps/ExpandedPrincipal.cpp
+++ b/caps/ExpandedPrincipal.cpp
@@ -139,18 +139,18 @@ ExpandedPrincipal::MayLoadInternal(nsIUR
     if (BasePrincipal::Cast(mPrincipals[i])->MayLoadInternal(uri)) {
       return true;
     }
   }
 
   return false;
 }
 
-NS_IMETHODIMP
-ExpandedPrincipal::GetHashValue(uint32_t* result)
+uint32_t
+ExpandedPrincipal::GetHashValue()
 {
   MOZ_CRASH("extended principal should never be used as key in a hash map");
 }
 
 NS_IMETHODIMP
 ExpandedPrincipal::GetURI(nsIURI** aURI)
 {
   *aURI = nullptr;
--- a/caps/ExpandedPrincipal.h
+++ b/caps/ExpandedPrincipal.h
@@ -27,17 +27,17 @@ public:
   ExpandedPrincipal();
 
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
 
   NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
   NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
-  NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
+  uint32_t GetHashValue() override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
   virtual bool AddonHasPermission(const nsAtom* aPerm) override;
   virtual nsresult GetScriptLocation(nsACString &aStr) override;
 
--- a/caps/NullPrincipal.cpp
+++ b/caps/NullPrincipal.cpp
@@ -134,21 +134,20 @@ NullPrincipal::GetScriptLocation(nsACStr
 {
   return mURI->GetSpec(aStr);
 }
 
 /**
  * nsIPrincipal implementation
  */
 
-NS_IMETHODIMP
-NullPrincipal::GetHashValue(uint32_t *aResult)
+uint32_t
+NullPrincipal::GetHashValue()
 {
-  *aResult = (NS_PTR_TO_INT32(this) >> 2);
-  return NS_OK;
+  return (NS_PTR_TO_INT32(this) >> 2);
 }
 
 NS_IMETHODIMP
 NullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
 {
   // Never destroy an existing CSP on the principal.
   // This method should only be called in rare cases.
 
--- a/caps/NullPrincipal.h
+++ b/caps/NullPrincipal.h
@@ -43,17 +43,17 @@ public:
   {
   }
 
   static PrincipalKind Kind() { return eNullPrincipal; }
 
   NS_DECL_NSISERIALIZABLE
 
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
-  NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
+  uint32_t GetHashValue() override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
 
   static already_AddRefed<NullPrincipal>
--- a/caps/SystemPrincipal.cpp
+++ b/caps/SystemPrincipal.cpp
@@ -47,21 +47,20 @@ SystemPrincipal::GetScriptLocation(nsACS
     aStr.AssignLiteral(SYSTEM_PRINCIPAL_SPEC);
     return NS_OK;
 }
 
 ///////////////////////////////////////
 // Methods implementing nsIPrincipal //
 ///////////////////////////////////////
 
-NS_IMETHODIMP
-SystemPrincipal::GetHashValue(uint32_t *result)
+uint32_t
+SystemPrincipal::GetHashValue()
 {
-    *result = NS_PTR_TO_INT32(this);
-    return NS_OK;
+    return NS_PTR_TO_INT32(this);
 }
 
 NS_IMETHODIMP
 SystemPrincipal::GetURI(nsIURI** aURI)
 {
     *aURI = nullptr;
     return NS_OK;
 }
--- a/caps/SystemPrincipal.h
+++ b/caps/SystemPrincipal.h
@@ -30,17 +30,17 @@ class SystemPrincipal final : public Bas
 
 public:
   static already_AddRefed<SystemPrincipal> Create();
 
   static PrincipalKind Kind() { return eSystemPrincipal; }
 
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
-  NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
+  uint32_t GetHashValue() override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD EnsureCSP(nsIDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
   NS_IMETHOD EnsurePreloadCSP(nsIDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
--- a/caps/nsIDomainPolicy.idl
+++ b/caps/nsIDomainPolicy.idl
@@ -44,21 +44,16 @@ interface nsIDomainPolicy : nsISupports
     [noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
     [noscript, notxpcom] void applyClone(in DomainPolicyCloneConstPtr aClone);
 };
 
 [scriptable, builtinclass, uuid(665c981b-0a0f-4229-ac06-a826e02d4f69)]
 interface nsIDomainSet : nsISupports
 {
     /*
-     * The type of the set. See: DomainSetType
-     */
-    [noscript] readonly attribute uint32_t type;
-
-    /*
      * Add a domain to the set. No-op if it already exists.
      */
     void add(in nsIURI aDomain);
 
     /*
      * Remove a domain from the set. No-op if it doesn't exist.
      */
     void remove(in nsIURI aDomain);
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -64,17 +64,17 @@ interface nsIPrincipal : nsISerializable
     %{C++
       DECL_FAST_INLINE_HELPER(Equals)
       DECL_FAST_INLINE_HELPER(EqualsConsideringDomain)
     %}
 
     /**
      * Returns a hash value for the principal.
      */
-    [noscript] readonly attribute unsigned long hashValue;
+    [notxpcom, nostdcall] readonly attribute unsigned long hashValue;
 
     /**
      * The codebase URI to which this principal pertains.  This is
      * generally the document URI.
      */
     readonly attribute nsIURI URI;
 
     /**
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -345,22 +345,24 @@ nsScriptSecurityManager::GetChannelResul
   if (owner) {
     CallQueryInterface(owner, aPrincipal);
     if (*aPrincipal) {
       return NS_OK;
     }
   }
 
   if (loadInfo) {
-        if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) {
-          MOZ_ALWAYS_TRUE(NS_SUCCEEDED(loadInfo->GetSandboxedLoadingPrincipal(aPrincipal)));
-          MOZ_ASSERT(*aPrincipal);
-          InheritAndSetCSPOnPrincipalIfNeeded(aChannel, *aPrincipal);
-          return NS_OK;
-        }
+    if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) {
+      nsCOMPtr<nsIPrincipal> sandboxedLoadingPrincipal =
+        loadInfo->GetSandboxedLoadingPrincipal();
+      MOZ_ASSERT(sandboxedLoadingPrincipal);
+      InheritAndSetCSPOnPrincipalIfNeeded(aChannel, sandboxedLoadingPrincipal);
+      sandboxedLoadingPrincipal.forget(aPrincipal);
+      return NS_OK;
+    }
 
     bool forceInherit = loadInfo->GetForceInheritPrincipal();
     if (aIgnoreSandboxing && !forceInherit) {
       // Check if SEC_FORCE_INHERIT_PRINCIPAL was dropped because of
       // sandboxing:
       if (loadInfo->GetLoadingSandboxed() &&
         loadInfo->GetForceInheritPrincipalDropped()) {
         forceInherit = true;
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -776,9 +776,9 @@ skip-if = os != "mac" || debug || !night
 skip-if = true # See bug 1481009
 [browser_dbg_rr_replay-01.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_replay-02.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_replay-03.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_console_warp-01.js]
-skip-if = true # Bug 1483969
+skip-if = os != "mac" || debug || !nightly_build
--- a/devtools/client/responsive.html/manager.js
+++ b/devtools/client/responsive.html/manager.js
@@ -2,33 +2,33 @@
  * 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/. */
 
 "use strict";
 
 const { Ci } = require("chrome");
 const promise = require("promise");
 const Services = require("Services");
-const asyncStorage = require("devtools/shared/async-storage");
 const EventEmitter = require("devtools/shared/event-emitter");
 
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/components/throttling/profiles");
 loader.lazyRequireGetter(this, "SettingOnboardingTooltip", "devtools/client/responsive.html/setting-onboarding-tooltip");
 loader.lazyRequireGetter(this, "swapToInnerBrowser", "devtools/client/responsive.html/browser/swap", true);
 loader.lazyRequireGetter(this, "startup", "devtools/client/responsive.html/utils/window", true);
 loader.lazyRequireGetter(this, "message", "devtools/client/responsive.html/utils/message");
 loader.lazyRequireGetter(this, "showNotification", "devtools/client/responsive.html/utils/notification", true);
 loader.lazyRequireGetter(this, "l10n", "devtools/client/responsive.html/utils/l10n");
 loader.lazyRequireGetter(this, "EmulationFront", "devtools/shared/fronts/emulation", true);
 loader.lazyRequireGetter(this, "PriorityLevels", "devtools/client/shared/components/NotificationBox", true);
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
+loader.lazyRequireGetter(this, "asyncStorage", "devtools/shared/async-storage");
 
 const TOOL_URL = "chrome://devtools/content/responsive.html/index.xhtml";
 
 const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
 const RELOAD_NOTIFICATION_PREF = "devtools.responsive.reloadNotification.enabled";
 const SHOW_SETTING_TOOLTIP_PREF = "devtools.responsive.show-setting-tooltip";
 
 function debug(msg) {
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -419,25 +419,16 @@ Editor.prototype = {
       if (!this._lastDirty) {
         this._lastDirty = true;
         this.emit("dirty-change");
       }
     });
 
     cm.on("gutterClick", (cmArg, line, gutter, ev) => {
       const lineOrOffset = !this.isWasm ? line : this.lineToWasmOffset(line);
-      const head = { line: line, ch: 0 };
-      const tail = { line: line, ch: this.getText(lineOrOffset).length };
-
-      // Shift-click on a gutter selects the whole line.
-      if (ev.shiftKey) {
-        cmArg.setSelection(head, tail);
-        return;
-      }
-
       this.emit("gutterClick", lineOrOffset, ev.button);
     });
 
     win.CodeMirror.defineExtension("l10n", (name) => {
       return L10N.getStr(name);
     });
 
     if (!this.config.disableSearchAddon) {
--- a/devtools/client/sourceeditor/test/browser_editor_cursor.js
+++ b/devtools/client/sourceeditor/test/browser_editor_cursor.js
@@ -32,13 +32,13 @@ function test() {
 
     // Check that shift-click on a gutter selects the whole line (bug 919707)
     const iframe = win.document.querySelector("iframe");
     const gutter =
       iframe.contentWindow.document.querySelector(".CodeMirror-gutters");
 
     EventUtils.sendMouseEvent({ type: "mousedown", shiftKey: true }, gutter,
       iframe.contentWindow);
-    is(ed.getSelection(), "Hello.", "shift-click");
+    is(ed.getSelection(), "", "shift-click");
 
     teardown(ed, win);
   });
 }
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -267,16 +267,17 @@ tags = mcb
 [browser_webconsole_close_sidebar.js]
 skip-if = true # Bug 1405250
 [browser_webconsole_console_api_iframe.js]
 [browser_webconsole_console_dir.js]
 [browser_webconsole_console_dir_uninspectable.js]
 [browser_webconsole_console_error_expand_object.js]
 [browser_webconsole_console_group.js]
 [browser_webconsole_console_logging_workers_api.js]
+skip-if = e10s # SharedWorkers console events are not received on the current process because they could run on any process.
 [browser_webconsole_console_table.js]
 [browser_webconsole_console_trace_duplicates.js]
 [browser_webconsole_context_menu_copy_entire_message.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_context_menu_copy_link_location.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) || (os == 'linux') # bug 1328915, disable linux32 debug devtools for timeouts, bug 1473120
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -350,17 +350,17 @@ const SourceActor = ActorClassWithSpec(s
             return toResolvedContent(sourceContent);
           }
         } catch (error) {
           this._reportLoadSourceError(error, map);
           throw error;
         }
       }
 
-      if (isWasm && this.dbg.allowWasmBinarySource) {
+      if (isWasm) {
         const wasm = this.source.binary;
         const buffer = wasm.buffer;
         assert(
           wasm.byteOffset === 0 && wasm.byteLength === buffer.byteLength,
           "Typed array from wasm source binary must cover entire buffer"
         );
         return toResolvedContent(buffer);
       }
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -434,19 +434,16 @@ const ThreadActor = ActorClassWithSpec(t
     if (this.state == "exited") {
       return { error: "wrongState" };
     }
     const options = request.options || {};
 
     if ("observeAsmJS" in options) {
       this.dbg.allowUnobservedAsmJS = !options.observeAsmJS;
     }
-    if ("wasmBinarySource" in options) {
-      this.dbg.allowWasmBinarySource = !!options.wasmBinarySource;
-    }
 
     Object.assign(this._options, options);
 
     // Update the global source store
     this.sources.setOptions(options);
 
     return {};
   },
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -367,16 +367,20 @@ WebConsoleActor.prototype =
 
     this.conn.removeActorPool(this._actorPool);
 
     if (this.parentActor.isRootActor) {
       Services.obs.removeObserver(this._onObserverNotification,
                                   "last-pb-context-exited");
     }
 
+    if (this.dbg.replaying && !isWorker) {
+      this.dbg.onConsoleMessage = null;
+    }
+
     this._actorPool = null;
     this._webConsoleCommandsCache = null;
     this._lastConsoleInputEvaluation = null;
     this._evalWindow = null;
     this.dbg.enabled = false;
     this.dbg = null;
     this.conn = null;
   },
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1110,72 +1110,58 @@ nsDocShell::ValidateOrigin(nsIDocShellTr
   }
 
   return innerOriginURI && innerTargetURI &&
          NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
          NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
          originIsFile && targetIsFile;
 }
 
-nsresult
-nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
-{
-  NS_ENSURE_ARG_POINTER(aPresContext);
-  *aPresContext = nullptr;
-
-  nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
+nsPresContext*
+nsDocShell::GetEldestPresContext()
+{
+  nsIContentViewer* viewer = mContentViewer;
   while (viewer) {
-    nsCOMPtr<nsIContentViewer> prevViewer;
-    viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
+    nsIContentViewer* prevViewer = viewer->GetPreviousViewer();
     if (!prevViewer) {
-      return viewer->GetPresContext(aPresContext);
+      return viewer->GetPresContext();
     }
     viewer = prevViewer;
   }
 
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::GetPresContext(nsPresContext** aPresContext)
-{
-  NS_ENSURE_ARG_POINTER(aPresContext);
-  *aPresContext = nullptr;
-
+  return nullptr;
+}
+
+nsPresContext*
+nsDocShell::GetPresContext()
+{
   if (!mContentViewer) {
-    return NS_OK;
-  }
-
-  return mContentViewer->GetPresContext(aPresContext);
-}
-
-NS_IMETHODIMP_(nsIPresShell*)
+    return nullptr;
+  }
+
+  return mContentViewer->GetPresContext();
+}
+
+nsIPresShell*
 nsDocShell::GetPresShell()
 {
-  RefPtr<nsPresContext> presContext;
-  (void)GetPresContext(getter_AddRefs(presContext));
+  nsPresContext* presContext = GetPresContext();
   return presContext ? presContext->GetPresShell() : nullptr;
 }
 
-NS_IMETHODIMP
-nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
-{
-  nsresult rv = NS_OK;
-
-  NS_ENSURE_ARG_POINTER(aPresShell);
-  *aPresShell = nullptr;
-
-  RefPtr<nsPresContext> presContext;
-  (void)GetEldestPresContext(getter_AddRefs(presContext));
+nsIPresShell*
+nsDocShell::GetEldestPresShell()
+{
+  nsPresContext* presContext = GetEldestPresContext();
 
   if (presContext) {
-    NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
-  }
-
-  return rv;
+    return presContext->GetPresShell();
+  }
+
+  return nullptr;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer)
 {
   NS_ENSURE_ARG_POINTER(aContentViewer);
 
   *aContentViewer = mContentViewer;
@@ -3393,28 +3379,26 @@ nsDocShell::SetTreeOwner(nsIDocShellTree
   // and we never set another parent. Given that this is neither expensive nor
   // performance-critical, let's be safe and unconditionally recompute this
   // state whenever dependent state changes.
   RecomputeCanExecuteScripts();
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 nsDocShell::SetChildOffset(int32_t aChildOffset)
 {
   mChildOffset = aChildOffset;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::GetChildOffset(int32_t* aChildOffset)
-{
-  *aChildOffset = mChildOffset;
-  return NS_OK;
+}
+
+int32_t
+nsDocShell::GetChildOffset()
+{
+  return mChildOffset;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHistoryID(nsID** aID)
 {
   *aID = mHistoryID.Clone();
   return NS_OK;
 }
@@ -3941,18 +3925,17 @@ nsDocShell::GetContentBlockingLog(Promis
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
 {
   if (mDeviceSizeIsPageSize != aValue) {
     mDeviceSizeIsPageSize = aValue;
-    RefPtr<nsPresContext> presContext;
-    GetPresContext(getter_AddRefs(presContext));
+    RefPtr<nsPresContext> presContext = GetPresContext();
     if (presContext) {
       presContext->MediaFeatureValuesChanged({
         MediaFeatureChangeReason::DeviceSizeIsPageSizeChange });
     }
   }
   return NS_OK;
 }
 
@@ -8103,18 +8086,20 @@ nsDocShell::RestoreFromHistory()
 
   // In cases where we use a transient about:blank viewer between loads,
   // we never show the transient viewer, so _its_ previous viewer is never
   // unhooked from the view hierarchy.  Destroy any such previous viewer now,
   // before we grab the root view sibling, so that we don't grab a view
   // that's about to go away.
 
   if (mContentViewer) {
-    nsCOMPtr<nsIContentViewer> previousViewer;
-    mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
+    // Make sure to hold a strong ref to previousViewer here while we
+    // drop the reference to it from mContentViewer.
+    nsCOMPtr<nsIContentViewer> previousViewer =
+      mContentViewer->GetPreviousViewer();
     if (previousViewer) {
       mContentViewer->SetPreviousViewer(nullptr);
       previousViewer->Destroy();
     }
   }
 
   // Save off the root view's parent and sibling so that we can insert the
   // new content viewer's root view at the same position.  Also save the
@@ -8814,18 +8799,17 @@ nsDocShell::SetupNewViewer(nsIContentVie
   nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer;
   if (contentViewer) {
     // Stop any activity that may be happening in the old document before
     // releasing it...
     contentViewer->Stop();
 
     // Try to extract the canvas background color from the old
     // presentation shell, so we can use it for the next document.
-    nsCOMPtr<nsIPresShell> shell;
-    contentViewer->GetPresShell(getter_AddRefs(shell));
+    nsCOMPtr<nsIPresShell> shell = contentViewer->GetPresShell();
 
     if (shell) {
       bgcolor = shell->GetCanvasBackground();
       isActive = shell->IsActive();
     }
 
     contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
     aNewViewer->SetPreviousViewer(contentViewer);
@@ -8873,18 +8857,17 @@ nsDocShell::SetupNewViewer(nsIContentVie
     NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX),
                       NS_ERROR_FAILURE);
     NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled),
                       NS_ERROR_FAILURE);
   }
 
   // Stuff the bgcolor from the old pres shell into the new
   // pres shell. This improves page load continuity.
-  nsCOMPtr<nsIPresShell> shell;
-  mContentViewer->GetPresShell(getter_AddRefs(shell));
+  nsCOMPtr<nsIPresShell> shell = mContentViewer->GetPresShell();
 
   if (shell) {
     shell->SetCanvasBackground(bgcolor);
     if (isActive) {
       shell->SetIsActive(isActive);
     }
   }
 
@@ -9994,22 +9977,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
     // Stop any current network activity.
     // Also stop content if this is a zombie doc. otherwise
     // the onload will be delayed by other loads initiated in the
     // background by the first document that
     // didn't fully load before the next load was initiated.
     // If not a zombie, don't stop content until data
     // starts arriving from the new URI...
 
-    nsCOMPtr<nsIContentViewer> zombieViewer;
-    if (mContentViewer) {
-      mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
-    }
-
-    if (zombieViewer ||
+    if ((mContentViewer && mContentViewer->GetPreviousViewer()) ||
         LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
       rv = Stop(nsIWebNavigation::STOP_ALL);
     } else {
       rv = Stop(nsIWebNavigation::STOP_NETWORK);
     }
 
     if (NS_FAILED(rv)) {
       return rv;
@@ -10034,22 +10012,22 @@ nsDocShell::InternalLoad(nsIURI* aURI,
 
   // If we have a saved content viewer in history, restore and show it now.
   if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
     // It's possible that the previous viewer of mContentViewer is the
     // viewer that will end up in aSHEntry when it gets closed.  If that's
     // the case, we need to go ahead and force it into its shentry so we
     // can restore it.
     if (mContentViewer) {
-      nsCOMPtr<nsIContentViewer> prevViewer;
-      mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
+      nsCOMPtr<nsIContentViewer> prevViewer =
+        mContentViewer->GetPreviousViewer();
       if (prevViewer) {
 #ifdef DEBUG
-        nsCOMPtr<nsIContentViewer> prevPrevViewer;
-        prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
+        nsCOMPtr<nsIContentViewer> prevPrevViewer =
+          prevViewer->GetPreviousViewer();
         NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
 #endif
         nsCOMPtr<nsISHEntry> viewerEntry;
         prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
         if (viewerEntry == aSHEntry) {
           // Make sure this viewer ends up in the right place
           mContentViewer->SetPreviousViewer(nullptr);
           prevViewer->Destroy();
@@ -14079,21 +14057,19 @@ nsDocShell::SetDisplayMode(uint32_t aDis
         aDisplayMode == nsIDocShell::DISPLAY_MODE_FULLSCREEN ||
         aDisplayMode == nsIDocShell::DISPLAY_MODE_MINIMAL_UI)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (aDisplayMode != mDisplayMode) {
     mDisplayMode = aDisplayMode;
 
-    RefPtr<nsPresContext> presContext;
-    if (NS_SUCCEEDED(GetPresContext(getter_AddRefs(presContext)))) {
-      presContext->MediaFeatureValuesChangedAllDocuments({
-        MediaFeatureChangeReason::DisplayModeChange });
-    }
+    RefPtr<nsPresContext> presContext = GetPresContext();
+    presContext->MediaFeatureValuesChangedAllDocuments({
+      MediaFeatureChangeReason::DisplayModeChange });
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetColorMatrix(float* aMatrix, uint32_t aMatrixLen)
 {
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -881,17 +881,17 @@ private: // member functions
   nsresult EnsureScriptEnvironment();
   nsresult EnsureEditorData();
   nsresult EnsureTransferableHookData();
   nsresult EnsureFind();
   nsresult EnsureCommandHandler();
   nsresult RefreshURIFromQueue();
   nsresult Embed(nsIContentViewer* aContentViewer,
                  const char* aCommand, nsISupports* aExtraInfo);
-  nsresult GetEldestPresContext(nsPresContext** aPresContext);
+  nsPresContext* GetEldestPresContext();
   nsresult CheckLoadingPermissions();
   nsresult PersistLayoutHistoryState();
   nsresult LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType);
   nsresult SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer);
   nsresult GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn);
   nsresult ConfirmRepost(bool* aRepost);
   nsresult GetPromptAndStringBundle(nsIPrompt** aPrompt,
                                     nsIStringBundle** aStringBundle);
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -417,18 +417,17 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocS
 
   // Set the preferred Size
   //XXX
   NS_ERROR("Implement this");
   /*
   Set the preferred size on the aShellItem.
   */
 
-  RefPtr<nsPresContext> presContext;
-  mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mWebBrowser->mDocShell->GetPresContext();
   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 
   nsIPresShell* presShell = presContext->GetPresShell();
   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
   NS_ENSURE_SUCCESS(
     presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
     NS_ERROR_FAILURE);
--- a/docshell/base/nsIContentViewer.idl
+++ b/docshell/base/nsIContentViewer.idl
@@ -38,19 +38,19 @@ interface nsIContentViewer : nsISupports
 {
   [noscript] void init(in nsIWidgetPtr aParentWidget,
                        [const] in nsIntRectRef aBounds);
 
   attribute nsIDocShell container;
 
   [noscript,notxpcom,nostdcall] void loadStart(in Document aDoc);
   void loadComplete(in nsresult aStatus);
-  [noscript] readonly attribute boolean loadCompleted;
+  [notxpcom,nostdcall] readonly attribute boolean loadCompleted;
 
-  [noscript] readonly attribute boolean isStopped;
+  [notxpcom,nostdcall] readonly attribute boolean isStopped;
 
   /**
    * aPermitUnloadFlags are passed to PermitUnload to indicate what action to take
    * if a beforeunload handler wants to prompt the user.  It is also used by
    * permitUnloadInternal to ensure we only prompt once.
    *
    * ePrompt: Prompt and return the user's choice (default).
    * eDontPromptAndDontUnload: Don't prompt and return false (unload not permitted)
@@ -148,17 +148,17 @@ interface nsIContentViewer : nsISupports
   const unsigned long eDelayResize = 1;
   [noscript] void setBoundsWithFlags([const] in nsIntRectRef aBounds,
                                      in unsigned long aFlags);
 
   /**
    * The previous content viewer, which has been |close|d but not
    * |destroy|ed.
    */
-  [noscript] attribute nsIContentViewer previousViewer;
+  [notxpcom,nostdcall] attribute nsIContentViewer previousViewer;
 
   void move(in long aX, in long aY);
 
   void show();
   void hide();
 
   attribute boolean sticky;
 
@@ -209,18 +209,20 @@ interface nsIContentViewer : nsISupports
 
   /**
    * Returns whether this content viewer is in a hidden state.
    *
    * @note Only Gecko internal code should set the attribute!
    */
   attribute boolean isHidden;
 
-  [noscript] readonly attribute nsIPresShellPtr presShell;
-  [noscript] readonly attribute nsPresContextPtr presContext;
+  // presShell can be null.
+  [notxpcom,nostdcall] readonly attribute nsIPresShellPtr presShell;
+  // presContext can be null.
+  [notxpcom,nostdcall] readonly attribute nsPresContextPtr presContext;
   // aDocument must not be null.
   [noscript] void setDocumentInternal(in Document aDocument,
                                       in boolean aForceReuseInnerWindow);
   /**
    * Find the view to use as the container view for MakeWindow. Returns
    * null if this will be the root of a view manager hierarchy. In that
    * case, if mParentWidget is null then this document should not even
    * be displayed.
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -233,28 +233,28 @@ interface nsIDocShell : nsIDocShellTreeI
    *        True to fire the unload event in addition to the pagehide event,
    *        and remove all dynamic subframe history entries.
    */
   [noscript] void firePageHideNotification(in boolean isUnload);
 
   /**
    * Presentation context for the currently loaded document.  This may be null.
    */
-  [noscript] readonly attribute nsPresContext presContext;
+  [notxpcom,nostdcall] readonly attribute nsPresContext presContext;
 
   /**
    * Presentation shell for the currently loaded document.  This may be null.
    */
-  [noscript,notxpcom] nsIPresShell GetPresShell();
+  [notxpcom,nostdcall] readonly attribute nsIPresShell presShell;
 
   /**
    * Presentation shell for the oldest document, if this docshell is
    * currently transitioning between documents.
    */
-  [noscript] readonly attribute nsIPresShell eldestPresShell;
+  [notxpcom,nostdcall] readonly attribute nsIPresShell eldestPresShell;
 
   /**
    * Content Viewer that is currently loaded for this DocShell.  This may
    * change as the underlying content changes.
    */
   readonly attribute nsIContentViewer contentViewer;
 
   /**
@@ -554,17 +554,17 @@ interface nsIDocShell : nsIDocShellTreeI
    * until after OnLocationChange fires.
    */
   readonly attribute nsIChannel currentDocumentChannel;
 
   /**
    * The original offset of this child in its container. This property is -1 for
    * dynamically added docShells.
    */
-  [noscript] attribute long childOffset;
+  [notxpcom,nostdcall] attribute long childOffset;
 
   /**
    * Find out whether the docshell is currently in the middle of a page
    * transition. This is set just before the pagehide/unload events fire.
    */
   readonly attribute boolean isInUnload;
 
   /**
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -14,16 +14,17 @@
 
 #include "AnimationCommon.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/Flex.h"
 #include "mozilla/dom/Grid.h"
+#include "mozilla/dom/Text.h"
 #include "mozilla/gfx/Matrix.h"
 #include "nsAtom.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "nsIDocumentInlines.h"
 #include "mozilla/dom/DocumentTimeline.h"
@@ -154,46 +155,49 @@
 
 #include "DOMMatrix.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 using mozilla::gfx::Matrix4x4;
 
+// Verify sizes of nodes. We use a template rather than a direct static
+// assert so that the error message actually displays the sizes.
+// On 32 bit systems the actual allocated size varies a bit between
+// OSes/compilers.
 //
-// Verify sizes of elements on 64-bit platforms. This should catch most memory
-// regressions, and is easy to verify locally since most developers are on
-// 64-bit machines. We use a template rather than a direct static assert so
-// that the error message actually displays the sizes.
-//
-
 // We need different numbers on certain build types to deal with the owning
 // thread pointer that comes with the non-threadsafe refcount on
-// FragmentOrElement.
+// nsIContent.
 #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
-#define EXTRA_DOM_ELEMENT_BYTES 8
+#define EXTRA_DOM_NODE_BYTES 8
 #else
-#define EXTRA_DOM_ELEMENT_BYTES 0
+#define EXTRA_DOM_NODE_BYTES 0
 #endif
 
-#define ASSERT_ELEMENT_SIZE(type, opt_size) \
-template<int a, int b> struct Check##type##Size \
+#define ASSERT_NODE_SIZE(type, opt_size_64, opt_size_32) \
+template<int a, int sizeOn64, int sizeOn32> struct Check##type##Size \
 { \
-  static_assert(sizeof(void*) != 8 || a == b, "DOM size changed"); \
+  static_assert((sizeof(void*) == 8 && a == sizeOn64) || \
+                (sizeof(void*) == 4 && a <= sizeOn32), "DOM size changed"); \
 }; \
-Check##type##Size<sizeof(type), opt_size + EXTRA_DOM_ELEMENT_BYTES> g##type##CES;
-
-// Note that mozjemalloc uses a 16 byte quantum, so 128 is a bin/bucket size.
-ASSERT_ELEMENT_SIZE(Element, 128);
-ASSERT_ELEMENT_SIZE(HTMLDivElement, 128);
-ASSERT_ELEMENT_SIZE(HTMLSpanElement, 128);
-
-#undef ASSERT_ELEMENT_SIZE
-#undef EXTRA_DOM_ELEMENT_BYTES
+Check##type##Size<sizeof(type), \
+                  opt_size_64 + EXTRA_DOM_NODE_BYTES, \
+                  opt_size_32 + EXTRA_DOM_NODE_BYTES> g##type##CES;
+
+// Note that mozjemalloc uses a 16 byte quantum, so 64, 80 and 128 are
+// bucket sizes.
+ASSERT_NODE_SIZE(Element, 128, 80);
+ASSERT_NODE_SIZE(HTMLDivElement, 128, 80);
+ASSERT_NODE_SIZE(HTMLSpanElement, 128, 80);
+ASSERT_NODE_SIZE(Text, 120, 64);
+
+#undef ASSERT_NODE_SIZE
+#undef EXTRA_DOM_NODE_BYTES
 
 nsAtom*
 nsIContent::DoGetID() const
 {
   MOZ_ASSERT(HasID(), "Unexpected call");
   MOZ_ASSERT(IsElement(), "Only elements can have IDs");
 
   return AsElement()->GetParsedAttr(nsGkAtoms::id)->GetAtomValue();
--- a/dom/base/FuzzingFunctions.cpp
+++ b/dom/base/FuzzingFunctions.cpp
@@ -285,18 +285,17 @@ FuzzingFunctions::SynthesizeKeyboardEven
   }
 
   nsIDocShell* docShell = activeWindow->GetDocShell();
   if (NS_WARN_IF(!docShell)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  RefPtr<nsPresContext> presContext;
-  docShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = docShell->GetPresContext();
   if (NS_WARN_IF(!presContext)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   event.mWidget = presContext->GetRootWidget();
   if (NS_WARN_IF(!event.mWidget)) {
     aRv.Throw(NS_ERROR_FAILURE);
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -387,21 +387,17 @@ TextInputProcessor::BeginInputTransactio
   nsCOMPtr<nsPIDOMWindowInner> pWindow = nsPIDOMWindowInner::From(aWindow);
   if (NS_WARN_IF(!pWindow)) {
     return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIDocShell> docShell(pWindow->GetDocShell());
   if (NS_WARN_IF(!docShell)) {
     return NS_ERROR_FAILURE;
   }
-  RefPtr<nsPresContext> presContext;
-  nsresult rv = docShell->GetPresContext(getter_AddRefs(presContext));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
+  RefPtr<nsPresContext> presContext = docShell->GetPresContext();
   if (NS_WARN_IF(!presContext)) {
     return NS_ERROR_FAILURE;
   }
   nsCOMPtr<nsIWidget> widget = presContext->GetRootWidget();
   if (NS_WARN_IF(!widget)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -440,16 +436,17 @@ TextInputProcessor::BeginInputTransactio
     mDispatcher->EndInputTransaction(this);
     if (NS_WARN_IF(mDispatcher)) {
       // Forcibly initialize the members if we failed to end the input
       // transaction.
       UnlinkFromTextEventDispatcher();
     }
   }
 
+  nsresult rv = NS_OK;
   if (aForTests) {
     bool isAPZAware = gfxPrefs::TestEventsAsyncEnabled();
     rv = dispatcher->BeginTestInputTransaction(this, isAPZAware);
   } else {
     rv = dispatcher->BeginInputTransaction(this);
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/base/nsContentAreaDragDrop.cpp
+++ b/dom/base/nsContentAreaDragDrop.cpp
@@ -336,21 +336,19 @@ nsContentAreaDragDropDataProvider::GetFl
       return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsIFile> file;
     rv = destDirectory->Clone(getter_AddRefs(file));
     NS_ENSURE_SUCCESS(rv, rv);
 
     file->Append(targetFilename);
 
-    bool isPrivate;
-    aTransferable->GetIsPrivateData(&isPrivate);
+    bool isPrivate = aTransferable->GetIsPrivateData();
 
-    nsCOMPtr<nsIPrincipal> principal;
-    aTransferable->GetRequestingPrincipal(getter_AddRefs(principal));
+    nsCOMPtr<nsIPrincipal> principal = aTransferable->GetRequestingPrincipal();
     rv = SaveURIToFile(sourceURI, principal, file, isPrivate);
     // send back an nsIFile
     if (NS_SUCCEEDED(rv)) {
       CallQueryInterface(file, aData);
       *aDataLen = sizeof(nsIFile*);
     }
   }
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6623,24 +6623,21 @@ nsContentUtils::IsSubDocumentTabbable(ns
   }
 
   nsCOMPtr<nsIContentViewer> contentViewer;
   docShell->GetContentViewer(getter_AddRefs(contentViewer));
   if (!contentViewer) {
     return false;
   }
 
-  nsCOMPtr<nsIContentViewer> zombieViewer;
-  contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
-
   // If there are 2 viewers for the current docshell, that
   // means the current document may be a zombie document.
   // While load and pageshow events are dispatched, zombie viewer is the old,
   // to be hidden document.
-  if (zombieViewer) {
+  if (contentViewer->GetPreviousViewer()) {
     bool inOnLoad = false;
     docShell->GetIsExecutingOnLoadHandler(&inOnLoad);
     return inOnLoad;
   }
 
   return true;
 }
 
@@ -7149,18 +7146,17 @@ nsContentUtils::HasPluginWithUncontrolle
     return false;
   }
 
   nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aContent);
   if (!olc) {
     return false;
   }
 
-  RefPtr<nsNPAPIPluginInstance> plugin;
-  olc->GetPluginInstance(getter_AddRefs(plugin));
+  RefPtr<nsNPAPIPluginInstance> plugin = olc->GetPluginInstance();
   if (!plugin) {
     return false;
   }
 
   bool isWindowless = false;
   nsresult res = plugin->IsWindowless(&isWindowless);
   if (NS_FAILED(res)) {
     return false;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -238,19 +238,17 @@ nsPresContext*
 nsDOMWindowUtils::GetPresContext()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   if (!window)
     return nullptr;
   nsIDocShell *docShell = window->GetDocShell();
   if (!docShell)
     return nullptr;
-  RefPtr<nsPresContext> presContext;
-  docShell->GetPresContext(getter_AddRefs(presContext));
-  return presContext;
+  return docShell->GetPresContext();
 }
 
 nsIDocument*
 nsDOMWindowUtils::GetDocument()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   if (!window) {
     return nullptr;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12910,17 +12910,17 @@ nsIDocument::SetUserHasInteracted()
 
   mUserHasInteracted = true;
 
   nsCOMPtr<nsILoadInfo> loadInfo = mChannel ? mChannel->GetLoadInfo() : nullptr;
   if (loadInfo) {
     loadInfo->SetDocumentHasUserInteracted(true);
   }
 
-  MaybeAllowStorageForOpener();
+  MaybeAllowStorageForOpenerAfterUserInteraction();
 }
 
 void
 nsIDocument::NotifyUserGestureActivation()
 {
   // Activate this document and all documents up to the top level
   // content document.
   nsIDocument* doc = this;
@@ -12957,17 +12957,17 @@ nsIDocument::SetDocTreeHadPlayRevoked()
 {
   nsIDocument* topLevelDoc = GetTopLevelContentDocument();
   if (topLevelDoc) {
     topLevelDoc->mDocTreeHadPlayRevoked = true;
   }
 }
 
 void
-nsIDocument::MaybeAllowStorageForOpener()
+nsIDocument::MaybeAllowStorageForOpenerAfterUserInteraction()
 {
   if (StaticPrefs::network_cookie_cookieBehavior() !=
         nsICookieService::BEHAVIOR_REJECT_TRACKER) {
     return;
   }
 
   // This will probably change for project fission, but currently this document
   // and the opener are on the same process. In the future, we should make this
@@ -13015,17 +13015,17 @@ nsIDocument::MaybeAllowStorageForOpener(
       !nsContentUtils::IsThirdPartyWindowOrChannel(openerInner, nullptr,
                                                    nullptr)) {
     return;
   }
 
   // We don't care when the asynchronous work finishes here.
   Unused << AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(NodePrincipal(),
                                                                      openerInner,
-                                                                     AntiTrackingCommon::eHeuristic);
+                                                                     AntiTrackingCommon::eOpenerAfterUserInteraction);
 }
 
 namespace {
 
 // Documents can stay alive for days. We don't want to update the permission
 // value at any user-interaction, and, using a timer triggered any X seconds
 // should be good enough. 'X' is taken from
 // privacy.userInteraction.document.interval pref.
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -813,18 +813,17 @@ nsFrameLoader::MarginsChanged(uint32_t a
       if (cur->IsHTMLElement(nsGkAtoms::body)) {
         static_cast<HTMLBodyElement*>(cur)->ClearMappedServoStyle();
       }
     }
   }
 
   // Trigger a restyle if there's a prescontext
   // FIXME: This could do something much less expensive.
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (presContext)
     // rebuild, because now the same nsMappedAttributes* will produce
     // a different style
     presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
 }
 
 bool
 nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -234,16 +234,17 @@
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/NavigatorBinding.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/InstallTriggerBinding.h"
 #include "mozilla/dom/Report.h"
 #include "mozilla/dom/ReportingObserver.h"
+#include "mozilla/dom/SharedWorker.h"
 #include "mozilla/dom/ServiceWorker.h"
 #include "mozilla/dom/ServiceWorkerRegistration.h"
 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
 #include "mozilla/dom/U2F.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/Worklet.h"
 #ifdef HAVE_SIDEBAR
 #include "mozilla/dom/ExternalBinding.h"
@@ -1171,16 +1172,22 @@ nsGlobalWindowInner::FreeInnerObjects(bo
   NotifyDOMWindowDestroyed(this);
   if (auto* reporter = nsWindowMemoryReporter::Get()) {
     reporter->ObserveDOMWindowDetached(this);
   }
 
   // Kill all of the workers for this window.
   CancelWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Close();
+  }
+
   if (mTimeoutManager) {
     mTimeoutManager->ClearAllTimeouts();
   }
 
   if (mIdleTimer) {
     mIdleTimer->Cancel();
     mIdleTimer = nullptr;
   }
@@ -1319,16 +1326,18 @@ nsGlobalWindowInner::FreeInnerObjects(bo
 
   mPaintWorklet = nullptr;
 
   mExternal = nullptr;
   mInstallTrigger = nullptr;
 
   mPerformance = nullptr;
 
+  mSharedWorkers.Clear();
+
 #ifdef MOZ_WEBSPEECH
   mSpeechSynthesis = nullptr;
 #endif
 
   mParentTarget = nullptr;
 
   if (mCleanMessageManager) {
     MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
@@ -1429,17 +1438,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
     tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
       cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
     });
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
-
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
@@ -1523,16 +1532,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   // while unlinking.
 
   tmp->UpdateTopInnerWindow();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
   if (tmp->mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
   }
   if (tmp->mIndexedDB) {
     tmp->mIndexedDB->DisconnectFromWindow(tmp);
@@ -5944,16 +5954,22 @@ nsGlobalWindowInner::Suspend()
     for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
       ac->RemoveWindowListener(mEnabledSensors[i], this);
   }
   DisableGamepadUpdates();
   DisableVRUpdates();
 
   SuspendWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Suspend();
+  }
+
   SuspendIdleRequests();
 
   mTimeoutManager->Suspend();
 
   // Suspend all of the AudioContexts for this window
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     ErrorResult dummy;
     RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy);
@@ -6005,16 +6021,22 @@ nsGlobalWindowInner::Resume()
   mTimeoutManager->Resume();
 
   ResumeIdleRequests();
 
   // Resume all of the workers for this window.  We must do this
   // after timeouts since workers may have queued events that can trigger
   // a setTimeout().
   ResumeWorkersForWindow(this);
+
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Resume();
+  }
 }
 
 bool
 nsGlobalWindowInner::IsSuspended() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mSuspendDepth != 0;
 }
@@ -6039,16 +6061,22 @@ nsGlobalWindowInner::FreezeInternal()
   mFreezeDepth += 1;
   MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
   if (mFreezeDepth != 1) {
     return;
   }
 
   FreezeWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Freeze();
+  }
+
   mTimeoutManager->Freeze();
   if (mClientSource) {
     mClientSource->Freeze();
   }
 
   NotifyDOMWindowFrozen(this);
 }
 
@@ -6078,16 +6106,22 @@ nsGlobalWindowInner::ThawInternal()
 
   if (mClientSource) {
     mClientSource->Thaw();
   }
   mTimeoutManager->Thaw();
 
   ThawWorkersForWindow(this);
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>>::ForwardIterator
+    iter(mSharedWorkers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Thaw();
+  }
+
   NotifyDOMWindowThawed(this);
 }
 
 bool
 nsGlobalWindowInner::IsFrozen() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   bool frozen = mFreezeDepth != 0;
@@ -7923,16 +7957,34 @@ nsGlobalWindowInner::GetIntlUtils(ErrorR
 {
   if (!mIntlUtils) {
     mIntlUtils = new IntlUtils(this);
   }
 
   return mIntlUtils;
 }
 
+void
+nsGlobalWindowInner::StoreSharedWorker(SharedWorker* aSharedWorker)
+{
+  MOZ_ASSERT(aSharedWorker);
+  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
+
+  mSharedWorkers.AppendElement(aSharedWorker);
+}
+
+void
+nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker)
+{
+  MOZ_ASSERT(aSharedWorker);
+  MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
+
+  mSharedWorkers.RemoveElement(aSharedWorker);
+}
+
 mozilla::dom::TabGroup*
 nsPIDOMWindowInner::TabGroup()
 {
   return nsGlobalWindowInner::Cast(this)->TabGroupInner();
 }
 
 /* static */ already_AddRefed<nsGlobalWindowInner>
 nsGlobalWindowInner::Create(nsGlobalWindowOuter *aOuterWindow, bool aIsChrome)
@@ -8062,16 +8114,30 @@ nsPIDOMWindowInner::GetAutoplayPermissio
     window->mAutoplayPermissionManager =
       new AutoplayPermissionManager(nsGlobalWindowInner::Cast(window));
   }
   RefPtr<mozilla::AutoplayPermissionManager> manager =
     window->mAutoplayPermissionManager;
   return manager.forget();
 }
 
+void
+nsPIDOMWindowInner::SaveStorageAccessGranted(const nsACString& aPermissionKey)
+{
+  if (!HasStorageAccessGranted(aPermissionKey)) {
+    mStorageAccessGranted.AppendElement(aPermissionKey);
+  }
+}
+
+bool
+nsPIDOMWindowInner::HasStorageAccessGranted(const nsACString& aPermissionKey)
+{
+  return mStorageAccessGranted.Contains(aPermissionKey);
+}
+
 // XXX: Can we define this in a header instead of here?
 namespace mozilla {
 namespace dom {
 extern uint64_t
 NextWindowID();
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -114,16 +114,17 @@ class InstallTriggerImpl;
 class IntlUtils;
 class Location;
 class MediaQueryList;
 class OwningExternalOrWindowProxy;
 class Promise;
 class PostMessageEvent;
 struct RequestInit;
 class RequestOrUSVString;
+class SharedWorker;
 class Selection;
 class SpeechSynthesis;
 class TabGroup;
 class Timeout;
 class U2F;
 class VisualViewport;
 class VRDisplay;
 enum class VRDisplayEventReason : uint8_t;
@@ -707,16 +708,22 @@ public:
   GetPaintWorklet(mozilla::ErrorResult& aRv);
 
   void
   GetRegionalPrefsLocales(nsTArray<nsString>& aLocales);
 
   mozilla::dom::IntlUtils*
   GetIntlUtils(mozilla::ErrorResult& aRv);
 
+  void
+  StoreSharedWorker(mozilla::dom::SharedWorker* aSharedWorker);
+
+  void
+  ForgetSharedWorker(mozilla::dom::SharedWorker* aSharedWorker);
+
 public:
   void Alert(nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
   void Alert(const nsAString& aMessage,
              nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
   bool Confirm(const nsAString& aMessage,
                nsIPrincipal& aSubjectPrincipal,
@@ -1400,16 +1407,18 @@ protected:
   RefPtr<mozilla::dom::Storage> mLocalStorage;
   RefPtr<mozilla::dom::Storage> mSessionStorage;
 
   RefPtr<mozilla::EventListenerManager> mListenerManager;
   RefPtr<mozilla::dom::Location> mLocation;
   RefPtr<nsHistory>           mHistory;
   RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;
 
+  nsTObserverArray<RefPtr<mozilla::dom::SharedWorker>> mSharedWorkers;
+
   RefPtr<mozilla::dom::VisualViewport> mVisualViewport;
 
   nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
   // mTabChild is only ever populated in the content process.
   nsCOMPtr<nsITabChild>  mTabChild;
 
   uint32_t mSuspendDepth;
   uint32_t mFreezeDepth;
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -3107,79 +3107,74 @@ nsGlobalWindowOuter::SetNameOuter(const 
 
 // Helper functions used by many methods below.
 int32_t
 nsGlobalWindowOuter::DevToCSSIntPixels(int32_t px)
 {
   if (!mDocShell)
     return px; // assume 1:1
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (!presContext)
     return px;
 
   return presContext->DevPixelsToIntCSSPixels(px);
 }
 
 int32_t
 nsGlobalWindowOuter::CSSToDevIntPixels(int32_t px)
 {
   if (!mDocShell)
     return px; // assume 1:1
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (!presContext)
     return px;
 
   return presContext->CSSPixelsToDevPixels(px);
 }
 
 nsIntSize
 nsGlobalWindowOuter::DevToCSSIntPixels(nsIntSize px)
 {
   if (!mDocShell)
     return px; // assume 1:1
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (!presContext)
     return px;
 
   return nsIntSize(
       presContext->DevPixelsToIntCSSPixels(px.width),
       presContext->DevPixelsToIntCSSPixels(px.height));
 }
 
 nsIntSize
 nsGlobalWindowOuter::CSSToDevIntPixels(nsIntSize px)
 {
   if (!mDocShell)
     return px; // assume 1:1
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (!presContext)
     return px;
 
   return nsIntSize(
     presContext->CSSPixelsToDevPixels(px.width),
     presContext->CSSPixelsToDevPixels(px.height));
 }
 
 nsresult
 nsGlobalWindowOuter::GetInnerSize(CSSIntSize& aSize)
 {
   EnsureSizeAndPositionUpToDate();
 
   NS_ENSURE_STATE(mDocShell);
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 
   if (!presContext || !presShell) {
     aSize = CSSIntSize(0, 0);
     return NS_OK;
   }
 
   /*
@@ -3397,18 +3392,17 @@ nsGlobalWindowOuter::GetScreenXY(CallerT
   if (!treeOwnerAsWin) {
     aError.Throw(NS_ERROR_FAILURE);
     return CSSIntPoint(0, 0);
   }
 
   int32_t x = 0, y = 0;
   aError = treeOwnerAsWin->GetPosition(&x, &y); // LayoutDevice px values
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (!presContext) {
     return CSSIntPoint(x, y);
   }
 
   // Find the global desktop coordinate of the top-left of the screen.
   // We'll use this as a "fake origin" when converting to CSS px units,
   // to avoid overlapping coordinates in cases such as a hi-dpi screen
   // placed to the right of a lo-dpi screen on Windows. (Instead, there
@@ -3488,18 +3482,17 @@ nsGlobalWindowOuter::GetMozInnerScreenYO
 
 double
 nsGlobalWindowOuter::GetDevicePixelRatioOuter(CallerType aCallerType)
 {
   if (!mDocShell) {
     return 1.0;
   }
 
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
   if (!presContext) {
     return 1.0;
   }
 
   if (nsContentUtils::ResistFingerprinting(aCallerType)) {
     return 1.0;
   }
 
@@ -3642,18 +3635,17 @@ nsGlobalWindowOuter::SetDocShellWidthAnd
 
   return NS_OK;
 }
 
 // NOTE: Arguments to this function should have values in app units
 void
 nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
 {
-  RefPtr<nsPresContext> presContext;
-  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
 
   nsRect shellArea = presContext->GetVisibleArea();
   shellArea.SetHeight(aInnerHeight);
   shellArea.SetWidth(aInnerWidth);
 
   presContext->SetVisibleArea(shellArea);
 }
 
@@ -4833,17 +4825,17 @@ nsGlobalWindowOuter::FocusOuter(ErrorRes
       GetPrivateRoot() == this && mDoc) {
     nsIURI* ourURI = mDoc->GetDocumentURI();
     if (ourURI) {
       lookForPresShell = !NS_IsAboutBlank(ourURI);
     }
   }
 
   if (lookForPresShell) {
-    mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
+    presShell = mDocShell->GetEldestPresShell();
   }
 
   nsCOMPtr<nsIDocShellTreeItem> parentDsti;
   mDocShell->GetParent(getter_AddRefs(parentDsti));
 
   // set the parent's current focus to the frame containing this window.
   nsCOMPtr<nsPIDOMWindowOuter> parent =
     parentDsti ? parentDsti->GetWindow() : nullptr;
@@ -7232,17 +7224,17 @@ nsGlobalWindowOuter::MaybeAllowStorageFo
   }
   nsCOMPtr<nsIPrincipal> principal =
     BasePrincipal::CreateCodebasePrincipal(aURI,
       doc->NodePrincipal()->OriginAttributesRef());
 
   // We don't care when the asynchronous work finishes here.
   Unused << AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(principal,
                                                                      inner,
-                                                                     AntiTrackingCommon::eHeuristic);
+                                                                     AntiTrackingCommon::eOpener);
 }
 
 //*****************************************************************************
 // nsGlobalWindowOuter: Helper Functions
 //*****************************************************************************
 
 already_AddRefed<nsIDocShellTreeOwner>
 nsGlobalWindowOuter::GetTreeOwner()
@@ -7470,17 +7462,17 @@ nsGlobalWindowOuter::SetCursorOuter(cons
     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
     if (!nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
       return;
     }
   }
 
   RefPtr<nsPresContext> presContext;
   if (mDocShell) {
-    mDocShell->GetPresContext(getter_AddRefs(presContext));
+    presContext = mDocShell->GetPresContext();
   }
 
   if (presContext) {
     // Need root widget.
     nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
     if (!presShell) {
       aError.Throw(NS_ERROR_FAILURE);
       return;
@@ -7644,18 +7636,17 @@ nsGlobalWindowOuter::ReportLargeAllocSta
 
 // Helper called by methods that move/resize the window,
 // to ensure the presContext (if any) is aware of resolution
 // change that may happen in multi-monitor configuration.
 void
 nsGlobalWindowOuter::CheckForDPIChange()
 {
   if (mDocShell) {
-    RefPtr<nsPresContext> presContext;
-    mDocShell->GetPresContext(getter_AddRefs(presContext));
+    RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
     if (presContext) {
       if (presContext->DeviceContext()->CheckDPIChange()) {
         presContext->UIResolutionChanged();
       }
     }
   }
 }
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3977,17 +3977,17 @@ protected:
   void UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell = nullptr);
 
   // Helper for GetScrollingElement/IsScrollingElement.
   bool IsPotentiallyScrollable(mozilla::dom::HTMLBodyElement* aBody);
 
   // Return the same type parent docuement if exists, or return null.
   nsIDocument* GetSameTypeParentDocument();
 
-  void MaybeAllowStorageForOpener();
+  void MaybeAllowStorageForOpenerAfterUserInteraction();
 
   void MaybeStoreUserInteractionAsPermission();
 
   // Helpers for GetElementsByName.
   static bool MatchNameAttribute(mozilla::dom::Element* aElement,
                                  int32_t aNamespaceID,
                                  nsAtom* aAtom, void* aData);
   static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
--- a/dom/base/nsIImageLoadingContent.idl
+++ b/dom/base/nsIImageLoadingContent.idl
@@ -66,17 +66,17 @@ interface nsIImageLoadingContent : imgIN
   [notxpcom, nostdcall] void setLoadingEnabled(in boolean aEnabled);
 
   /**
    * Returns the image blocking status (@see nsIContentPolicy).  This
    * will always be an nsIContentPolicy REJECT_* status for cases when
    * the image was blocked.  This status always refers to the
    * CURRENT_REQUEST load.
    */
-  [noscript, infallible] readonly attribute short imageBlockingStatus;
+  [notxpcom, nostdcall] readonly attribute short imageBlockingStatus;
 
   /**
    * Used to register an image decoder observer.  Typically, this will
    * be a proxy for a frame that wants to paint the image.
    * Notifications from ongoing image loads will be passed to all
    * registered observers.  Notifications for all request types,
    * current and pending, will be passed through.
    *
@@ -162,23 +162,16 @@ interface nsIImageLoadingContent : imgIN
   /**
    * Enables/disables image state forcing. When |aForce| is true, we force
    * nsImageLoadingContent::ImageState() to return |aState|. Call again with |aForce|
    * as false to revert ImageState() to its original behaviour.
    */
   [notxpcom, nostdcall] void forceImageState(in boolean aForce, in unsigned long long aState);
 
   /**
-   * The intrinsic size and width of this content. May differ from actual image
-   * size due to things like responsive image density.
-   */
-  [noscript] readonly attribute unsigned long    naturalWidth;
-  [noscript] readonly attribute unsigned long    naturalHeight;
-
-  /**
    * Called by layout to announce when the frame associated with this content
    * has changed its visibility state.
    *
    * @param aNewVisibility    The new visibility state.
    * @param aNonvisibleAction A requested action if the frame has become
    *                          nonvisible. If Nothing(), no action is
    *                          requested. If DISCARD_IMAGES is specified, the
    *                          frame is requested to ask any images it's
--- a/dom/base/nsIObjectLoadingContent.idl
+++ b/dom/base/nsIObjectLoadingContent.idl
@@ -89,28 +89,21 @@ interface nsIObjectLoadingContent : nsIS
   /**
    * Gets the content type that corresponds to the give MIME type.  See the
    * constants above for the list of possible values.  If nothing else fits,
    * TYPE_NULL will be returned.
    */
   unsigned long getContentTypeForMIMEType(in AUTF8String aMimeType);
 
   /**
-   * Returns the base URI of the object as seen by plugins. This differs from
-   * the normal codebase in that it takes <param> tags and plugin-specific
-   * quirks into account.
-   */
-  [noscript] readonly attribute nsIURI baseURI;
-
-  /**
    * Returns the plugin instance if it has already been instantiated. This
    * will never instantiate the plugin and so is safe to call even when
    * content script must not execute.
    */
-  [noscript] readonly attribute nsNPAPIPluginInstancePtr pluginInstance;
+  [notxpcom,nostdcall] readonly attribute nsNPAPIPluginInstancePtr pluginInstance;
 
   /**
    * Tells the content about an associated object frame.
    * This can be called multiple times for different frames.
    *
    * This is noscript because this is an internal method that will go away, and
    * because nsIObjectFrame is unscriptable.
    */
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -384,22 +384,20 @@ nsImageLoadingContent::MaybeForceSyncDec
 
   if (imageFrame) {
     imageFrame->SetForceSyncDecoding(forceSync);
   } else {
     svgImageFrame->SetForceSyncDecoding(forceSync);
   }
 }
 
-NS_IMETHODIMP
-nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
+int16_t
+nsImageLoadingContent::GetImageBlockingStatus()
 {
-  MOZ_ASSERT(aStatus, "Null out param");
-  *aStatus = ImageBlockingStatus();
-  return NS_OK;
+  return ImageBlockingStatus();
 }
 
 static void
 ReplayImageStatus(imgIRequest* aRequest, imgINotificationObserver* aObserver)
 {
   if (!aRequest) {
     return;
   }
@@ -1100,54 +1098,46 @@ nsImageLoadingContent::LoadImage(nsIURI*
 void
 nsImageLoadingContent::ForceImageState(bool aForce,
                                        EventStates::InternalType aState)
 {
   mIsImageStateForced = aForce;
   mForcedImageState = EventStates(aState);
 }
 
-NS_IMETHODIMP
-nsImageLoadingContent::GetNaturalWidth(uint32_t* aNaturalWidth)
+uint32_t
+nsImageLoadingContent::NaturalWidth()
 {
-  NS_ENSURE_ARG_POINTER(aNaturalWidth);
-
   nsCOMPtr<imgIContainer> image;
   if (mCurrentRequest) {
     mCurrentRequest->GetImage(getter_AddRefs(image));
   }
 
   int32_t width;
   if (image && NS_SUCCEEDED(image->GetWidth(&width))) {
-    *aNaturalWidth = width;
-  } else {
-    *aNaturalWidth = 0;
+    return width;
   }
 
-  return NS_OK;
+  return 0;
 }
 
-NS_IMETHODIMP
-nsImageLoadingContent::GetNaturalHeight(uint32_t* aNaturalHeight)
+uint32_t
+nsImageLoadingContent::NaturalHeight()
 {
-  NS_ENSURE_ARG_POINTER(aNaturalHeight);
-
   nsCOMPtr<imgIContainer> image;
   if (mCurrentRequest) {
     mCurrentRequest->GetImage(getter_AddRefs(image));
   }
 
   int32_t height;
   if (image && NS_SUCCEEDED(image->GetHeight(&height))) {
-    *aNaturalHeight = height;
-  } else {
-    *aNaturalHeight = 0;
+    return height;
   }
 
-  return NS_OK;
+  return 0;
 }
 
 EventStates
 nsImageLoadingContent::ImageState() const
 {
   if (mIsImageStateForced) {
     return mForcedImageState;
   }
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -229,16 +229,20 @@ protected:
   static nsContentPolicyType PolicyTypeForLoad(ImageLoadType aImageLoadType);
 
   void AsyncEventRunning(mozilla::AsyncEventDispatcher* aEvent);
 
   // Get ourselves as an nsIContent*.  Not const because some of the callers
   // want a non-const nsIContent.
   virtual nsIContent* AsContent() = 0;
 
+  // Hooks for subclasses to call to get the intrinsic width and height.
+  uint32_t NaturalWidth();
+  uint32_t NaturalHeight();
+
   enum class ImageDecodingType : uint8_t {
     Auto,
     Async,
     Sync,
   };
 
   static const nsAttrValue::EnumTable kDecodingTable[];
   static const nsAttrValue::EnumTable* kDecodingTableDefault;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -394,18 +394,17 @@ bool
 NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
                      const ErrorEventInit &aErrorEventInit,
                      nsEventStatus *aStatus)
 {
   bool called = false;
   nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aScriptGlobal));
   nsIDocShell *docShell = win ? win->GetDocShell() : nullptr;
   if (docShell) {
-    RefPtr<nsPresContext> presContext;
-    docShell->GetPresContext(getter_AddRefs(presContext));
+    RefPtr<nsPresContext> presContext = docShell->GetPresContext();
 
     static int32_t errorDepth; // Recursion prevention
     ++errorDepth;
 
     if (errorDepth < 2) {
       // Dispatch() must be synchronous for the recursion block
       // (errorDepth) to work.
       RefPtr<ErrorEvent> event =
@@ -444,18 +443,17 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     // First, notify the DOM that we have a script error, but only if
     // our window is still the current inner.
     JS::RootingContext* rootingCx = RootingCx();
     if (win->IsCurrentInnerWindow() && win->GetDocShell() && !sHandlingScriptError) {
       AutoRestore<bool> recursionGuard(sHandlingScriptError);
       sHandlingScriptError = true;
 
-      RefPtr<nsPresContext> presContext;
-      win->GetDocShell()->GetPresContext(getter_AddRefs(presContext));
+      RefPtr<nsPresContext> presContext = win->GetDocShell()->GetPresContext();
 
       RootedDictionary<ErrorEventInit> init(rootingCx);
       init.mCancelable = true;
       init.mFilename = mReport->mFileName;
       init.mBubbles = true;
 
       NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
       if (!mReport->mIsMuted) {
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -534,20 +534,18 @@ nsObjectLoadingContent::MakePluginListen
   }
   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
   if (!pluginHost) {
     MOZ_ASSERT_UNREACHABLE("No pluginHost");
     return false;
   }
   NS_ASSERTION(!mFinalListener, "overwriting a final listener");
   nsresult rv;
-  RefPtr<nsNPAPIPluginInstance> inst;
+  RefPtr<nsNPAPIPluginInstance> inst = mInstanceOwner->GetInstance();
   nsCOMPtr<nsIStreamListener> finalListener;
-  rv = mInstanceOwner->GetInstance(getter_AddRefs(inst));
-  NS_ENSURE_SUCCESS(rv, false);
   rv = pluginHost->NewPluginStreamListener(mURI, inst,
                                            getter_AddRefs(finalListener));
   NS_ENSURE_SUCCESS(rv, false);
   mFinalListener = finalListener;
   return true;
 }
 
 // Helper to spawn the frameloader.
@@ -750,35 +748,30 @@ nsObjectLoadingContent::InstantiatePlugi
 
   if (!mInstantiating || NS_FAILED(rv)) {
     LOG(("OBJLC [%p]: Plugin instantiation failed or re-entered, "
          "killing old instance", this));
     // XXX(johns): This needs to be de-duplicated with DoStopPlugin, but we
     //             don't want to touch the protochain or delayed stop.
     //             (Bug 767635)
     if (newOwner) {
-      RefPtr<nsNPAPIPluginInstance> inst;
-      newOwner->GetInstance(getter_AddRefs(inst));
+      RefPtr<nsNPAPIPluginInstance> inst = newOwner->GetInstance();
       newOwner->SetFrame(nullptr);
       if (inst) {
         pluginHost->StopPluginInstance(inst);
       }
       newOwner->Destroy();
     }
     return NS_OK;
   }
 
   mInstanceOwner = newOwner;
 
   if (mInstanceOwner) {
-    RefPtr<nsNPAPIPluginInstance> inst;
-    rv = mInstanceOwner->GetInstance(getter_AddRefs(inst));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+    RefPtr<nsNPAPIPluginInstance> inst = mInstanceOwner->GetInstance();
 
     rv = inst->GetRunID(&mRunID);
     mHasRunID = NS_SUCCEEDED(rv);
   }
 
   // Ensure the frame did not change during instantiation re-entry (common).
   // HasNewFrame would not have mInstanceOwner yet, so the new frame would be
   // dangling. (Bug 854082)
@@ -789,18 +782,17 @@ nsObjectLoadingContent::InstantiatePlugi
     // Bug 870216 - Adobe Reader renders with incorrect dimensions until it gets
     // a second SetWindow call. This is otherwise redundant.
     mInstanceOwner->CallSetWindow();
   }
 
   // Set up scripting interfaces.
   NotifyContentObjectWrapper();
 
-  RefPtr<nsNPAPIPluginInstance> pluginInstance;
-  GetPluginInstance(getter_AddRefs(pluginInstance));
+  RefPtr<nsNPAPIPluginInstance> pluginInstance = GetPluginInstance();
   if (pluginInstance) {
     nsCOMPtr<nsIPluginTag> pluginTag;
     pluginHost->GetPluginTagForInstance(pluginInstance,
                                         getter_AddRefs(pluginTag));
 
 
     uint32_t blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
     pluginTag->GetBlocklistState(&blockState);
@@ -1184,43 +1176,34 @@ nsObjectLoadingContent::HasNewFrame(nsIO
   // Otherwise, we're just changing frames
   // Set up relationship between instance owner and frame.
   nsPluginFrame *objFrame = static_cast<nsPluginFrame*>(aFrame);
   mInstanceOwner->SetFrame(objFrame);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
+nsNPAPIPluginInstance*
+nsObjectLoadingContent::GetPluginInstance()
 {
-  *aInstance = nullptr;
-
   if (!mInstanceOwner) {
-    return NS_OK;
+    return nullptr;
   }
 
-  return mInstanceOwner->GetInstance(aInstance);
+  return mInstanceOwner->GetInstance();
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
                                                   uint32_t* aType)
 {
   *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType), false);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsObjectLoadingContent::GetBaseURI(nsIURI **aResult)
-{
-  NS_IF_ADDREF(*aResult = mBaseURI);
-  return NS_OK;
-}
-
 // nsIInterfaceRequestor
 // We use a shim class to implement this so that JS consumers still
 // see an interface requestor even though WebIDL bindings don't expose
 // that stuff.
 class ObjectInterfaceRequestorShim final : public nsIInterfaceRequestor,
                                            public nsIChannelEventSink,
                                            public nsIStreamListener
 {
@@ -2823,19 +2806,18 @@ nsObjectLoadingContent::PluginCrashed(ns
                              submittedCrashReport);
   nsresult rv = NS_DispatchToCurrentThread(ev);
   if (NS_FAILED(rv)) {
     NS_WARNING("failed to dispatch nsPluginCrashedEvent");
   }
   return NS_OK;
 }
 
-nsresult
-nsObjectLoadingContent::ScriptRequestPluginInstance(JSContext* aCx,
-                                                    nsNPAPIPluginInstance **aResult)
+nsNPAPIPluginInstance*
+nsObjectLoadingContent::ScriptRequestPluginInstance(JSContext* aCx)
 {
   // The below methods pull the cx off the stack, so make sure they match.
   //
   // NB: Sometimes there's a null cx on the stack, in which case |cx| is the
   // safe JS context. But in that case, IsCallerChrome() will return true,
   // so the ensuing expression is short-circuited.
   // XXXbz the NB comment above doesn't really make sense.  At the moment, all
   // the callers to this except maybe SetupProtoChain have a useful JSContext*
@@ -2845,18 +2827,16 @@ nsObjectLoadingContent::ScriptRequestPlu
                 aCx == nsContentUtils::GetCurrentJSContext());
   bool callerIsContentJS = (nsContentUtils::GetCurrentJSContext() &&
                             !nsContentUtils::IsCallerChrome() &&
                             !nsContentUtils::IsCallerContentXBL());
 
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
-  *aResult = nullptr;
-
   // The first time content script attempts to access placeholder content, fire
   // an event.  Fallback types >= eFallbackClickToPlay are plugin-replacement
   // types, see header.
   if (callerIsContentJS && !mScriptRequested &&
       InActiveDocument(thisContent) && mType == eType_Null &&
       mFallbackType >= eFallbackClickToPlay) {
     nsCOMPtr<nsIRunnable> ev =
       new nsSimplePluginEvent(thisContent,
@@ -2870,21 +2850,21 @@ nsObjectLoadingContent::ScriptRequestPlu
              nsContentUtils::IsSafeToRunScript() &&
              InActiveDocument(thisContent)) {
     // If we're configured as a plugin in an active document and it's safe to
     // run scripts right now, try spawning synchronously
     SyncStartPluginInstance();
   }
 
   if (mInstanceOwner) {
-    return mInstanceOwner->GetInstance(aResult);
+    return mInstanceOwner->GetInstance();
   }
 
   // Note that returning a null plugin is expected (and happens often)
-  return NS_OK;
+  return nullptr;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::SyncStartPluginInstance()
 {
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Must be able to run script in order to instantiate a plugin instance!");
 
@@ -3022,18 +3002,17 @@ nsObjectLoadingContent::DoStopPlugin(nsP
 
   RefPtr<nsPluginInstanceOwner> kungFuDeathGrip(aInstanceOwner);
   if (mType == eType_FakePlugin) {
     if (mFrameLoader) {
       mFrameLoader->Destroy();
       mFrameLoader = nullptr;
     }
   } else {
-    RefPtr<nsNPAPIPluginInstance> inst;
-    aInstanceOwner->GetInstance(getter_AddRefs(inst));
+    RefPtr<nsNPAPIPluginInstance> inst = aInstanceOwner->GetInstance();
     if (inst) {
 #if defined(XP_MACOSX)
       aInstanceOwner->HidePluginWindow();
 #endif
 
       RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
       NS_ASSERTION(pluginHost, "No plugin host?");
       pluginHost->StopPluginInstance(inst);
@@ -3572,31 +3551,27 @@ nsObjectLoadingContent::SetupProtoChain(
   // We get called on random realms here for some reason
   // (perhaps because WrapObject can happen on a random realm?)
   // so make sure to enter the realm of aObject.
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
 
   MOZ_ASSERT(IsDOMObject(aObject));
   JSAutoRealm ar(aCx, aObject);
 
-  RefPtr<nsNPAPIPluginInstance> pi;
-  nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
-  if (NS_FAILED(rv)) {
-    return;
-  }
+  RefPtr<nsNPAPIPluginInstance> pi = ScriptRequestPluginInstance(aCx);
 
   if (!pi) {
     // No plugin around for this object.
     return;
   }
 
   JS::Rooted<JSObject*> pi_obj(aCx); // XPConnect-wrapped peer object, when we get it.
   JS::Rooted<JSObject*> pi_proto(aCx); // 'pi.__proto__'
 
-  rv = GetPluginJSObject(aCx, pi, &pi_obj, &pi_proto);
+  nsresult rv = GetPluginJSObject(aCx, pi, &pi_obj, &pi_proto);
   if (NS_FAILED(rv)) {
     return;
   }
 
   if (!pi_obj) {
     // Didn't get a plugin instance JSObject, nothing we can do then.
     return;
   }
@@ -3741,22 +3716,17 @@ nsObjectLoadingContent::TeardownProtoCha
 
 bool
 nsObjectLoadingContent::DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                                   JS::Handle<jsid> aId,
                                   JS::MutableHandle<JS::PropertyDescriptor> aDesc)
 {
   // We don't resolve anything; we just try to make sure we're instantiated.
   // This purposefully does not fire for chrome/xray resolves, see bug 967694
-
-  RefPtr<nsNPAPIPluginInstance> pi;
-  nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
-  if (NS_FAILED(rv)) {
-    return mozilla::dom::Throw(aCx, rv);
-  }
+  Unused << ScriptRequestPluginInstance(aCx);
   return true;
 }
 
 /* static */
 bool
 nsObjectLoadingContent::MayResolve(jsid aId)
 {
   // We can resolve anything, really.
@@ -3767,18 +3737,17 @@ void
 nsObjectLoadingContent::GetOwnPropertyNames(JSContext* aCx,
                                             JS::AutoIdVector& /* unused */,
                                             bool /* unused */,
                                             ErrorResult& aRv)
 {
   // Just like DoResolve, just make sure we're instantiated.  That will do
   // the work our Enumerate hook needs to do.  This purposefully does not fire
   // for xray resolves, see bug 967694
-  RefPtr<nsNPAPIPluginInstance> pi;
-  aRv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
+  Unused << ScriptRequestPluginInstance(aCx);
 }
 
 void
 nsObjectLoadingContent::MaybeFireErrorEvent()
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   // Queue a task to fire an error event if we're an <object> element.  The
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -614,18 +614,17 @@ class nsObjectLoadingContent : public ns
 
     private:
       // We store an nsIObjectLoadingContent because we can
       // unambiguously refcount that.
       RefPtr<nsIObjectLoadingContent> mContent;
     };
 
     // Utility getter for getting our nsNPAPIPluginInstance in a safe way.
-    nsresult ScriptRequestPluginInstance(JSContext* aCx,
-                                         nsNPAPIPluginInstance** aResult);
+    nsNPAPIPluginInstance* ScriptRequestPluginInstance(JSContext* aCx);
 
     // Utility method for getting our plugin JSObject
     static nsresult GetPluginJSObject(JSContext *cx,
                                       nsNPAPIPluginInstance *plugin_inst,
                                       JS::MutableHandle<JSObject*> plugin_obj,
                                       JS::MutableHandle<JSObject*> plugin_proto);
 
     // Utility for firing an error event, if we're an <object>.
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -641,16 +641,22 @@ public:
   UnregisterReportingObserver(mozilla::dom::ReportingObserver* aObserver);
 
   void
   BroadcastReport(mozilla::dom::Report* aReport);
 
   void
   NotifyReportingObservers();
 
+  void
+  SaveStorageAccessGranted(const nsACString& aPermissionKey);
+
+  bool
+  HasStorageAccessGranted(const nsACString& aPermissionKey);
+
 protected:
   void CreatePerformanceObjectIfNeeded();
 
   // Lazily instantiate an about:blank document if necessary, and if
   // we have what it takes to do so.
   void MaybeCreateDoc();
 
   void SetChromeEventHandlerInternal(mozilla::dom::EventTarget* aChromeEventHandler) {
@@ -739,16 +745,21 @@ protected:
 
   // The event dispatch code sets and unsets this while keeping
   // the event object alive.
   mozilla::dom::Event* mEvent;
 
   // List of Report objects for ReportingObservers.
   nsTArray<RefPtr<mozilla::dom::ReportingObserver>> mReportingObservers;
   nsTArray<RefPtr<mozilla::dom::Report>> mReportRecords;
+
+  // This is a list of storage access granted for the current window. These are
+  // also set as permissions, but it could happen that we need to access them
+  // synchronously in this context, and for this, we need a copy here.
+  nsTArray<nsCString> mStorageAccessGranted;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowInner, NS_PIDOMWINDOWINNER_IID)
 
 class nsPIDOMWindowOuter : public mozIDOMWindowProxy
 {
 protected:
   explicit nsPIDOMWindowOuter(uint64_t aWindowID);
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5283,17 +5283,17 @@ CanvasRenderingContext2D::DrawWindow(nsG
   EnsureTarget(discardContent ? &drawRect : nullptr);
   if (!IsTargetValid()) {
     return;
   }
 
   RefPtr<nsPresContext> presContext;
   nsIDocShell* docshell = aWindow.GetDocShell();
   if (docshell) {
-    docshell->GetPresContext(getter_AddRefs(presContext));
+    presContext = docshell->GetPresContext();
   }
   if (!presContext) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   nscolor backgroundColor;
   if (!ParseColor(aBgColor, &backgroundColor)) {
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -1141,18 +1141,17 @@ DataTransfer::GetTransferable(uint32_t a
 bool
 DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
                                  nsISupports** aSupports,
                                  uint32_t* aLength) const
 {
   *aSupports = nullptr;
   *aLength = 0;
 
-  uint16_t type;
-  aVariant->GetDataType(&type);
+  uint16_t type = aVariant->GetDataType();
   if (type == nsIDataType::VTYPE_INTERFACE ||
       type == nsIDataType::VTYPE_INTERFACE_IS) {
     nsCOMPtr<nsISupports> data;
     if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data)))) {
       return false;
     }
 
     nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4354,18 +4354,17 @@ EventStateManager::NotifyMouseOut(Widget
 
   if (wrapper->mLastOverFrame) {
     // if the frame is associated with a subdocument,
     // tell the subdocument that we're moving out of it
     nsSubDocumentFrame* subdocFrame = do_QueryFrame(wrapper->mLastOverFrame.GetFrame());
     if (subdocFrame) {
       nsIDocShell* docshell = subdocFrame->GetDocShell();
       if (docshell) {
-        RefPtr<nsPresContext> presContext;
-        docshell->GetPresContext(getter_AddRefs(presContext));
+        RefPtr<nsPresContext> presContext = docshell->GetPresContext();
 
         if (presContext) {
           EventStateManager* kidESM = presContext->EventStateManager();
           // Not moving into any element in this subdocument
           kidESM->NotifyMouseOut(aMouseEvent, nullptr);
         }
       }
     }
@@ -5825,22 +5824,21 @@ EventStateManager::DoContentCommandEvent
 
             nsCOMPtr<nsITransferable> transferable = aEvent->mTransferable;
             IPCDataTransfer ipcDataTransfer;
             ContentParent* cp = remote->Manager()->AsContentParent();
             nsContentUtils::TransferableToIPCTransferable(transferable,
                                                           &ipcDataTransfer,
                                                           false, nullptr,
                                                           cp);
-            bool isPrivateData = false;
-            transferable->GetIsPrivateData(&isPrivateData);
-            nsCOMPtr<nsIPrincipal> requestingPrincipal;
-            transferable->GetRequestingPrincipal(getter_AddRefs(requestingPrincipal));
-            nsContentPolicyType contentPolicyType = nsIContentPolicy::TYPE_OTHER;
-            transferable->GetContentPolicyType(&contentPolicyType);
+            bool isPrivateData = transferable->GetIsPrivateData();
+            nsCOMPtr<nsIPrincipal> requestingPrincipal =
+              transferable->GetRequestingPrincipal();
+            nsContentPolicyType contentPolicyType =
+              transferable->GetContentPolicyType();
             remote->SendPasteTransferable(ipcDataTransfer, isPrivateData,
                                           IPC::Principal(requestingPrincipal),
                                           contentPolicyType);
             rv = NS_OK;
           } else {
             nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
             NS_ENSURE_STATE(commandController);
 
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -1801,18 +1801,17 @@ IMEContentObserver::AChangeEvent::IsSafe
 /******************************************************************************
  * mozilla::IMEContentObserver::IMENotificationSender
  ******************************************************************************/
 
 void
 IMEContentObserver::IMENotificationSender::Dispatch(nsIDocShell* aDocShell)
 {
   if (XRE_IsContentProcess() && aDocShell) {
-    RefPtr<nsPresContext> presContext;
-    aDocShell->GetPresContext(getter_AddRefs(presContext));
+    RefPtr<nsPresContext> presContext = aDocShell->GetPresContext();
     if (presContext) {
       nsRefreshDriver* refreshDriver = presContext->RefreshDriver();
       if (refreshDriver) {
         refreshDriver->AddEarlyRunner(this);
         return;
       }
     }
   }
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -280,18 +280,17 @@ TouchEvent::PrefEnabled(nsIDocShell* aDo
           CrashReporter::Annotation::HasDeviceTouchScreen, enabled);
         firstTime = false;
       }
 
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
       if (enabled && aDocShell) {
         // APZ might be disabled on this particular widget, in which case
         // TouchEvent support will also be disabled. Try to detect that.
-        RefPtr<nsPresContext> pc;
-        aDocShell->GetPresContext(getter_AddRefs(pc));
+        RefPtr<nsPresContext> pc = aDocShell->GetPresContext();
         if (pc && pc->GetRootWidget()) {
           enabled &= pc->GetRootWidget()->AsyncPanZoomEnabled();
         }
       }
 #endif
     } else {
       enabled = !!sPrefCacheValue;
     }
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -28,16 +28,17 @@
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/FetchDriver.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/MutableBlobStreamListener.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/Telemetry.h"
 
 #include "BodyExtractor.h"
 #include "EmptyBody.h"
@@ -901,17 +902,17 @@ WorkerFetchResolver::FlushConsoleReport(
   if (worker->IsServiceWorker()) {
     // Flush to service worker
     mReporter->FlushReportsToConsoleForServiceWorkerScope(worker->ServiceWorkerScope());
     return;
   }
 
   if (worker->IsSharedWorker()) {
     // Flush to shared worker
-    worker->FlushReportsToSharedWorkers(mReporter);
+    worker->GetRemoteWorkerController()->FlushReportsOnMainThread(mReporter);
     return;
   }
 
   // Flush to dedicated worker
   mReporter->FlushConsoleReports(worker->GetLoadGroup());
 }
 
 nsresult
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -753,60 +753,34 @@ HTMLImageElement::Image(const GlobalObje
         return nullptr;
       }
     }
   }
 
   return img.forget();
 }
 
-NS_IMETHODIMP
-HTMLImageElement::GetNaturalHeight(uint32_t* aNaturalHeight)
-{
-  *aNaturalHeight = NaturalHeight();
-  return NS_OK;
-}
-
 uint32_t
 HTMLImageElement::NaturalHeight()
 {
-  uint32_t height;
-  nsresult rv = nsImageLoadingContent::GetNaturalHeight(&height);
-
-  if (NS_FAILED(rv)) {
-    MOZ_ASSERT(false, "GetNaturalHeight should not fail");
-    return 0;
-  }
+  uint32_t height = nsImageLoadingContent::NaturalHeight();
 
   if (mResponsiveSelector) {
     double density = mResponsiveSelector->GetSelectedImageDensity();
     MOZ_ASSERT(density >= 0.0);
     height = NSToIntRound(double(height) / density);
   }
 
   return height;
 }
 
-NS_IMETHODIMP
-HTMLImageElement::GetNaturalWidth(uint32_t* aNaturalWidth)
-{
-  *aNaturalWidth = NaturalWidth();
-  return NS_OK;
-}
-
 uint32_t
 HTMLImageElement::NaturalWidth()
 {
-  uint32_t width;
-  nsresult rv = nsImageLoadingContent::GetNaturalWidth(&width);
-
-  if (NS_FAILED(rv)) {
-    MOZ_ASSERT(false, "GetNaturalWidth should not fail");
-    return 0;
-  }
+  uint32_t width = nsImageLoadingContent::NaturalWidth();
 
   if (mResponsiveSelector) {
     double density = mResponsiveSelector->GetSelectedImageDensity();
     MOZ_ASSERT(density >= 0.0);
     width = NSToIntRound(double(width) / density);
   }
 
   return width;
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -82,21 +82,16 @@ public:
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
 
   virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 
   nsresult CopyInnerTo(HTMLImageElement* aDest);
 
   void MaybeLoadImage(bool aAlwaysForceLoad);
 
-  // Overrides for nsImageLoadingContent's GetNaturalHeight/Width, since we
-  // handle responsive scaling in the element's version of these methods.
-  NS_IMETHOD GetNaturalHeight(uint32_t* aNaturalHeight) override;
-  NS_IMETHOD GetNaturalWidth(uint32_t* aNaturalWidth) override;
-
   bool IsMap()
   {
     return GetBoolAttr(nsGkAtoms::ismap);
   }
   void SetIsMap(bool aIsMap, ErrorResult& aError)
   {
     SetHTMLBoolAttr(nsGkAtoms::ismap, aIsMap, aError);
   }
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -407,20 +407,20 @@ HTMLObjectElement::SubmitNamesValues(HTM
 
   nsIObjectFrame *objFrame = do_QueryFrame(frame);
   if (!objFrame) {
     // No frame, nothing to submit.
 
     return NS_OK;
   }
 
-  RefPtr<nsNPAPIPluginInstance> pi;
-  objFrame->GetPluginInstance(getter_AddRefs(pi));
-  if (!pi)
+  RefPtr<nsNPAPIPluginInstance> pi = objFrame->GetPluginInstance();
+  if (!pi) {
     return NS_OK;
+  }
 
   nsAutoString value;
   nsresult rv = pi->GetFormValue(value);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return aFormSubmission->AddNameValuePair(name, value);
 }
 
--- a/dom/html/PluginDocument.cpp
+++ b/dom/html/PluginDocument.cpp
@@ -266,18 +266,17 @@ PluginDocument::CreateSyntheticPluginDoc
 NS_IMETHODIMP
 PluginDocument::Print()
 {
   NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE);
 
   nsIObjectFrame* objectFrame =
     do_QueryFrame(mPluginContent->GetPrimaryFrame());
   if (objectFrame) {
-    RefPtr<nsNPAPIPluginInstance> pi;
-    objectFrame->GetPluginInstance(getter_AddRefs(pi));
+    RefPtr<nsNPAPIPluginInstance> pi = objectFrame->GetPluginInstance();
     if (pi) {
       NPPrint npprint;
       npprint.mode = NP_FULL;
       npprint.print.fullPrint.pluginPrinted = false;
       npprint.print.fullPrint.printOne = false;
       npprint.print.fullPrint.platformPrint = nullptr;
 
       pi->Print(&npprint);
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -318,18 +318,17 @@ nsGenericHTMLFrameElement::AfterSetAttr(
         nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(docshell);
         if (scrollable) {
           int32_t cur;
           scrollable->GetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, &cur);
           int32_t val = MapScrollingAttribute(aValue);
           if (cur != val) {
             scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, val);
             scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, val);
-            RefPtr<nsPresContext> presContext;
-            docshell->GetPresContext(getter_AddRefs(presContext));
+            RefPtr<nsPresContext> presContext = docshell->GetPresContext();
             nsIPresShell* shell = presContext ? presContext->GetPresShell() : nullptr;
             nsIFrame* rootScroll = shell ? shell->GetRootScrollFrame() : nullptr;
             if (rootScroll) {
               shell->FrameNeedsReflow(rootScroll, nsIPresShell::eStyleChange,
                                       NS_FRAME_IS_DIRTY);
             }
           }
         }
@@ -362,20 +361,20 @@ nsGenericHTMLFrameElement::AfterMaybeCha
                                                 const nsAttrValueOrString* aValue,
                                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                                 bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::src) {
       mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
           this, aValue ? aValue->String() : EmptyString(), aMaybeScriptedPrincipal);
-      if (aValue && (!IsHTMLElement(nsGkAtoms::iframe) ||
-          !HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc))) {
-        // Don't propagate error here. The attribute was successfully set,
-        // that's what we should reflect.
+      if (!IsHTMLElement(nsGkAtoms::iframe) ||
+          !HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc)) {
+        // Don't propagate error here. The attribute was successfully
+        // set or removed; that's what we should reflect.
         LoadSrc();
       }
     } else if (aName == nsGkAtoms::name) {
       // Propagate "name" to the docshell to make browsing context names live,
       // per HTML5.
       nsIDocShell* docShell = mFrameLoader ? mFrameLoader->GetExistingDocShell()
                                            : nullptr;
       if (docShell) {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -39,16 +39,17 @@
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/FileCreatorHelper.h"
 #include "mozilla/dom/GetFilesHelper.h"
 #include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/MemoryReportRequest.h"
 #include "mozilla/dom/PLoginReputationChild.h"
 #include "mozilla/dom/PushNotifier.h"
+#include "mozilla/dom/RemoteWorkerService.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
 #include "mozilla/dom/TabGroup.h"
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/dom/URLClassifierChild.h"
 #include "mozilla/dom/WorkerDebugger.h"
 #include "mozilla/dom/WorkerDebuggerManager.h"
 #include "mozilla/dom/ipc/SharedMap.h"
 #include "mozilla/gfx/gfxVars.h"
@@ -1220,16 +1221,18 @@ ContentChild::InitXPCOM(const XPCOMInitD
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actorChild)) {
     MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
     return;
   }
 
   ClientManager::Startup();
 
+  RemoteWorkerService::Initialize();
+
   nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!svc) {
     NS_WARNING("Couldn't acquire console service");
     return;
   }
 
   mConsoleListener = new ConsoleListener(this);
   if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1857,16 +1857,21 @@ ContentParent::TryToRecycle()
 
 bool
 ContentParent::ShouldKeepProcessAlive() const
 {
   if (IsForJSPlugin()) {
     return true;
   }
 
+  // If we have active workers, we need to stay alive.
+  if (mRemoteWorkerActors) {
+    return true;
+  }
+
   if (!sBrowserContentParents) {
     return false;
   }
 
   // If we have already been marked as troubled/dead, don't prevent shutdown.
   if (!IsAvailable()) {
     return false;
   }
@@ -2380,16 +2385,17 @@ ContentParent::ContentParent(ContentPare
   , mSubprocess(nullptr)
   , mLaunchTS(TimeStamp::Now())
   , mActivateTS(TimeStamp::Now())
   , mOpener(aOpener)
   , mRemoteType(aRemoteType)
   , mChildID(gContentChildID++)
   , mGeolocationWatchID(-1)
   , mJSPluginID(aJSPluginID)
+  , mRemoteWorkerActors(0)
   , mNumDestroyingTabs(0)
   , mIsAvailable(true)
   , mIsAlive(true)
   , mIsForBrowser(!mRemoteType.IsEmpty())
   , mRecordReplayState(aRecordReplayState)
   , mRecordingFile(aRecordingFile)
   , mCalledClose(false)
   , mCalledKillHard(false)
@@ -6159,8 +6165,37 @@ ContentParent::RecvSetOpenerBrowsingCont
     return IPC_OK();
   }
 
   RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerContextId);
   context->SetOpener(opener);
 
   return IPC_OK();
 }
+
+void
+ContentParent::RegisterRemoteWorkerActor()
+{
+  ++mRemoteWorkerActors;
+}
+
+void
+ContentParent::UnregisterRemoveWorkerActor()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (--mRemoteWorkerActors) {
+    return;
+  }
+
+  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+  if (!cpm->GetTabParentCountByProcessId(ChildID()) &&
+      !ShouldKeepProcessAlive() &&
+      !TryToRecycle()) {
+    // In the case of normal shutdown, send a shutdown message to child to
+    // allow it to perform shutdown tasks.
+    MessageLoop::current()->PostTask(
+      NewRunnableMethod<ShutDownMethod>("dom::ContentParent::ShutDownProcess",
+                                        this,
+                                        &ContentParent::ShutDownProcess,
+                                        SEND_SHUTDOWN_MESSAGE));
+  }
+}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -358,16 +358,25 @@ public:
 
   jsipc::CPOWManager* GetCPOWManager() override;
 
   static void
   UnregisterRemoteFrame(const TabId& aTabId,
                         const ContentParentId& aCpId,
                         bool aMarkedDestroying);
 
+  // This method can be called on any thread.
+  void
+  RegisterRemoteWorkerActor();
+
+  // This method _must_ be called on main-thread because it can start the
+  // shutting down of the content process.
+  void
+  UnregisterRemoveWorkerActor();
+
   void ReportChildAlreadyBlocked();
 
   bool RequestRunToCompletion();
 
   void UpdateCookieStatus(nsIChannel *aChannel);
 
   bool IsAvailable() const
   {
@@ -1296,16 +1305,23 @@ private:
   // nsFakePluginTag::NOT_JSPLUGIN.
   int32_t mJSPluginID;
 
   // After we initiate shutdown, we also start a timer to ensure
   // that even content processes that are 100% blocked (say from
   // SIGSTOP), are still killed eventually.  This task enforces that
   // timer.
   nsCOMPtr<nsITimer> mForceKillTimer;
+
+  // Number of active remote workers. This value is increased when a
+  // RemoteWorkerParent actor is created for this ContentProcess and it is
+  // decreased when the actor is destroyed.
+  // It's touched on PBackground thread and on main-thread.
+  Atomic<uint32_t> mRemoteWorkerActors;
+
   // How many tabs we're waiting to finish their destruction
   // sequence.  Precisely, how many TabParents have called
   // NotifyTabDestroying() but not called NotifyTabDestroyed().
   int32_t mNumDestroyingTabs;
   // True only while this process is in "good health" and may be used for
   // new remote tabs.
   bool mIsAvailable;
   // True only while remote content is being actively used from this process.
--- a/dom/media/MediaDevices.cpp
+++ b/dom/media/MediaDevices.cpp
@@ -78,26 +78,24 @@ class MediaDevices::EnumDevResolver
       : mPromise(aPromise), mWindowId(aWindowId) {}
 
   NS_IMETHOD
   OnSuccess(nsIVariant* aDevices) override {
     // Create array for nsIMediaDevice
     nsTArray<nsCOMPtr<nsIMediaDevice>> devices;
     // Contain the fumes
     {
-      uint16_t vtype;
-      nsresult rv = aDevices->GetDataType(&vtype);
-      NS_ENSURE_SUCCESS(rv, rv);
+      uint16_t vtype = aDevices->GetDataType();
       if (vtype != nsIDataType::VTYPE_EMPTY_ARRAY) {
         nsIID elementIID;
         uint16_t elementType;
         void* rawArray;
         uint32_t arrayLen;
-        rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen,
-                                  &rawArray);
+        nsresult rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen,
+                                           &rawArray);
         NS_ENSURE_SUCCESS(rv, rv);
         if (elementType != nsIDataType::VTYPE_INTERFACE) {
           free(rawArray);
           return NS_ERROR_FAILURE;
         }
 
         nsISupports** supportsArray = reinterpret_cast<nsISupports**>(rawArray);
         for (uint32_t i = 0; i < arrayLen; ++i) {
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -315,25 +315,23 @@ void MediaEngineTabVideoSource::Draw() {
     mData = MakeUniqueFallible<unsigned char[]>(mDataSize);
   }
   if (!mData) {
     return;
   }
 
   nsCOMPtr<nsIPresShell> presShell;
   if (mWindow) {
-    RefPtr<nsPresContext> presContext;
     nsIDocShell* docshell = mWindow->GetDocShell();
     if (docshell) {
-      docshell->GetPresContext(getter_AddRefs(presContext));
+      presShell = docshell->GetPresShell();
     }
-    if (!presContext) {
+    if (!presShell) {
       return;
     }
-    presShell = presContext->PresShell();
   }
 
   RefPtr<layers::ImageContainer> container =
       layers::LayerManager::CreateImageContainer(
           layers::ImageContainer::ASYNCHRONOUS);
   RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
       gfxPlatform::GetPlatform()->GetSoftwareBackend(), mData.get(), size,
       stride, SurfaceFormat::B8G8R8X8, true);
--- a/dom/plugins/base/nsIPluginInstanceOwner.idl
+++ b/dom/plugins/base/nsIPluginInstanceOwner.idl
@@ -31,17 +31,17 @@ interface nsIPluginInstanceOwner : nsISu
   /**
    * Let the owner know what its instance is
    */
   void setInstance(in nsNPAPIPluginInstancePtr aInstance);
 
   /**
    * Get the instance associated with this owner.
    */
-  nsNPAPIPluginInstancePtr getInstance();
+  [notxpcom, nostdcall] nsNPAPIPluginInstancePtr getInstance();
 
   /**
    * Get a handle to the window structure of the owner.
    * This pointer cannot be made persistent by the caller.
    */
   void getWindow(in NPWindowStarRef aWindow);
 
   /**
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -824,22 +824,17 @@ nsPluginHost::InstantiatePluginInstance(
   }
 
   rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
   if (NS_FAILED(rv)) {
     instanceOwner->Destroy();
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<nsNPAPIPluginInstance> instance;
-  rv = instanceOwner->GetInstance(getter_AddRefs(instance));
-  if (NS_FAILED(rv)) {
-    instanceOwner->Destroy();
-    return rv;
-  }
+  RefPtr<nsNPAPIPluginInstance> instance = instanceOwner->GetInstance();
 
   if (instance) {
     CreateWidget(instanceOwner);
   }
 
   // At this point we consider instantiation to be successful. Do not return an error.
   instanceOwner.forget(aOwner);
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -389,23 +389,20 @@ void nsPluginInstanceOwner::GetAttribute
   loadingContent->GetPluginAttributes(attributes);
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(Element** result)
 {
   return CallQueryReferent(mContent.get(), result);
 }
 
-nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
+nsNPAPIPluginInstance*
+nsPluginInstanceOwner::GetInstance()
 {
-  NS_ENSURE_ARG_POINTER(aInstance);
-
-  *aInstance = mInstance;
-  NS_IF_ADDREF(*aInstance);
-  return NS_OK;
+  return mInstance;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
                                             const char *aTarget,
                                             nsIInputStream *aPostStream,
                                             void *aHeadersData,
                                             uint32_t aHeadersDataLen,
                                             bool aDoCheckLoadURIChecks)
--- a/dom/plugins/test/moz.build
+++ b/dom/plugins/test/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-DIRS += ['testplugin', 'testaddon']
+DIRS += ['testplugin']
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk3', 'cocoa', 'windows'):
     MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
     MOCHITEST_CHROME_MANIFESTS += ['mochitest/chrome.ini']
     BROWSER_CHROME_MANIFESTS += ['mochitest/browser.ini']
 
deleted file mode 100644
--- a/dom/plugins/test/testaddon/Makefile.in
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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 $(topsrcdir)/config/rules.mk
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-plugin_file_names = Test.plugin SecondTest.plugin ThirdTest.plugin npswftest.plugin
-else
-plugin_file_names = $(DLL_PREFIX)nptest$(DLL_SUFFIX) $(DLL_PREFIX)npsecondtest$(DLL_SUFFIX) $(DLL_PREFIX)npthirdtest$(DLL_SUFFIX) $(DLL_PREFIX)npswftest$(DLL_SUFFIX)
-endif
-
-# This is so hacky. Waiting on bug 988938.
-testdir = $(topobjdir)/_tests/xpcshell/dom/plugins/test/unit/
-addonpath = $(testdir)/testaddon.xpi
-
-libs::
-	$(NSINSTALL) -D $(testdir)
-	rm -f $(addonpath)
-	cd $(srcdir) && zip -rD $(addonpath) install.rdf
-	cd $(DIST) && zip -rD $(addonpath) $(foreach name,$(plugin_file_names),plugins/$(name))
deleted file mode 100644
--- a/dom/plugins/test/testaddon/install.rdf
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0"?>
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>test-plugin-from-xpi@tests.mozilla.org</em:id>
-    <em:version>1</em:version>
-    <em:name>Test plugin from XPI</em:name>
-    <em:description>This tests shipping a plugin through an extensions.</em:description>
-
-    <em:targetApplication>
-      <Description>
-        <em:id>toolkit@mozilla.org</em:id>
-        <em:minVersion>0</em:minVersion>
-        <em:maxVersion>*</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-
-    <em:unpack>true</em:unpack>
-    <em:multiprocessCompatible>true</em:multiprocessCompatible>
-
-  </Description>
-</RDF>
deleted file mode 100644
--- a/dom/plugins/test/testaddon/moz.build
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
--- a/dom/quota/StorageManager.cpp
+++ b/dom/quota/StorageManager.cpp
@@ -447,21 +447,17 @@ RequestResolver::ResolveOrReject()
 NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaUsageCallback, nsIQuotaCallback)
 
 nsresult
 RequestResolver::GetStorageEstimate(nsIVariant* aResult)
 {
   MOZ_ASSERT(aResult);
   MOZ_ASSERT(mType == Type::Estimate);
 
-#ifdef DEBUG
-  uint16_t dataType;
-  MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType));
-  MOZ_ASSERT(dataType == nsIDataType::VTYPE_INTERFACE_IS);
-#endif
+  MOZ_ASSERT(aResult->GetDataType() == nsIDataType::VTYPE_INTERFACE_IS);
 
   nsID* iid;
   nsCOMPtr<nsISupports> supports;
   nsresult rv = aResult->GetAsInterface(&iid, getter_AddRefs(supports));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -482,18 +478,17 @@ RequestResolver::GetStorageEstimate(nsIV
 
 nsresult
 RequestResolver::GetPersisted(nsIVariant* aResult)
 {
   MOZ_ASSERT(aResult);
   MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
 
 #ifdef DEBUG
-  uint16_t dataType;
-  MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType));
+  uint16_t dataType = aResult->GetDataType();
 #endif
 
   if (mType == Type::Persist) {
     MOZ_ASSERT(dataType == nsIDataType::VTYPE_VOID);
 
     mPersisted = true;
     return NS_OK;
   }
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -1753,25 +1753,29 @@ nsCSPContext::Read(nsIObjectInputStream*
 
     rv = aStream->ReadString(policyString);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool reportOnly = false;
     rv = aStream->ReadBoolean(&reportOnly);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    bool deliveredViaMetaTag = false;
+    rv = aStream->ReadBoolean(&deliveredViaMetaTag);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     // @param deliveredViaMetaTag:
     // when parsing the CSP policy string initially we already remove directives
     // that should not be processed when delivered via the meta tag. Such directives
     // will not be present at this point anymore.
     nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(policyString,
                                                                   mSelfURI,
                                                                   reportOnly,
                                                                   this,
-                                                                  false);
+                                                                  deliveredViaMetaTag);
     if (policy) {
       mPolicies.AppendElement(policy);
     }
   }
 
   return NS_OK;
 }
 
@@ -1788,11 +1792,12 @@ nsCSPContext::Write(nsIObjectOutputStrea
   aStream->Write32(mPolicies.Length());
 
   nsAutoString polStr;
   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
     polStr.Truncate();
     mPolicies[p]->toString(polStr);
     aStream->WriteWStringZ(polStr.get());
     aStream->WriteBoolean(mPolicies[p]->getReportOnlyFlag());
+    aStream->WriteBoolean(mPolicies[p]->getDeliveredViaMetaTagFlag());
   }
   return NS_OK;
 }
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -1284,16 +1284,18 @@ nsCSPParser::parseContentSecurityPolicy(
       NS_ENSURE_SUCCESS(rv, policy);
       NS_ConvertUTF8toUTF16 unicodePrePath(prePath);
       const char16_t* params[] = { unicodePrePath.get() };
       parser.logWarningErrorToConsole(nsIScriptError::warningFlag, "reportURInotInReportOnlyHeader",
                                       params, ArrayLength(params));
     }
   }
 
+  policy->setDeliveredViaMetaTagFlag(aDeliveredViaMetaTag);
+
   if (policy->getNumDirectives() == 0) {
     // Individual errors were already reported in the parser, but if
     // we do not have an enforcable directive at all, we return null.
     delete policy;
     return nullptr;
   }
 
   if (CSPPARSERLOGENABLED()) {
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -1461,16 +1461,17 @@ nsRequireSRIForDirective::getDirName(nsA
     nsIContentSecurityPolicy::REQUIRE_SRI_FOR));
 }
 
 /* ===== nsCSPPolicy ========================= */
 
 nsCSPPolicy::nsCSPPolicy()
   : mUpgradeInsecDir(nullptr)
   , mReportOnly(false)
+  , mDeliveredViaMetaTag(false)
 {
   CSPUTILSLOG(("nsCSPPolicy::nsCSPPolicy"));
 }
 
 nsCSPPolicy::~nsCSPPolicy()
 {
   CSPUTILSLOG(("nsCSPPolicy::~nsCSPPolicy"));
 
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -673,16 +673,22 @@ class nsCSPPolicy {
     inline void addUpgradeInsecDir(nsUpgradeInsecureDirective* aDir)
       {
         mUpgradeInsecDir = aDir;
         addDirective(aDir);
       }
 
     bool hasDirective(CSPDirective aDir) const;
 
+    inline void setDeliveredViaMetaTagFlag(bool aFlag)
+      { mDeliveredViaMetaTag = aFlag; }
+
+    inline bool getDeliveredViaMetaTagFlag() const
+      { return mDeliveredViaMetaTag; }
+
     inline void setReportOnlyFlag(bool aFlag)
       { mReportOnly = aFlag; }
 
     inline bool getReportOnlyFlag() const
       { return mReportOnly; }
 
     void getReportURIs(nsTArray<nsString> &outReportURIs) const;
 
@@ -700,11 +706,12 @@ class nsCSPPolicy {
       { return mDirectives.Length(); }
 
     bool visitDirectiveSrcs(CSPDirective aDir, nsCSPSrcVisitor* aVisitor) const;
 
   private:
     nsUpgradeInsecureDirective* mUpgradeInsecDir;
     nsTArray<nsCSPDirective*>   mDirectives;
     bool                        mReportOnly;
+    bool                        mDeliveredViaMetaTag;
 };
 
 #endif /* nsCSPUtils_h___ */
new file mode 100644
--- /dev/null
+++ b/dom/serviceworkers/test/console_monitor.js
@@ -0,0 +1,45 @@
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+let consoleListener;
+
+function ConsoleListener() {
+  Services.console.registerListener(this);
+}
+
+ConsoleListener.prototype  = {
+  callbacks: [],
+
+  observe: (aMsg) => {
+    if (!(aMsg instanceof Ci.nsIScriptError)) {
+      return;
+    }
+
+    let msg = {
+      errorMessage  : aMsg.errorMessage,
+      sourceName    : aMsg.sourceName,
+      sourceLine    : aMsg.sourceLine,
+      lineNumber    : aMsg.lineNumber,
+      columnNumber  : aMsg.columnNumber,
+      category      : aMsg.category,
+      windowID      : aMsg.outerWindowID,
+      innerWindowID : aMsg.innerWindowID,
+      isScriptError : true,
+      isWarning     : ((aMsg.flags & Ci.nsIScriptError.warningFlag) === 1),
+      isException   : ((aMsg.flags & Ci.nsIScriptError.exceptionFlag) === 1),
+      isStrict      : ((aMsg.flags & Ci.nsIScriptError.strictFlag) === 1),
+    };
+
+    sendAsyncMessage("monitor", msg);
+  }
+}
+
+addMessageListener("load", function (e) {
+  consoleListener = new ConsoleListener();
+  sendAsyncMessage("ready", {});
+});
+
+addMessageListener("unload", function (e) {
+  Services.console.unregisterListener(consoleListener);
+  consoleListener = null;
+  sendAsyncMessage("unloaded", {});
+});
--- a/dom/serviceworkers/test/mochitest.ini
+++ b/dom/serviceworkers/test/mochitest.ini
@@ -243,16 +243,17 @@ skip-if = debug # Bug 1262224
 [test_eval_allowed.html]
 [test_eventsource_intercept.html]
 [test_event_listener_leaks.html]
 [test_fetch_event.html]
 skip-if = (debug && e10s) # Bug 1262224
 [test_fetch_event_with_thirdpartypref.html]
 skip-if = (debug && e10s) # Bug 1262224
 [test_fetch_integrity.html]
+support-files = console_monitor.js
 [test_file_blob_response.html]
 [test_file_blob_upload.html]
 [test_force_refresh.html]
 [test_gzip_redirect.html]
 [test_hsts_upgrade_intercept.html]
 [test_https_fetch.html]
 [test_https_fetch_cloned_response.html]
 [test_https_origin_after_redirect.html]
--- a/dom/serviceworkers/test/test_fetch_integrity.html
+++ b/dom/serviceworkers/test/test_fetch_integrity.html
@@ -12,16 +12,81 @@
 <div id="content" style="display: none"></div>
 <script src="utils.js"></script>
 <script type="text/javascript">
 "use strict";
 
 let security_localizer =
   stringBundleService.createBundle("chrome://global/locale/security/security.properties");
 
+let consoleScript;
+let monitorCallbacks = [];
+
+function registerConsoleMonitor() {
+  return new Promise(resolve => {
+    var url = SimpleTest.getTestFileURL("console_monitor.js");
+    consoleScript = SpecialPowers.loadChromeScript(url);
+
+    consoleScript.addMessageListener("ready", resolve);
+    consoleScript.addMessageListener("monitor", function(msg) {
+      for (let i = 0; i < monitorCallbacks.length;) {
+         if (monitorCallbacks[i](msg)) {
+           ++i;
+         } else {
+           monitorCallbacks.splice(i, 1);
+         }
+      }
+    });
+    consoleScript.sendAsyncMessage("load", {});
+  });
+}
+
+function unregisterConsoleMonitor() {
+  return new Promise(resolve => {
+    consoleScript.addMessageListener("unloaded", () => {
+      consoleScript.destroy();
+      resolve();
+    });
+    consoleScript.sendAsyncMessage("unload", {});
+  });
+}
+
+function registerConsoleMonitorCallback(callback) {
+  monitorCallbacks.push(callback);
+}
+
+function waitForMessages() {
+  let messages = [];
+
+  // process repeated paired arguments of: msgId, args
+  for (let i = 0; i < arguments.length; i += 3) {
+    let msgId = arguments[i];
+    let args = arguments[i + 1];
+    messages.push(security_localizer.formatStringFromName(msgId, args, args.length));
+  }
+
+  return new Promise(resolve => {
+    registerConsoleMonitorCallback(msg => {
+      for (let i = 0; i < messages.length; ++i) {
+        if (messages[i] == msg.errorMessage) {
+          messages.splice(i, 1);
+          break;
+        }
+      }
+
+      if (messages.length == 0) {
+        resolve();
+        return false;
+      }
+
+      return true;
+    });
+  });
+}
+
 function expect_security_console_message(/* msgId, args, ... */) {
   let expectations = [];
   // process repeated paired arguments of: msgId, args
   for (let i = 0; i < arguments.length; i += 3) {
     let msgId = arguments[i];
     let args = arguments[i + 1];
     let filename = arguments[i + 2];
     expectations.push({
@@ -87,17 +152,19 @@ add_task(async function test_integrity_s
 
   await registration.unregister();
   client_win.close();
 });
 
 add_task(async function test_integrity_sharedWorker() {
   var filename = make_absolute_url("sharedWorker_fetch.js");
 
-  info("Attch main window to a SharedWorker.");
+  await registerConsoleMonitor();
+
+  info("Attach main window to a SharedWorker.");
   let sharedWorker = new SharedWorker(filename);
   let waitForConnected = new Promise((resolve) => {
     sharedWorker.port.onmessage = function (e) {
       if (e.data == "Connected") {
         resolve();
       } else {
         reject();
       }
@@ -114,25 +181,26 @@ add_task(async function test_integrity_s
         resolve();
       } else {
         reject();
       }
     }
   });
   await waitForBothConnected;
 
-  let expectedMessage = expect_security_console_message(
+  let expectedMessage = waitForMessages(
     "MalformedIntegrityHash",
     ["abc"],
     filename,
     "NoValidMetadata",
     [""],
     filename,
   );
-  let expectedMessage2 = expect_security_console_message(
+
+  let expectedMessage2 = waitForMessages(
     "MalformedIntegrityHash",
     ["abc"],
     filename,
     "NoValidMetadata",
     [""],
     filename,
   );
 
@@ -146,17 +214,19 @@ add_task(async function test_integrity_s
         resolve();
       } else {
         reject();
       }
     }
   });
   await waitForSRIFailed;
 
-  await wait_for_expected_message(expectedMessage);
+  await expectedMessage;
+  await expectedMessage2;
 
-  await wait_for_expected_message(expectedMessage2);
   client_win.close();
+
+  await unregisterConsoleMonitor();
 });
 
 </script>
 </body>
 </html>
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -28,31 +28,31 @@
 #include <algorithm>
 #include "mozilla/ipc/BackgroundChild.h"
 #include "GeckoProfiler.h"
 #include "jsfriendapi.h"
 #include "js/LocaleSensitive.h"
 #include "mozilla/AbstractThread.h"
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/ArrayUtils.h"
-#include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/PerformanceService.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/Monitor.h"
@@ -66,17 +66,16 @@
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "OSFileConstants.h"
 #include "xpcpublic.h"
 
 #include "Principal.h"
-#include "SharedWorker.h"
 #include "WorkerDebuggerManager.h"
 #include "WorkerError.h"
 #include "WorkerLoadInfo.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 #include "WorkerThread.h"
 #include "prsystem.h"
@@ -1402,36 +1401,16 @@ RuntimeService::RegisterWorker(WorkerPri
       domainInfo->mChildWorkerCount++;
     }
     else if (isServiceWorker) {
       domainInfo->mActiveServiceWorkers.AppendElement(aWorkerPrivate);
     }
     else {
       domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
     }
-
-    if (isSharedWorker) {
-#ifdef DEBUG
-      for (const UniquePtr<SharedWorkerInfo>& data : domainInfo->mSharedWorkerInfos) {
-         if (data->mScriptSpec == sharedWorkerScriptSpec &&
-             data->mName == aWorkerPrivate->WorkerName() &&
-             // We want to be sure that the window's principal subsumes the
-             // SharedWorker's principal and vice versa.
-             data->mWorkerPrivate->GetPrincipal()->Subsumes(aWorkerPrivate->GetPrincipal()) &&
-             aWorkerPrivate->GetPrincipal()->Subsumes(data->mWorkerPrivate->GetPrincipal())) {
-           MOZ_CRASH("We should not instantiate a new SharedWorker!");
-         }
-      }
-#endif
-
-      UniquePtr<SharedWorkerInfo> sharedWorkerInfo(
-        new SharedWorkerInfo(aWorkerPrivate, sharedWorkerScriptSpec,
-                             aWorkerPrivate->WorkerName()));
-      domainInfo->mSharedWorkerInfos.AppendElement(std::move(sharedWorkerInfo));
-    }
   }
 
   // From here on out we must call UnregisterWorker if something fails!
   if (parent) {
     if (!parent->AddChildWorker(aWorkerPrivate)) {
       UnregisterWorker(aWorkerPrivate);
       return false;
     }
@@ -1477,30 +1456,16 @@ RuntimeService::RegisterWorker(WorkerPri
   if (isServiceWorker) {
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_WAS_SPAWNED, 1);
   }
   return true;
 }
 
 void
-RuntimeService::RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
-                                   WorkerPrivate* aWorkerPrivate)
-{
-  for (uint32_t i = 0; i < aDomainInfo->mSharedWorkerInfos.Length(); ++i) {
-    const UniquePtr<SharedWorkerInfo>& data =
-      aDomainInfo->mSharedWorkerInfos[i];
-    if (data->mWorkerPrivate == aWorkerPrivate) {
-      aDomainInfo->mSharedWorkerInfos.RemoveElementAt(i);
-      break;
-    }
-  }
-}
-
-void
 RuntimeService::UnregisterWorker(WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnParentThread();
 
   WorkerPrivate* parent = aWorkerPrivate->GetParent();
   if (!parent) {
     AssertIsOnMainThread();
   }
@@ -1532,20 +1497,16 @@ RuntimeService::UnregisterWorker(WorkerP
       domainInfo->mActiveServiceWorkers.RemoveElement(aWorkerPrivate);
     }
     else {
       MOZ_ASSERT(domainInfo->mActiveWorkers.Contains(aWorkerPrivate),
                  "Don't know about this worker!");
       domainInfo->mActiveWorkers.RemoveElement(aWorkerPrivate);
     }
 
-    if (aWorkerPrivate->IsSharedWorker()) {
-      RemoveSharedWorker(domainInfo, aWorkerPrivate);
-    }
-
     // See if there's a queued worker we can schedule.
     if (domainInfo->ActiveWorkerCount() < gMaxWorkersPerDomain &&
         !domainInfo->mQueuedWorkers.IsEmpty()) {
       queuedWorker = domainInfo->mQueuedWorkers[0];
       domainInfo->mQueuedWorkers.RemoveElementAt(0);
 
       if (queuedWorker->GetParent()) {
         domainInfo->mChildWorkerCount++;
@@ -1565,20 +1526,19 @@ RuntimeService::UnregisterWorker(WorkerP
   }
 
   if (aWorkerPrivate->IsServiceWorker()) {
     AssertIsOnMainThread();
     Telemetry::AccumulateTimeDelta(Telemetry::SERVICE_WORKER_LIFE_TIME,
                                    aWorkerPrivate->CreationTimeStamp());
   }
 
-  if (aWorkerPrivate->IsSharedWorker() ||
-      aWorkerPrivate->IsServiceWorker()) {
+  if (aWorkerPrivate->IsSharedWorker()) {
     AssertIsOnMainThread();
-    aWorkerPrivate->CloseAllSharedWorkers();
+    aWorkerPrivate->GetRemoteWorkerController()->CloseWorkerOnMainThread();
   }
 
   if (parent) {
     parent->RemoveChildWorker(aWorkerPrivate);
   }
   else if (aWorkerPrivate->IsSharedWorker()) {
     AssertIsOnMainThread();
 
@@ -2204,78 +2164,78 @@ RuntimeService::CancelWorkersForWindow(n
   AssertIsOnMainThread();
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   if (!workers.IsEmpty()) {
     for (uint32_t index = 0; index < workers.Length(); index++) {
       WorkerPrivate*& worker = workers[index];
-
-      if (worker->IsSharedWorker()) {
-        worker->CloseSharedWorkersForWindow(aWindow);
-      } else {
-        worker->Cancel();
-      }
+      MOZ_ASSERT(!worker->IsSharedWorker());
+      worker->Cancel();
     }
   }
 }
 
 void
 RuntimeService::FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->Freeze(aWindow);
   }
 }
 
 void
 RuntimeService::ThawWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->Thaw(aWindow);
   }
 }
 
 void
 RuntimeService::SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->ParentWindowPaused();
   }
 }
 
 void
 RuntimeService::ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
+    MOZ_ASSERT(!workers[index]->IsSharedWorker());
     workers[index]->ParentWindowResumed();
   }
 }
 
 void
 RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
@@ -2286,202 +2246,16 @@ RuntimeService::PropagateFirstPartyStora
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     workers[index]->PropagateFirstPartyStorageAccessGranted();
   }
 }
 
-nsresult
-RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal,
-                                   const nsAString& aScriptURL,
-                                   const nsAString& aName,
-                                   SharedWorker** aSharedWorker)
-{
-  AssertIsOnMainThread();
-
-  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
-  MOZ_ASSERT(window);
-
-  // If the window is blocked from accessing storage, do not allow it
-  // to connect to a SharedWorker.  This would potentially allow it
-  // to communicate with other windows that do have storage access.
-  // Allow private browsing, however, as we handle that isolation
-  // via the principal.
-  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
-  if (storageAllowed != nsContentUtils::StorageAccess::eAllow &&
-      storageAllowed != nsContentUtils::StorageAccess::ePrivateBrowsing) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  // Assert that the principal private browsing state matches the
-  // StorageAccess value.
-#ifdef  MOZ_DIAGNOSTIC_ASSERT_ENABLED
-  if (storageAllowed == nsContentUtils::StorageAccess::ePrivateBrowsing) {
-    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-    nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
-    uint32_t privateBrowsingId = 0;
-    if (principal) {
-      MOZ_ALWAYS_SUCCEEDS(principal->GetPrivateBrowsingId(&privateBrowsingId));
-    }
-    MOZ_DIAGNOSTIC_ASSERT(privateBrowsingId != 0);
-  }
-#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
-
-  JSContext* cx = aGlobal.Context();
-
-  WorkerLoadInfo loadInfo;
-  nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
-                                           false,
-                                           WorkerPrivate::OverrideLoadGroup,
-                                           WorkerTypeShared, &loadInfo);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName,
-                                        aSharedWorker);
-}
-
-nsresult
-RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
-                                               WorkerLoadInfo* aLoadInfo,
-                                               const nsAString& aScriptURL,
-                                               const nsAString& aName,
-                                               SharedWorker** aSharedWorker)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aLoadInfo);
-  MOZ_ASSERT(aLoadInfo->mResolvedScriptURI);
-
-  RefPtr<WorkerPrivate> workerPrivate;
-  {
-    MutexAutoLock lock(mMutex);
-
-    nsCString scriptSpec;
-    nsresult rv = aLoadInfo->mResolvedScriptURI->GetSpec(scriptSpec);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    MOZ_DIAGNOSTIC_ASSERT(aLoadInfo->mPrincipal && aLoadInfo->mLoadingPrincipal);
-
-    WorkerDomainInfo* domainInfo;
-    if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo)) {
-      for (const UniquePtr<SharedWorkerInfo>& data : domainInfo->mSharedWorkerInfos) {
-        if (data->mScriptSpec == scriptSpec &&
-            data->mName == aName &&
-            // We want to be sure that the window's principal subsumes the
-            // SharedWorker's loading principal and vice versa.
-            aLoadInfo->mLoadingPrincipal->Subsumes(data->mWorkerPrivate->GetLoadingPrincipal()) &&
-            data->mWorkerPrivate->GetLoadingPrincipal()->Subsumes(aLoadInfo->mLoadingPrincipal)) {
-          workerPrivate = data->mWorkerPrivate;
-          break;
-        }
-      }
-    }
-  }
-
-  // Keep a reference to the window before spawning the worker. If the worker is
-  // a Shared/Service worker and the worker script loads and executes before
-  // the SharedWorker object itself is created before then WorkerScriptLoaded()
-  // will reset the loadInfo's window.
-  nsCOMPtr<nsPIDOMWindowInner> window = aLoadInfo->mWindow;
-
-  // shouldAttachToWorkerPrivate tracks whether our SharedWorker should actually
-  // get attached to the WorkerPrivate we're using.  It will become false if the
-  // WorkerPrivate already exists and its secure context state doesn't match
-  // what we want for the new SharedWorker.
-  bool shouldAttachToWorkerPrivate = true;
-  bool created = false;
-  ErrorResult rv;
-  if (!workerPrivate) {
-    workerPrivate =
-      WorkerPrivate::Constructor(aCx, aScriptURL, false,
-                                 WorkerTypeShared, aName, VoidCString(),
-                                 aLoadInfo, rv);
-    NS_ENSURE_TRUE(workerPrivate, rv.StealNSResult());
-
-    created = true;
-  } else {
-    // Check whether the secure context state matches.  The current realm
-    // of aCx is the realm of the SharedWorker constructor that was invoked,
-    // which is the realm of the document that will be hooked up to the worker,
-    // so that's what we want to check.
-    shouldAttachToWorkerPrivate =
-      workerPrivate->IsSecureContext() ==
-        JS::GetIsSecureContext(js::GetContextRealm(aCx));
-
-    // If we're attaching to an existing SharedWorker private, then we
-    // must update the overriden load group to account for our document's
-    // load group.
-    if (shouldAttachToWorkerPrivate) {
-      workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
-    }
-  }
-
-  // We don't actually care about this MessageChannel, but we use it to 'steal'
-  // its 2 connected ports.
-  RefPtr<MessageChannel> channel =
-    MessageChannel::Constructor(window->AsGlobal(), rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
-  }
-
-  RefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
-                                                       channel->Port1());
-
-  if (!shouldAttachToWorkerPrivate) {
-    // We're done here.  Just queue up our error event and return our
-    // dead-on-arrival SharedWorker.
-    RefPtr<AsyncEventDispatcher> errorEvent =
-      new AsyncEventDispatcher(sharedWorker,
-                               NS_LITERAL_STRING("error"),
-                               CanBubble::eNo);
-    errorEvent->PostDOMEvent();
-    sharedWorker.forget(aSharedWorker);
-    return NS_OK;
-  }
-
-  if (!workerPrivate->RegisterSharedWorker(sharedWorker, channel->Port2())) {
-    NS_WARNING("Worker is unreachable, this shouldn't happen!");
-    sharedWorker->Close();
-    return NS_ERROR_FAILURE;
-  }
-
-  // This is normally handled in RegisterWorker, but that wasn't called if the
-  // worker already existed.
-  if (!created) {
-    nsTArray<WorkerPrivate*>* windowArray;
-    if (!mWindowMap.Get(window, &windowArray)) {
-      windowArray = new nsTArray<WorkerPrivate*>(1);
-      mWindowMap.Put(window, windowArray);
-    }
-
-    if (!windowArray->Contains(workerPrivate)) {
-      windowArray->AppendElement(workerPrivate);
-    }
-  }
-
-  sharedWorker.forget(aSharedWorker);
-  return NS_OK;
-}
-
-void
-RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aWorkerPrivate);
-  MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
-
-  MutexAutoLock lock(mMutex);
-
-  WorkerDomainInfo* domainInfo;
-  if (mDomainMap.Get(aWorkerPrivate->Domain(), &domainInfo)) {
-    RemoveSharedWorker(domainInfo, aWorkerPrivate);
-  }
-}
-
 void
 RuntimeService::NoteIdleThread(WorkerThread* aThread)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aThread);
 
   bool shutdownThread = mShuttingDown;
   bool scheduleTimer = false;
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -18,44 +18,29 @@
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 
 class nsITimer;
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
-class SharedWorker;
 struct WorkerLoadInfo;
 class WorkerThread;
 
 namespace workerinternals {
 
 class RuntimeService final : public nsIObserver
 {
-  struct SharedWorkerInfo
-  {
-    WorkerPrivate* mWorkerPrivate;
-    nsCString mScriptSpec;
-    nsString mName;
-
-    SharedWorkerInfo(WorkerPrivate* aWorkerPrivate,
-                     const nsACString& aScriptSpec,
-                     const nsAString& aName)
-    : mWorkerPrivate(aWorkerPrivate), mScriptSpec(aScriptSpec), mName(aName)
-    { }
-  };
-
   struct WorkerDomainInfo
   {
     nsCString mDomain;
     nsTArray<WorkerPrivate*> mActiveWorkers;
     nsTArray<WorkerPrivate*> mActiveServiceWorkers;
     nsTArray<WorkerPrivate*> mQueuedWorkers;
-    nsTArray<UniquePtr<SharedWorkerInfo>> mSharedWorkerInfos;
     uint32_t mChildWorkerCount;
 
     WorkerDomainInfo()
     : mActiveWorkers(1), mChildWorkerCount(0)
     { }
 
     uint32_t
     ActiveWorkerCount() const
@@ -129,20 +114,16 @@ public:
 
   bool
   RegisterWorker(WorkerPrivate* aWorkerPrivate);
 
   void
   UnregisterWorker(WorkerPrivate* aWorkerPrivate);
 
   void
-  RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
-                     WorkerPrivate* aWorkerPrivate);
-
-  void
   CancelWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   FreezeWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   ThawWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
@@ -150,25 +131,16 @@ public:
   SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow);
 
   void
   PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow);
 
-  nsresult
-  CreateSharedWorker(const GlobalObject& aGlobal,
-                     const nsAString& aScriptURL,
-                     const nsAString& aName,
-                     SharedWorker** aSharedWorker);
-
-  void
-  ForgetSharedWorker(WorkerPrivate* aWorkerPrivate);
-
   const NavigatorProperties&
   GetNavigatorProperties() const
   {
     return mNavigatorProperties;
   }
 
   void
   NoteIdleThread(WorkerThread* aThread);
@@ -261,22 +233,15 @@ private:
   GetWorkersForWindow(nsPIDOMWindowInner* aWindow,
                       nsTArray<WorkerPrivate*>& aWorkers);
 
   bool
   ScheduleWorker(WorkerPrivate* aWorkerPrivate);
 
   static void
   ShutdownIdleThreads(nsITimer* aTimer, void* aClosure);
-
-  nsresult
-  CreateSharedWorkerFromLoadInfo(JSContext* aCx,
-                                 WorkerLoadInfo* aLoadInfo,
-                                 const nsAString& aScriptURL,
-                                 const nsAString& aName,
-                                 SharedWorker** aSharedWorker);
 };
 
 } // workerinternals namespace
 } // dom namespace
 } // mozilla namespace
 
 #endif /* mozilla_dom_workers_runtimeservice_h__ */
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -108,49 +108,55 @@ GetBaseURI(bool aIsMainScript, WorkerPri
     baseURI = aWorkerPrivate->GetBaseURI();
     NS_ASSERTION(baseURI, "Should have been set already!");
   }
 
   return baseURI;
 }
 
 nsresult
-ChannelFromScriptURL(nsIPrincipal* principal,
-                     nsIURI* baseURI,
-                     nsIDocument* parentDoc,
-                     WorkerPrivate* aWorkerPrivate,
-                     nsILoadGroup* loadGroup,
-                     nsIIOService* ios,
-                     nsIScriptSecurityManager* secMan,
-                     const nsAString& aScriptURL,
-                     const Maybe<ClientInfo>& aClientInfo,
-                     const Maybe<ServiceWorkerDescriptor>& aController,
-                     bool aIsMainScript,
-                     WorkerScriptType aWorkerScriptType,
-                     nsContentPolicyType aMainScriptContentPolicyType,
-                     nsLoadFlags aLoadFlags,
-                     bool aDefaultURIEncoding,
-                     nsIChannel** aChannel)
+ConstructURI(const nsAString& aScriptURL, nsIURI* baseURI,
+             nsIDocument* parentDoc, bool aDefaultURIEncoding,
+             nsIURI** aResult)
 {
-  AssertIsOnMainThread();
-
   nsresult rv;
-  nsCOMPtr<nsIURI> uri;
-
   if (aDefaultURIEncoding) {
-    rv = NS_NewURI(getter_AddRefs(uri), aScriptURL, nullptr, baseURI);
+    rv = NS_NewURI(aResult, aScriptURL, nullptr, baseURI);
   } else {
-    rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
+    rv = nsContentUtils::NewURIWithDocumentCharset(aResult,
                                                    aScriptURL, parentDoc,
                                                    baseURI);
   }
 
   if (NS_FAILED(rv)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
+  return NS_OK;
+}
+
+nsresult
+ChannelFromScriptURL(nsIPrincipal* principal,
+                     nsIDocument* parentDoc,
+                     WorkerPrivate* aWorkerPrivate,
+                     nsILoadGroup* loadGroup,
+                     nsIIOService* ios,
+                     nsIScriptSecurityManager* secMan,
+                     nsIURI* aScriptURL,
+                     const Maybe<ClientInfo>& aClientInfo,
+                     const Maybe<ServiceWorkerDescriptor>& aController,
+                     bool aIsMainScript,
+                     WorkerScriptType aWorkerScriptType,
+                     nsContentPolicyType aMainScriptContentPolicyType,
+                     nsLoadFlags aLoadFlags,
+                     nsIChannel** aChannel)
+{
+  AssertIsOnMainThread();
+
+  nsresult rv;
+  nsCOMPtr<nsIURI> uri = aScriptURL;
 
   // If we have the document, use it. Unfortunately, for dedicated workers
   // 'parentDoc' ends up being the parent document, which is not the document
   // that we want to use. So make sure to avoid using 'parentDoc' in that
   // situation.
   if (parentDoc && parentDoc->NodePrincipal() != principal) {
     parentDoc = nullptr;
   }
@@ -1049,24 +1055,30 @@ private:
         }
       }
     }
 
     if (!channel) {
       // Only top level workers' main script use the document charset for the
       // script uri encoding. Otherwise, default encoding (UTF-8) is applied.
       bool useDefaultEncoding = !(!parentWorker && IsMainWorkerScript());
-      rv = ChannelFromScriptURL(principal, baseURI, parentDoc, mWorkerPrivate,
+      nsCOMPtr<nsIURI> url;
+      rv = ConstructURI(loadInfo.mURL, baseURI, parentDoc, useDefaultEncoding,
+                        getter_AddRefs(url));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      rv = ChannelFromScriptURL(principal, parentDoc, mWorkerPrivate,
                                 loadGroup, ios,
-                                secMan, loadInfo.mURL,
+                                secMan, url,
                                 mClientInfo, mController,
                                 IsMainWorkerScript(),
                                 mWorkerScriptType,
                                 mWorkerPrivate->ContentPolicyType(), loadFlags,
-                                useDefaultEncoding,
                                 getter_AddRefs(channel));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
 
     // We need to know which index we're on in OnStreamComplete so we know
     // where to put the result.
@@ -1967,30 +1979,34 @@ public:
     nsCOMPtr<nsIURI> baseURI = mWorkerPrivate->GetBaseURI();
     MOZ_ASSERT(baseURI);
 
     // May be null.
     nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
 
     mLoadInfo.mLoadGroup = mWorkerPrivate->GetLoadGroup();
 
+    // Nested workers use default uri encoding.
+    nsCOMPtr<nsIURI> url;
+    mResult = ConstructURI(mScriptURL, baseURI, parentDoc, true,
+                           getter_AddRefs(url));
+    NS_ENSURE_SUCCESS(mResult, true);
+
     Maybe<ClientInfo> clientInfo;
     clientInfo.emplace(mClientInfo);
 
     nsCOMPtr<nsIChannel> channel;
     mResult = workerinternals::
       ChannelFromScriptURLMainThread(mLoadInfo.mLoadingPrincipal,
-                                     baseURI, parentDoc,
+                                     parentDoc,
                                      mLoadInfo.mLoadGroup,
-                                     mScriptURL,
+                                     url,
                                      clientInfo,
                                      // Nested workers are always dedicated.
                                      nsIContentPolicy::TYPE_INTERNAL_WORKER,
-                                     // Nested workers use default uri encoding.
-                                     true,
                                      getter_AddRefs(channel));
     NS_ENSURE_SUCCESS(mResult, true);
 
     mResult = mLoadInfo.SetPrincipalFromChannel(channel);
     NS_ENSURE_SUCCESS(mResult, true);
 
     mLoadInfo.mChannel = channel.forget();
     return true;
@@ -2318,38 +2334,35 @@ LoadAllScripts(WorkerPrivate* aWorkerPri
 }
 
 } /* anonymous namespace */
 
 namespace workerinternals {
 
 nsresult
 ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
-                               nsIURI* aBaseURI,
                                nsIDocument* aParentDoc,
                                nsILoadGroup* aLoadGroup,
-                               const nsAString& aScriptURL,
+                               nsIURI* aScriptURL,
                                const Maybe<ClientInfo>& aClientInfo,
                                nsContentPolicyType aMainScriptContentPolicyType,
-                               bool aDefaultURIEncoding,
                                nsIChannel** aChannel)
 {
   AssertIsOnMainThread();
 
   nsCOMPtr<nsIIOService> ios(do_GetIOService());
 
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   NS_ASSERTION(secMan, "This should never be null!");
 
-  return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, nullptr,
+  return ChannelFromScriptURL(aPrincipal, aParentDoc, nullptr,
                               aLoadGroup, ios, secMan, aScriptURL, aClientInfo,
                               Maybe<ServiceWorkerDescriptor>(),
                               true, WorkerScript, aMainScriptContentPolicyType,
-                              nsIRequest::LOAD_NORMAL, aDefaultURIEncoding,
-                              aChannel);
+                              nsIRequest::LOAD_NORMAL, aChannel);
 }
 
 nsresult
 ChannelFromScriptURLWorkerThread(JSContext* aCx,
                                  WorkerPrivate* aParent,
                                  const nsAString& aScriptURL,
                                  WorkerLoadInfo& aLoadInfo)
 {
--- a/dom/workers/ScriptLoader.h
+++ b/dom/workers/ScriptLoader.h
@@ -2,17 +2,17 @@
 /* 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_workers_scriptloader_h__
 #define mozilla_dom_workers_scriptloader_h__
 
-#include "WorkerCommon.h"
+#include "mozilla/dom/WorkerCommon.h"
 #include "nsIContentPolicy.h"
 #include "nsStringFwd.h"
 
 class nsIPrincipal;
 class nsIURI;
 class nsIDocument;
 class nsILoadGroup;
 class nsIChannel;
@@ -30,23 +30,21 @@ enum WorkerScriptType {
   WorkerScript,
   DebuggerScript
 };
 
 namespace workerinternals {
 
 nsresult
 ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
-                               nsIURI* aBaseURI,
                                nsIDocument* aParentDoc,
                                nsILoadGroup* aLoadGroup,
-                               const nsAString& aScriptURL,
+                               nsIURI* aScriptURL,
                                const Maybe<ClientInfo>& aClientInfo,
                                nsContentPolicyType aContentPolicyType,
-                               bool aDefaultURIEncoding,
                                nsIChannel** aChannel);
 
 nsresult
 ChannelFromScriptURLWorkerThread(JSContext* aCx,
                                  WorkerPrivate* aParent,
                                  const nsAString& aScriptURL,
                                  WorkerLoadInfo& aLoadInfo);
 
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -8,16 +8,20 @@
 
 #include "MessageEventRunnable.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsContentUtils.h"
 #include "WorkerPrivate.h"
 
+#ifdef XP_WIN
+#undef PostMessage
+#endif
+
 namespace mozilla {
 namespace dom {
 
 /* static */ already_AddRefed<Worker>
 Worker::Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
                     const WorkerOptions& aOptions, ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.Context();
--- a/dom/workers/WorkerError.cpp
+++ b/dom/workers/WorkerError.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 "WorkerError.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsGlobalWindowInner.h"
 #include "nsIConsoleService.h"
 #include "nsScriptError.h"
@@ -196,18 +197,19 @@ private:
       // care of naturally.
       MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
 
       // Similarly for paused windows; all its workers should have been informed.
       // (Subworkers are unaffected by paused windows.)
       MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
 
       if (aWorkerPrivate->IsSharedWorker()) {
-        aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport,
-                                                      /* isErrorEvent */ true);
+        aWorkerPrivate->GetRemoteWorkerController()
+                      ->ErrorPropagationOnMainThread(&mReport,
+                                                     /* isErrorEvent */ true);
         return true;
       }
 
       // Service workers do not have a main thread parent global, so normal
       // worker error reporting will crash.  Instead, pass the error to
       // the ServiceWorkerManager to report on any controlled documents.
       if (aWorkerPrivate->IsServiceWorker()) {
         RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
@@ -286,18 +288,18 @@ private:
     // care of naturally.
     MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
 
     // Similarly for paused windows; all its workers should have been informed.
     // (Subworkers are unaffected by paused windows.)
     MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
 
     if (aWorkerPrivate->IsSharedWorker()) {
-      aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr,
-                                                    /* isErrorEvent */ false);
+      aWorkerPrivate->GetRemoteWorkerController()
+                    ->ErrorPropagationOnMainThread(nullptr, false);
       return true;
     }
 
     if (aWorkerPrivate->IsServiceWorker()) {
       RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
       if (swm) {
         swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
                          aWorkerPrivate->ServiceWorkerScope(),
@@ -493,73 +495,94 @@ WorkerErrorReport::ReportError(JSContext
   // Otherwise log an error to the error console.
   WorkerErrorReport::LogErrorToConsole(aReport, aInnerWindowId);
 }
 
 /* static */ void
 WorkerErrorReport::LogErrorToConsole(const WorkerErrorReport& aReport,
                                      uint64_t aInnerWindowId)
 {
+  nsTArray<ErrorDataNote> notes;
+  for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
+    const WorkerErrorNote& note = aReport.mNotes.ElementAt(i);
+    notes.AppendElement(ErrorDataNote(note.mLineNumber, note.mColumnNumber,
+                                      note.mMessage, note.mFilename));
+  }
+
+  ErrorData errorData(aReport.mLineNumber,
+                      aReport.mColumnNumber,
+                      aReport.mFlags,
+                      aReport.mMessage,
+                      aReport.mFilename,
+                      aReport.mLine,
+                      notes);
+  LogErrorToConsole(errorData, aInnerWindowId);
+}
+
+/* static */ void
+WorkerErrorReport::LogErrorToConsole(const ErrorData& aReport,
+                                     uint64_t aInnerWindowId)
+{
   AssertIsOnMainThread();
 
   RefPtr<nsScriptErrorBase> scriptError = new nsScriptError();
   NS_WARNING_ASSERTION(scriptError, "Failed to create script error!");
 
   if (scriptError) {
     nsAutoCString category("Web Worker");
-    if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage,
-                                                aReport.mFilename,
-                                                aReport.mLine,
-                                                aReport.mLineNumber,
-                                                aReport.mColumnNumber,
-                                                aReport.mFlags,
+    if (NS_FAILED(scriptError->InitWithWindowID(aReport.message(),
+                                                aReport.filename(),
+                                                aReport.line(),
+                                                aReport.lineNumber(),
+                                                aReport.columnNumber(),
+                                                aReport.flags(),
                                                 category,
                                                 aInnerWindowId))) {
       NS_WARNING("Failed to init script error!");
       scriptError = nullptr;
     }
 
-    for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) {
-      const WorkerErrorNote& note = aReport.mNotes.ElementAt(i);
+    for (size_t i = 0, len = aReport.notes().Length(); i < len; i++) {
+      const ErrorDataNote& note = aReport.notes().ElementAt(i);
 
       nsScriptErrorNote* noteObject = new nsScriptErrorNote();
-      noteObject->Init(note.mMessage, note.mFilename,
-                       note.mLineNumber, note.mColumnNumber);
+      noteObject->Init(note.message(), note.filename(),
+                       note.lineNumber(), note.columnNumber());
       scriptError->AddNote(noteObject);
     }
   }
 
   nsCOMPtr<nsIConsoleService> consoleService =
     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   NS_WARNING_ASSERTION(consoleService, "Failed to get console service!");
 
   if (consoleService) {
     if (scriptError) {
       if (NS_SUCCEEDED(consoleService->LogMessage(scriptError))) {
         return;
       }
       NS_WARNING("LogMessage failed!");
     } else if (NS_SUCCEEDED(consoleService->LogStringMessage(
-                              aReport.mMessage.BeginReading()))) {
+                              aReport.message().BeginReading()))) {
       return;
     }
     NS_WARNING("LogStringMessage failed!");
   }
 
-  NS_ConvertUTF16toUTF8 msg(aReport.mMessage);
-  NS_ConvertUTF16toUTF8 filename(aReport.mFilename);
+  NS_ConvertUTF16toUTF8 msg(aReport.message());
+  NS_ConvertUTF16toUTF8 filename(aReport.filename());
 
   static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]";
 
 #ifdef ANDROID
   __android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(),
-                      filename.get(), aReport.mLineNumber);
+                      filename.get(), aReport.lineNumber());
 #endif
 
-  fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber);
+  fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.lineNumber());
   fflush(stderr);
 }
 
 /* static */ void
 WorkerErrorReport::CreateAndDispatchGenericErrorRunnableToParent(WorkerPrivate* aWorkerPrivate)
 {
   ReportGenericErrorRunnable::CreateAndDispatch(aWorkerPrivate);
 }
--- a/dom/workers/WorkerError.h
+++ b/dom/workers/WorkerError.h
@@ -2,25 +2,26 @@
 /* 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_workers_WorkerError_h
 #define mozilla_dom_workers_WorkerError_h
 
-#include "WorkerCommon.h"
+#include "mozilla/dom/WorkerCommon.h"
 #include "jsapi.h"
 
 namespace mozilla {
 
 class DOMEventTargetHelper;
 
 namespace dom {
 
+class ErrorData;
 class WorkerErrorBase
 {
 public:
   nsString mMessage;
   nsString mFilename;
   uint32_t mLineNumber;
   uint32_t mColumnNumber;
   uint32_t mErrorNumber;
@@ -67,15 +68,18 @@ public:
               bool aFireAtScope, DOMEventTargetHelper* aTarget,
               const WorkerErrorReport& aReport, uint64_t aInnerWindowId,
               JS::Handle<JS::Value> aException = JS::NullHandleValue);
 
   static void
   LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId);
 
   static void
+  LogErrorToConsole(const mozilla::dom::ErrorData& aReport, uint64_t aInnerWindowId);
+
+  static void
   CreateAndDispatchGenericErrorRunnableToParent(WorkerPrivate* aWorkerPrivate);
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_workers_WorkerError_h
--- a/dom/workers/WorkerLoadInfo.cpp
+++ b/dom/workers/WorkerLoadInfo.cpp
@@ -91,16 +91,17 @@ WorkerLoadInfo::WorkerLoadInfo()
   , mFromWindow(false)
   , mEvalAllowed(false)
   , mReportCSPViolations(false)
   , mXHRParamsAllowed(false)
   , mPrincipalIsSystem(false)
   , mStorageAllowed(false)
   , mFirstPartyStorageAccessGranted(false)
   , mServiceWorkersTestingInWindow(false)
+  , mSecureContext(eNotSet)
 {
   MOZ_COUNT_CTOR(WorkerLoadInfo);
 }
 
 WorkerLoadInfo::~WorkerLoadInfo()
 {
   MOZ_COUNT_DTOR(WorkerLoadInfo);
 }
@@ -154,16 +155,17 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo
   mReportCSPViolations = aOther.mReportCSPViolations;
   mXHRParamsAllowed = aOther.mXHRParamsAllowed;
   mPrincipalIsSystem = aOther.mPrincipalIsSystem;
   mStorageAllowed = aOther.mStorageAllowed;
   mFirstPartyStorageAccessGranted = aOther.mFirstPartyStorageAccessGranted;
   mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
   mOriginAttributes = aOther.mOriginAttributes;
   mParentController = aOther.mParentController;
+  mSecureContext = aOther.mSecureContext;
 }
 
 nsresult
 WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
                                          nsILoadGroup* aLoadGroup)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
--- a/dom/workers/WorkerLoadInfo.h
+++ b/dom/workers/WorkerLoadInfo.h
@@ -60,16 +60,23 @@ struct WorkerLoadInfo
   {
     NS_DECL_ISUPPORTS
 
   public:
     InterfaceRequestor(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
     void MaybeAddTabChild(nsILoadGroup* aLoadGroup);
     NS_IMETHOD GetInterface(const nsIID& aIID, void** aSink) override;
 
+    void SetOuterRequestor(nsIInterfaceRequestor* aOuterRequestor)
+    {
+      MOZ_ASSERT(!mOuterRequestor);
+      MOZ_ASSERT(aOuterRequestor);
+      mOuterRequestor = aOuterRequestor;
+    }
+
   private:
     ~InterfaceRequestor() { }
 
     already_AddRefed<nsITabChild> GetAnyLiveTabChild();
 
     nsCOMPtr<nsILoadContext> mLoadContext;
     nsCOMPtr<nsIInterfaceRequestor> mOuterRequestor;
 
@@ -102,16 +109,22 @@ struct WorkerLoadInfo
   bool mReportCSPViolations;
   bool mXHRParamsAllowed;
   bool mPrincipalIsSystem;
   bool mStorageAllowed;
   bool mFirstPartyStorageAccessGranted;
   bool mServiceWorkersTestingInWindow;
   OriginAttributes mOriginAttributes;
 
+  enum {
+    eNotSet,
+    eInsecureContext,
+    eSecureContext,
+  } mSecureContext;
+
   WorkerLoadInfo();
   ~WorkerLoadInfo();
 
   void StealFrom(WorkerLoadInfo& aOther);
 
   nsresult
   SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -14,29 +14,28 @@
 #include "mozilla/ScopeExit.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientSource.h"
 #include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/DOMTypes.h"
-#include "mozilla/dom/ErrorEvent.h"
-#include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PerformanceStorageWorker.h"
 #include "mozilla/dom/PromiseDebugging.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/ThreadEventQueue.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsCycleCollector.h"
 #include "nsGlobalWindowInner.h"
 #include "nsNetUtil.h"
@@ -52,17 +51,16 @@
 #include "nsRFPService.h"
 #include "nsSandboxFlags.h"
 #include "nsUTF8Utils.h"
 
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "mozilla/dom/ServiceWorkerEvents.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
-#include "SharedWorker.h"
 #include "WorkerCSPEventListener.h"
 #include "WorkerDebugger.h"
 #include "WorkerDebuggerManager.h"
 #include "WorkerError.h"
 #include "WorkerEventTarget.h"
 #include "WorkerNavigator.h"
 #include "WorkerRef.h"
 #include "WorkerRunnable.h"
@@ -881,49 +879,16 @@ public:
 #ifdef DEBUG
 static bool
 StartsWithExplicit(nsACString& s)
 {
     return StringBeginsWith(s, NS_LITERAL_CSTRING("explicit/"));
 }
 #endif
 
-class MessagePortRunnable final : public WorkerRunnable
-{
-  MessagePortIdentifier mPortIdentifier;
-
-public:
-  MessagePortRunnable(WorkerPrivate* aWorkerPrivate, MessagePort* aPort)
-  : WorkerRunnable(aWorkerPrivate)
-  {
-    MOZ_ASSERT(aPort);
-    // In order to move the port from one thread to another one, we have to
-    // close and disentangle it. The output will be a MessagePortIdentifier that
-    // will be used to recreate a new MessagePort on the other thread.
-    aPort->CloneAndDisentangle(mPortIdentifier);
-  }
-
-private:
-  ~MessagePortRunnable()
-  { }
-
-  virtual bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
-  }
-
-  nsresult
-  Cancel() override
-  {
-    MessagePort::ForceClose(mPortIdentifier);
-    return WorkerRunnable::Cancel();
-  }
-};
-
 PRThread*
 PRThreadFromThread(nsIThread* aThread)
 {
   MOZ_ASSERT(aThread);
 
   PRThread* result;
   MOZ_ALWAYS_SUCCEEDS(aThread->GetPRThread(&result));
   MOZ_ASSERT(result);
@@ -1734,23 +1699,16 @@ WorkerPrivate::Notify(WorkerStatus aStat
     if (mParentStatus >= aStatus) {
       return true;
     }
 
     pending = mParentStatus == Pending;
     mParentStatus = aStatus;
   }
 
-  if (IsSharedWorker()) {
-    RuntimeService* runtime = RuntimeService::GetService();
-    MOZ_ASSERT(runtime);
-
-    runtime->ForgetSharedWorker(this);
-  }
-
   if (pending) {
 #ifdef DEBUG
     {
       // Fake a thread here just so that our assertions don't go off for no
       // reason.
       nsIThread* currentThread = NS_GetCurrentThread();
       MOZ_ASSERT(currentThread);
 
@@ -1775,45 +1733,16 @@ WorkerPrivate::Notify(WorkerStatus aStat
   return runnable->Dispatch();
 }
 
 bool
 WorkerPrivate::Freeze(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnParentThread();
 
-  // Shared workers are only frozen if all of their owning documents are
-  // frozen. It can happen that mSharedWorkers is empty but this thread has
-  // not been unregistered yet.
-  if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
-    AssertIsOnMainThread();
-
-    bool allFrozen = true;
-
-    for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-      if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
-        // Calling Freeze() may change the refcount, ensure that the worker
-        // outlives this call.
-        RefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
-
-        kungFuDeathGrip->Freeze();
-      } else {
-        MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
-                      !SameCOMIdentity(mSharedWorkers[i]->GetOwner(), aWindow));
-        if (!mSharedWorkers[i]->IsFrozen()) {
-          allFrozen = false;
-        }
-      }
-    }
-
-    if (!allFrozen || mParentFrozen) {
-      return true;
-    }
-  }
-
   mParentFrozen = true;
 
   // WorkerDebuggeeRunnables sent from a worker to content must not be delivered
   // while the worker is frozen.
   //
   // Since a top-level worker and all its children share the same
   // mMainThreadDebuggeeEventTarget, it's sufficient to do this only in the
   // top-level worker.
@@ -1843,47 +1772,16 @@ WorkerPrivate::Freeze(nsPIDOMWindowInner
 
   return true;
 }
 
 bool
 WorkerPrivate::Thaw(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnParentThread();
-
-  // Shared workers are resumed if any of their owning documents are thawed.
-  // It can happen that mSharedWorkers is empty but this thread has not been
-  // unregistered yet.
-  if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
-    AssertIsOnMainThread();
-
-    bool anyRunning = false;
-
-    for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-      if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
-        // Calling Thaw() may change the refcount, ensure that the worker
-        // outlives this call.
-        RefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
-
-        kungFuDeathGrip->Thaw();
-        anyRunning = true;
-      } else {
-        MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
-                      !SameCOMIdentity(mSharedWorkers[i]->GetOwner(), aWindow));
-        if (!mSharedWorkers[i]->IsFrozen()) {
-          anyRunning = true;
-        }
-      }
-    }
-
-    if (!anyRunning || !mParentFrozen) {
-      return true;
-    }
-  }
-
   MOZ_ASSERT(mParentFrozen);
 
   mParentFrozen = false;
 
   // Delivery of WorkerDebuggeeRunnables to the window may resume.
   //
   // Since a top-level worker and all its children share the same
   // mMainThreadDebuggeeEventTarget, it's sufficient to do this only in the
@@ -1915,38 +1813,34 @@ WorkerPrivate::Thaw(nsPIDOMWindowInner* 
 
   return true;
 }
 
 void
 WorkerPrivate::ParentWindowPaused()
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT_IF(IsDedicatedWorker(), mParentWindowPausedDepth == 0);
-  mParentWindowPausedDepth += 1;
+  MOZ_ASSERT(!mParentWindowPaused);
+  mParentWindowPaused = true;
 
   // This is called from WorkerPrivate construction, and we may not have
   // allocated mMainThreadDebuggeeEventTarget yet.
   if (mMainThreadDebuggeeEventTarget) {
     // Pausing a ThrottledEventQueue is infallible.
     MOZ_ALWAYS_SUCCEEDS(mMainThreadDebuggeeEventTarget->SetIsPaused(true));
   }
 }
 
 void
 WorkerPrivate::ParentWindowResumed()
 {
   AssertIsOnMainThread();
 
-  MOZ_ASSERT(mParentWindowPausedDepth > 0);
-  MOZ_ASSERT_IF(IsDedicatedWorker(), mParentWindowPausedDepth == 1);
-  mParentWindowPausedDepth -= 1;
-  if (mParentWindowPausedDepth > 0) {
-    return;
-  }
+  MOZ_ASSERT(mParentWindowPaused);
+  mParentWindowPaused = false;
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mParentStatus >= Canceling) {
       return;
     }
   }
@@ -1989,17 +1883,17 @@ WorkerPrivate::Close()
   return true;
 }
 
 bool
 WorkerPrivate::ModifyBusyCount(bool aIncrease)
 {
   AssertIsOnParentThread();
 
-  NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
+  MOZ_ASSERT(aIncrease || mBusyCount, "Mismatched busy count mods!");
 
   if (aIncrease) {
     mBusyCount++;
     return true;
   }
 
   if (--mBusyCount == 0) {
 
@@ -2183,242 +2077,16 @@ void
 WorkerPrivate::MemoryPressure(bool aDummy)
 {
   AssertIsOnParentThread();
 
   RefPtr<MemoryPressureRunnable> runnable = new MemoryPressureRunnable(this);
   Unused << NS_WARN_IF(!runnable->Dispatch());
 }
 
-bool
-WorkerPrivate::RegisterSharedWorker(SharedWorker* aSharedWorker,
-                                    MessagePort* aPort)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aSharedWorker);
-  MOZ_ASSERT(IsSharedWorker());
-  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
-
-  if (IsSharedWorker()) {
-    RefPtr<MessagePortRunnable> runnable = new MessagePortRunnable(this, aPort);
-    if (!runnable->Dispatch()) {
-      return false;
-    }
-  }
-
-  mSharedWorkers.AppendElement(aSharedWorker);
-
-  // If there were other SharedWorker objects attached to this worker then they
-  // may all have been frozen and this worker would need to be thawed.
-  if (mSharedWorkers.Length() > 1 && IsFrozen() && !Thaw(nullptr)) {
-    return false;
-  }
-
-  return true;
-}
-
-void
-WorkerPrivate::BroadcastErrorToSharedWorkers(
-                                     JSContext* aCx,
-                                     const WorkerErrorReport* aReport,
-                                     bool aIsErrorEvent)
-{
-  AssertIsOnMainThread();
-
-  if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) {
-    // Don't fire any events anywhere.  Just log to console.
-    // XXXbz should we log to all the consoles of all the relevant windows?
-    MOZ_ASSERT(aReport);
-    WorkerErrorReport::LogErrorToConsole(*aReport, 0);
-    return;
-  }
-
-  AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
-  GetAllSharedWorkers(sharedWorkers);
-
-  if (sharedWorkers.IsEmpty()) {
-    return;
-  }
-
-  AutoTArray<WindowAction, 10> windowActions;
-
-  // First fire the error event at all SharedWorker objects. This may include
-  // multiple objects in a single window as well as objects in different
-  // windows.
-  for (size_t index = 0; index < sharedWorkers.Length(); index++) {
-    RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
-
-    // May be null.
-    nsPIDOMWindowInner* window = sharedWorker->GetOwner();
-
-    RefPtr<Event> event;
-
-    if (aIsErrorEvent) {
-      RootedDictionary<ErrorEventInit> errorInit(aCx);
-      errorInit.mBubbles = false;
-      errorInit.mCancelable = true;
-      errorInit.mMessage = aReport->mMessage;
-      errorInit.mFilename = aReport->mFilename;
-      errorInit.mLineno = aReport->mLineNumber;
-      errorInit.mColno = aReport->mColumnNumber;
-
-      event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
-                                      errorInit);
-    } else {
-      event = Event::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
-                                 EventInit());
-    }
-
-    if (!event) {
-      ThrowAndReport(window, NS_ERROR_UNEXPECTED);
-      continue;
-    }
-
-    event->SetTrusted(true);
-
-    ErrorResult res;
-    bool defaultActionEnabled =
-      sharedWorker->DispatchEvent(*event, CallerType::System, res);
-    if (res.Failed()) {
-      ThrowAndReport(window, res.StealNSResult());
-      continue;
-    }
-
-    if (!aIsErrorEvent) {
-      continue;
-    }
-
-    if (defaultActionEnabled) {
-      // Add the owning window to our list so that we will fire an error event
-      // at it later.
-      if (!windowActions.Contains(window)) {
-        windowActions.AppendElement(WindowAction(window));
-      }
-    } else {
-      size_t actionsIndex = windowActions.LastIndexOf(WindowAction(window));
-      if (actionsIndex != windowActions.NoIndex) {
-        // Any listener that calls preventDefault() will prevent the window from
-        // receiving the error event.
-        windowActions[actionsIndex].mDefaultAction = false;
-      }
-    }
-  }
-
-  // If there are no windows to consider further then we're done.
-  if (windowActions.IsEmpty()) {
-    return;
-  }
-
-  bool shouldLogErrorToConsole = true;
-
-  // Now fire error events at all the windows remaining.
-  for (uint32_t index = 0; index < windowActions.Length(); index++) {
-    WindowAction& windowAction = windowActions[index];
-
-    // If there is no window or the script already called preventDefault then
-    // skip this window.
-    if (!windowAction.mWindow || !windowAction.mDefaultAction) {
-      continue;
-    }
-
-    nsCOMPtr<nsIScriptGlobalObject> sgo =
-      do_QueryInterface(windowAction.mWindow);
-    MOZ_ASSERT(sgo);
-
-    MOZ_ASSERT(NS_IsMainThread());
-    RootedDictionary<ErrorEventInit> init(aCx);
-    init.mLineno = aReport->mLineNumber;
-    init.mFilename = aReport->mFilename;
-    init.mMessage = aReport->mMessage;
-    init.mCancelable = true;
-    init.mBubbles = true;
-
-    nsEventStatus status = nsEventStatus_eIgnore;
-    if (!sgo->HandleScriptError(init, &status)) {
-      ThrowAndReport(windowAction.mWindow, NS_ERROR_UNEXPECTED);
-      continue;
-    }
-
-    if (status == nsEventStatus_eConsumeNoDefault) {
-      shouldLogErrorToConsole = false;
-    }
-  }
-
-  // Finally log a warning in the console if no window tried to prevent it.
-  if (shouldLogErrorToConsole) {
-    MOZ_ASSERT(aReport);
-    WorkerErrorReport::LogErrorToConsole(*aReport, 0);
-  }
-}
-
-void
-WorkerPrivate::GetAllSharedWorkers(nsTArray<RefPtr<SharedWorker>>& aSharedWorkers)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-
-  if (!aSharedWorkers.IsEmpty()) {
-    aSharedWorkers.Clear();
-  }
-
-  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-    aSharedWorkers.AppendElement(mSharedWorkers[i]);
-  }
-}
-
-void
-WorkerPrivate::CloseSharedWorkersForWindow(nsPIDOMWindowInner* aWindow)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-  MOZ_ASSERT(aWindow);
-
-  bool someRemoved = false;
-
-  for (uint32_t i = 0; i < mSharedWorkers.Length();) {
-    if (mSharedWorkers[i]->GetOwner() == aWindow) {
-      mSharedWorkers[i]->Close();
-      mSharedWorkers.RemoveElementAt(i);
-      someRemoved = true;
-    } else {
-      MOZ_ASSERT(!SameCOMIdentity(mSharedWorkers[i]->GetOwner(), aWindow));
-      ++i;
-    }
-  }
-
-  if (!someRemoved) {
-    return;
-  }
-
-  // If there are still SharedWorker objects attached to this worker then they
-  // may all be frozen and this worker would need to be frozen. Otherwise,
-  // if that was the last SharedWorker then it's time to cancel this worker.
-
-  if (!mSharedWorkers.IsEmpty()) {
-    Freeze(nullptr);
-  } else {
-    Cancel();
-  }
-}
-
-void
-WorkerPrivate::CloseAllSharedWorkers()
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
-
-  for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
-    mSharedWorkers[i]->Close();
-  }
-
-  mSharedWorkers.Clear();
-
-  Cancel();
-}
-
 void
 WorkerPrivate::WorkerScriptLoaded()
 {
   AssertIsOnMainThread();
 
   if (IsSharedWorker() || IsServiceWorker()) {
     // No longer need to hold references to the window or document we came from.
     mLoadInfo.mWindow = nullptr;
@@ -2519,60 +2187,16 @@ void
 WorkerPrivate::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
 {
   AssertIsOnMainThread();
 
   // The load group should have been overriden at init time.
   mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
 }
 
-void
-WorkerPrivate::FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter)
-{
-  AssertIsOnMainThread();
-
-  AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
-  AutoTArray<WindowAction, 10> windowActions;
-  GetAllSharedWorkers(sharedWorkers);
-
-  // First find out all the shared workers' window.
-  for (size_t index = 0; index < sharedWorkers.Length(); index++) {
-    RefPtr<SharedWorker>& sharedWorker = sharedWorkers[index];
-
-    // May be null.
-    nsPIDOMWindowInner* window = sharedWorker->GetOwner();
-
-    // Add the owning window to our list so that we will flush the reports later.
-    if (window && !windowActions.Contains(window)) {
-      windowActions.AppendElement(WindowAction(window));
-    }
-  }
-
-  bool reportErrorToBrowserConsole = true;
-
-  // Flush the reports.
-  for (uint32_t index = 0; index < windowActions.Length(); index++) {
-    WindowAction& windowAction = windowActions[index];
-
-    aReporter->FlushReportsToConsole(
-      windowAction.mWindow->WindowID(),
-      nsIConsoleReportCollector::ReportAction::Save);
-    reportErrorToBrowserConsole = false;
-  }
-
-  // Finally report to browser console if there is no any window or shared
-  // worker.
-  if (reportErrorToBrowserConsole) {
-    aReporter->FlushReportsToConsole(0);
-    return;
-  }
-
-  aReporter->ClearConsoleReports();
-}
-
 #ifdef DEBUG
 
 void
 WorkerPrivate::AssertIsOnParentThread() const
 {
   if (GetParent()) {
     GetParent()->AssertIsOnWorkerThread();
   } else {
@@ -2641,17 +2265,17 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
                                                    WorkerEventTarget::Behavior::Hybrid))
   , mParentStatus(Pending)
   , mStatus(Pending)
   , mBusyCount(0)
   , mLoadingWorkerScript(false)
   , mCreationTimeStamp(TimeStamp::Now())
   , mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
   , mWorkerThreadAccessible(aParent)
-  , mParentWindowPausedDepth(0)
+  , mParentWindowPaused(false)
   , mPendingEventQueueClearing(false)
   , mCancelAllPendingRunnables(false)
   , mWorkerScriptExecutedSuccessfully(false)
   , mFetchHandlerWasAdded(false)
   , mMainThreadObjectsForgotten(false)
   , mIsChromeWorker(aIsChromeWorker)
   , mParentFrozen(false)
   , mIsSecureContext(false)
@@ -2684,21 +2308,18 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
   else {
     AssertIsOnMainThread();
 
     RuntimeService::GetDefaultJSSettings(mJSSettings);
 
     // Our secure context state depends on the kind of worker we have.
     if (UsesSystemPrincipal() || IsServiceWorker()) {
       mIsSecureContext = true;
-    } else if (mLoadInfo.mWindow) {
-      // Shared and dedicated workers both inherit the loading window's secure
-      // context state.  Shared workers then prevent windows with a different
-      // secure context state from attaching to them.
-      mIsSecureContext = mLoadInfo.mWindow->IsSecureContext();
+    } else if (mLoadInfo.mSecureContext != WorkerLoadInfo::eNotSet) {
+      mIsSecureContext = mLoadInfo.mSecureContext == WorkerLoadInfo::eSecureContext;
     } else {
       MOZ_ASSERT_UNREACHABLE("non-chrome worker that is not a service worker "
                              "that has no parent and no associated window");
     }
 
     if (mIsSecureContext) {
       mJSSettings.chrome.realmOptions
                  .creationOptions().setSecureContext(true);
@@ -3051,16 +2672,20 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
 
       loadInfo.mFromWindow = true;
       loadInfo.mWindowID = globalWindow->WindowID();
       nsContentUtils::StorageAccess access =
         nsContentUtils::StorageAllowedForWindow(globalWindow);
       loadInfo.mStorageAllowed = access > nsContentUtils::StorageAccess::eDeny;
       loadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(document);
       loadInfo.mParentController = globalWindow->GetController();
+      loadInfo.mSecureContext =
+        loadInfo.mWindow->IsSecureContext()
+          ? WorkerLoadInfo::eSecureContext
+          : WorkerLoadInfo::eInsecureContext;
     } else {
       // Not a window
       MOZ_ASSERT(isChrome);
 
       // We're being created outside of a window. Need to figure out the script
       // that is creating us in order for us to use relative URIs later on.
       JS::AutoFilename fileName;
       if (JS::DescribeScriptedCaller(aCx, &fileName)) {
@@ -3106,24 +2731,28 @@ WorkerPrivate::GetLoadInfo(JSContext* aC
     if (!loadInfo.mLoadGroup || aLoadGroupBehavior == OverrideLoadGroup) {
       OverrideLoadInfoLoadGroup(loadInfo, loadInfo.mLoadingPrincipal);
     }
     MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup,
                                             loadInfo.mLoadingPrincipal));
 
     // Top level workers' main script use the document charset for the script
     // uri encoding.
-    bool useDefaultEncoding = false;
+    nsCOMPtr<nsIURI> url;
+    rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(url),
+                                                   aScriptURL,
+                                                   document,
+                                                   loadInfo.mBaseURI);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
+
     rv = ChannelFromScriptURLMainThread(loadInfo.mLoadingPrincipal,
-                                        loadInfo.mBaseURI,
                                         document, loadInfo.mLoadGroup,
-                                        aScriptURL,
+                                        url,
                                         clientInfo,
                                         ContentPolicyType(aWorkerType),
-                                        useDefaultEncoding,
                                         getter_AddRefs(loadInfo.mChannel));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = NS_GetFinalChannelURI(loadInfo.mChannel,
                                getter_AddRefs(loadInfo.mResolvedScriptURI));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = loadInfo.SetPrincipalFromChannel(loadInfo.mChannel);
@@ -5277,17 +4906,17 @@ WorkerPrivate::EndCTypesCall()
   AssertIsOnWorkerThread();
 
   // Make sure the periodic timer is running before we start running JS again.
   SetGCTimerMode(PeriodicTimer);
 }
 
 bool
 WorkerPrivate::ConnectMessagePort(JSContext* aCx,
-                                  MessagePortIdentifier& aIdentifier)
+                                  const MessagePortIdentifier& aIdentifier)
 {
   AssertIsOnWorkerThread();
 
   WorkerGlobalScope* globalScope = GlobalScope();
 
   JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
   MOZ_ASSERT(jsGlobal);
 
@@ -5444,16 +5073,34 @@ WorkerPrivate::GetPerformanceCounter()
 PerformanceStorage*
 WorkerPrivate::GetPerformanceStorage()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mPerformanceStorage);
   return mPerformanceStorage;
 }
 
+void
+WorkerPrivate::SetRemoteWorkerController(RemoteWorkerChild* aController)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aController);
+  MOZ_ASSERT(!mRemoteWorkerController);
+
+  mRemoteWorkerController = aController;
+}
+
+RemoteWorkerChild*
+WorkerPrivate::GetRemoteWorkerController()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mRemoteWorkerController);
+  return mRemoteWorkerController;
+}
+
 NS_IMPL_ADDREF(WorkerPrivate::EventTarget)
 NS_IMPL_RELEASE(WorkerPrivate::EventTarget)
 
 NS_INTERFACE_MAP_BEGIN(WorkerPrivate::EventTarget)
   NS_INTERFACE_MAP_ENTRY(nsISerialEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 #ifdef DEBUG
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -18,17 +18,16 @@
 #include "mozilla/dom/Worker.h"
 #include "mozilla/dom/WorkerHolder.h"
 #include "mozilla/dom/WorkerLoadInfo.h"
 #include "mozilla/dom/workerinternals/JSSettings.h"
 #include "mozilla/dom/workerinternals/Queue.h"
 #include "mozilla/PerformanceCounter.h"
 #include "mozilla/ThreadBound.h"
 
-class nsIConsoleReportCollector;
 class nsIThreadInternal;
 
 namespace mozilla {
 class ThrottledEventQueue;
 namespace dom {
 
 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
 // to be updated too.
@@ -40,17 +39,17 @@ enum WorkerType
 };
 
 class ClientInfo;
 class ClientSource;
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PerformanceStorage;
-class SharedWorker;
+class RemoteWorkerChild;
 class WorkerControlRunnable;
 class WorkerCSPEventListener;
 class WorkerDebugger;
 class WorkerDebuggerGlobalScope;
 class WorkerErrorReport;
 class WorkerEventTarget;
 class WorkerGlobalScope;
 class WorkerRunnable;
@@ -457,17 +456,17 @@ public:
   EndCTypesCallback()
   {
     // If a callback is ending then we need to do the exact same thing as
     // when a ctypes call begins.
     BeginCTypesCall();
   }
 
   bool
-  ConnectMessagePort(JSContext* aCx, MessagePortIdentifier& aIdentifier);
+  ConnectMessagePort(JSContext* aCx, const MessagePortIdentifier& aIdentifier);
 
   WorkerGlobalScope*
   GetOrCreateGlobalScope(JSContext* aCx);
 
   WorkerDebuggerGlobalScope*
   CreateDebuggerGlobalScope(JSContext* aCx);
 
   bool
@@ -718,17 +717,17 @@ public:
     AssertIsOnParentThread();
     return mParentFrozen;
   }
 
   bool
   IsParentWindowPaused() const
   {
     AssertIsOnParentThread();
-    return mParentWindowPausedDepth > 0;
+    return mParentWindowPaused;
   }
 
   // When we debug a worker, we want to disconnect the window and the worker
   // communication. This happens calling this method.
   // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
   void
   ParentWindowPaused();
 
@@ -1075,42 +1074,24 @@ public:
   // top level script.
   void
   SetLoadingWorkerScript(bool aLoadingWorkerScript)
   {
     // any thread
     mLoadingWorkerScript = aLoadingWorkerScript;
   }
 
-  bool
-  RegisterSharedWorker(SharedWorker* aSharedWorker, MessagePort* aPort);
-
-  void
-  BroadcastErrorToSharedWorkers(JSContext* aCx,
-                                const WorkerErrorReport* aReport,
-                                bool aIsErrorEvent);
+  RemoteWorkerChild*
+  GetRemoteWorkerController();
 
   void
-  GetAllSharedWorkers(nsTArray<RefPtr<SharedWorker>>& aSharedWorkers);
-
-  void
-  CloseSharedWorkersForWindow(nsPIDOMWindowInner* aWindow);
-
-  void
-  CloseAllSharedWorkers();
-
-  void
-  FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter);
+  SetRemoteWorkerController(RemoteWorkerChild* aController);
 
   // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
   // as these are only used for globals going in and out of the bfcache.
-  //
-  // XXXbz: This is a bald-faced lie given the uses in RegisterSharedWorker and
-  // CloseSharedWorkersForWindow, which pass null for aWindow to Thaw and Freeze
-  // respectively.  See bug 1251722.
   bool
   Freeze(nsPIDOMWindowInner* aWindow);
 
   bool
   Thaw(nsPIDOMWindowInner* aWindow);
 
   void
   PropagateFirstPartyStorageAccessGranted();
@@ -1406,19 +1387,18 @@ private:
 
   RefPtr<PerformanceStorage> mPerformanceStorage;
 
   RefPtr<WorkerCSPEventListener> mCSPEventListener;
 
   // Protected by mMutex.
   nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
 
-  // Only touched on the parent thread (currently this is always the main
-  // thread as SharedWorkers are always top-level).
-  nsTArray<RefPtr<SharedWorker>> mSharedWorkers;
+  // Only touched on the parent thread. This is set only if IsSharedWorker().
+  RefPtr<RemoteWorkerChild> mRemoteWorkerController;
 
   JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
   TimeStamp mKillTime;
   WorkerStatus mParentStatus;
   WorkerStatus mStatus;
 
   // This is touched on parent thread only, but it can be read on a different
   // thread before crashing because hanging.
@@ -1459,19 +1439,17 @@ private:
     bool mTimerRunning;
     bool mRunningExpiredTimeouts;
     bool mPeriodicGCTimerRunning;
     bool mIdleGCTimerRunning;
     bool mOnLine;
   };
   ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible;
 
-  // SharedWorkers may have multiple windows paused, so this must be
-  // a count instead of just a boolean.
-  uint32_t mParentWindowPausedDepth;
+  bool mParentWindowPaused;
 
   bool mPendingEventQueueClearing;
   bool mCancelAllPendingRunnables;
   bool mWorkerScriptExecutedSuccessfully;
   bool mFetchHandlerWasAdded;
   bool mMainThreadObjectsForgotten;
   bool mIsChromeWorker;
   bool mParentFrozen;
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -2,40 +2,43 @@
 # vim: set filetype=python:
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Workers")
 
+DIRS += ['remoteworkers', 'sharedworkers']
+
 # Public stuff.
 EXPORTS.mozilla.dom += [
     'ChromeWorker.h',
-    'SharedWorker.h',
     'Worker.h',
     'WorkerCommon.h',
     'WorkerDebugger.h',
     'WorkerDebuggerManager.h',
+    'WorkerError.h',
     'WorkerHolder.h',
     'WorkerHolderToken.h',
     'WorkerLoadInfo.h',
     'WorkerLocation.h',
     'WorkerNavigator.h',
     'WorkerPrivate.h',
     'WorkerRef.h',
     'WorkerRunnable.h',
     'WorkerScope.h',
 ]
 
 # Private stuff.
 EXPORTS.mozilla.dom.workerinternals += [
     'JSSettings.h',
     'Queue.h',
     'RuntimeService.h',
+    'ScriptLoader.h',
 ]
 
 XPIDL_MODULE = 'dom_workers'
 
 XPIDL_SOURCES += [
     'nsIWorkerDebugger.idl',
     'nsIWorkerDebuggerManager.idl',
 ]
@@ -43,17 +46,16 @@ XPIDL_SOURCES += [
 UNIFIED_SOURCES += [
     'ChromeWorker.cpp',
     'ChromeWorkerScope.cpp',
     'MessageEventRunnable.cpp',
     'Principal.cpp',
     'RegisterBindings.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
-    'SharedWorker.cpp',
     'Worker.cpp',
     'WorkerCSPEventListener.cpp',
     'WorkerDebugger.cpp',
     'WorkerDebuggerManager.cpp',
     'WorkerError.cpp',
     'WorkerEventTarget.cpp',
     'WorkerHolder.cpp',
     'WorkerHolderToken.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/PRemoteWorker.ipdl
@@ -0,0 +1,75 @@
+/* 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 protocol PBackground;
+
+include DOMTypes;
+include RemoteWorkerTypes;
+
+namespace mozilla {
+namespace dom {
+
+struct RemoteWorkerSuspendOp
+{};
+
+struct RemoteWorkerResumeOp
+{};
+
+struct RemoteWorkerFreezeOp
+{};
+
+struct RemoteWorkerThawOp
+{};
+
+struct RemoteWorkerTerminateOp
+{};
+
+struct RemoteWorkerPortIdentifierOp
+{
+  MessagePortIdentifier portIdentifier;
+};
+
+struct RemoteWorkerAddWindowIDOp
+{
+  uint64_t windowID;
+};
+
+struct RemoteWorkerRemoveWindowIDOp
+{
+  uint64_t windowID;
+};
+
+union RemoteWorkerOp {
+  RemoteWorkerSuspendOp;
+  RemoteWorkerResumeOp;
+  RemoteWorkerFreezeOp;
+  RemoteWorkerThawOp;
+  RemoteWorkerTerminateOp;
+  RemoteWorkerPortIdentifierOp;
+  RemoteWorkerAddWindowIDOp;
+  RemoteWorkerRemoveWindowIDOp;
+};
+
+// This protocol is used to make a remote worker controllable from the parent
+// process. The parent process will receive operations from the
+// PRemoteWorkerController protocol.
+protocol PRemoteWorker
+{
+  manager PBackground;
+
+parent:
+  async Created(bool aStatus);
+
+  async Error(ErrorValue aValue);
+
+  async Close();
+
+child:
+  async __delete__();
+
+  async ExecOp(RemoteWorkerOp op);
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/PRemoteWorkerService.ipdl
@@ -0,0 +1,24 @@
+/* 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 protocol PBackground;
+
+include ProtocolTypes;
+include RemoteWorkerTypes;
+
+namespace mozilla {
+namespace dom {
+
+// Simple protocol to register any active RemoteWorkerService running on any
+// process.
+protocol PRemoteWorkerService
+{
+  manager PBackground;
+
+parent:
+  async __delete__();
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -0,0 +1,733 @@
+/* -*- 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 "RemoteWorkerChild.h"
+#include "RemoteWorkerService.h"
+#include "mozilla/dom/IndexedDatabaseManager.h"
+#include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/RemoteWorkerTypes.h"
+#include "mozilla/dom/ServiceWorkerInterceptController.h"
+#include "mozilla/dom/workerinternals/ScriptLoader.h"
+#include "mozilla/dom/WorkerError.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRef.h"
+#include "mozilla/dom/WorkerRunnable.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/ipc/URIUtils.h"
+#include "nsIConsoleReportCollector.h"
+#include "nsIPrincipal.h"
+#include "nsNetUtil.h"
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+using workerinternals::ChannelFromScriptURLMainThread;
+
+namespace {
+
+nsresult
+PopulateContentSecurityPolicy(nsIContentSecurityPolicy* aCSP,
+                              const nsTArray<ContentSecurityPolicy>& aPolicies)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aCSP);
+  MOZ_ASSERT(!aPolicies.IsEmpty());
+
+  for (const ContentSecurityPolicy& policy : aPolicies) {
+    nsresult rv = aCSP->AppendPolicy(policy.policy(),
+                                     policy.reportOnlyFlag(),
+                                     policy.deliveredViaMetaTagFlag());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+PopulatePrincipalContentSecurityPolicy(nsIPrincipal* aPrincipal,
+                                       const nsTArray<ContentSecurityPolicy>& aPolicies,
+                                       const nsTArray<ContentSecurityPolicy>& aPreloadPolicies)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+
+  if (!aPolicies.IsEmpty()) {
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    aPrincipal->EnsureCSP(nullptr, getter_AddRefs(csp));
+    nsresult rv = PopulateContentSecurityPolicy(csp, aPolicies);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  if (!aPreloadPolicies.IsEmpty()) {
+    nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
+    aPrincipal->EnsurePreloadCSP(nullptr, getter_AddRefs(preloadCsp));
+    nsresult rv = PopulateContentSecurityPolicy(preloadCsp, aPreloadPolicies);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
+class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  SharedWorkerInterfaceRequestor()
+    : mSWController(new ServiceWorkerInterceptController())
+  {}
+
+  NS_IMETHOD
+  GetInterface(const nsIID& aIID, void** aSink) override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
+      // If asked for the network intercept controller, ask the outer requestor,
+      // which could be the docshell.
+      RefPtr<ServiceWorkerInterceptController> swController = mSWController;
+      swController.forget(aSink);
+      return NS_OK;
+    }
+
+    return NS_NOINTERFACE;
+  }
+
+private:
+  ~SharedWorkerInterfaceRequestor() = default;
+
+  RefPtr<ServiceWorkerInterceptController> mSWController;
+};
+
+NS_IMPL_ADDREF(SharedWorkerInterfaceRequestor)
+NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
+NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
+
+// Normal runnable because AddPortIdentifier() is going to exec JS code.
+class MessagePortIdentifierRunnable final : public WorkerRunnable
+{
+public:
+  MessagePortIdentifierRunnable(WorkerPrivate* aWorkerPrivate,
+                                RemoteWorkerChild* aActor,
+                                const MessagePortIdentifier& aPortIdentifier)
+    : WorkerRunnable(aWorkerPrivate)
+    , mActor(aActor)
+    , mPortIdentifier(aPortIdentifier)
+  {}
+
+private:
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    mActor->AddPortIdentifier(aCx, aWorkerPrivate, mPortIdentifier);
+    return true;
+  }
+
+  nsresult
+  Cancel() override
+  {
+    MessagePort::ForceClose(mPortIdentifier);
+    return WorkerRunnable::Cancel();
+  }
+
+  virtual bool
+  PreDispatch(WorkerPrivate* aWorkerPrivate) override
+  {
+    // Silence bad assertions.
+    return true;
+  }
+
+  virtual void
+  PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
+  {
+    // Silence bad assertions.
+  }
+
+  bool
+  PreRun(WorkerPrivate* aWorkerPrivate) override
+  {
+    // Silence bad assertions.
+    return true;
+  }
+
+  void
+  PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+          bool aRunResult) override
+  {
+    // Silence bad assertions.
+    return;
+  }
+
+
+  RefPtr<RemoteWorkerChild> mActor;
+  MessagePortIdentifier mPortIdentifier;
+};
+
+} // anonymous
+
+class RemoteWorkerChild::InitializeWorkerRunnable final : public WorkerRunnable
+{
+public:
+  InitializeWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+                           RemoteWorkerChild* aActor)
+    : WorkerRunnable(aWorkerPrivate)
+    , mActor(aActor)
+  {}
+
+private:
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    mActor->InitializeOnWorker(aWorkerPrivate);
+    return true;
+  }
+
+  nsresult
+  Cancel() override
+  {
+    mActor->CreationFailedOnAnyThread();
+    mActor->ShutdownOnWorker();
+    return WorkerRunnable::Cancel();
+  }
+
+  RefPtr<RemoteWorkerChild> mActor;
+};
+
+RemoteWorkerChild::RemoteWorkerChild()
+  : mIPCActive(true)
+  , mWorkerState(ePending)
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+}
+
+RemoteWorkerChild::~RemoteWorkerChild()
+{
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+
+  NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate",
+                  target, mWorkerPrivate.forget());
+}
+
+void
+RemoteWorkerChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mIPCActive = false;
+  mPendingOps.Clear();
+}
+
+void
+RemoteWorkerChild::ExecWorker(const RemoteWorkerData& aData)
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+  MOZ_ASSERT(mIPCActive);
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ExecWorker",
+                           [self, aData]() {
+      nsresult rv = self->ExecWorkerOnMainThread(aData);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        self->CreationFailedOnAnyThread();
+      }
+  });
+
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+nsresult
+RemoteWorkerChild::ExecWorkerOnMainThread(const RemoteWorkerData& aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Ensure that the IndexedDatabaseManager is initialized
+  Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
+
+  nsresult rv = NS_OK;
+
+  nsCOMPtr<nsIPrincipal> principal =
+    PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = PopulatePrincipalContentSecurityPolicy(principal,
+                                              aData.principalCsp(),
+                                              aData.principalPreloadCsp());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIPrincipal> loadingPrincipal =
+    PrincipalInfoToPrincipal(aData.loadingPrincipalInfo(), &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = PopulatePrincipalContentSecurityPolicy(loadingPrincipal,
+                                              aData.loadingPrincipalCsp(),
+                                              aData.loadingPrincipalPreloadCsp());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  WorkerLoadInfo info;
+  info.mBaseURI = DeserializeURI(aData.baseScriptURL());
+  info.mResolvedScriptURI = DeserializeURI(aData.resolvedScriptURL());
+
+  info.mPrincipalInfo = new PrincipalInfo(aData.principalInfo());
+
+  info.mDomain = aData.domain();
+  info.mPrincipal = principal;
+  info.mLoadingPrincipal = loadingPrincipal;
+
+  nsContentUtils::StorageAccess access =
+    nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
+  info.mStorageAllowed =
+    access > nsContentUtils::StorageAccess::ePrivateBrowsing;
+  info.mOriginAttributes =
+    BasePrincipal::Cast(principal)->OriginAttributesRef();
+
+  // Default CSP permissions for now.  These will be overrided if necessary
+  // based on the script CSP headers during load in ScriptLoader.
+  info.mEvalAllowed = true;
+  info.mReportCSPViolations = false;
+  info.mSecureContext = aData.isSecureContext()
+    ? WorkerLoadInfo::eSecureContext : WorkerLoadInfo::eInsecureContext;
+
+  WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mLoadingPrincipal);
+
+  RefPtr<SharedWorkerInterfaceRequestor> requestor =
+    new SharedWorkerInterfaceRequestor();
+  info.mInterfaceRequestor->SetOuterRequestor(requestor);
+
+  rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  Maybe<ClientInfo> clientInfo;
+  if (aData.clientInfo().type() == OptionalIPCClientInfo::TIPCClientInfo) {
+    clientInfo.emplace(ClientInfo(aData.clientInfo().get_IPCClientInfo()));
+  }
+
+  // Top level workers' main script use the document charset for the script
+  // uri encoding.
+  rv = ChannelFromScriptURLMainThread(info.mLoadingPrincipal,
+                                      nullptr /* parent document */,
+                                      info.mLoadGroup,
+                                      info.mResolvedScriptURI,
+                                      clientInfo,
+                                      aData.isSharedWorker()
+                                        ? nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
+                                        : nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER,
+                                      getter_AddRefs(info.mChannel));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+
+  ErrorResult error;
+  mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
+                                              aData.originalScriptURL(),
+                                              false,
+                                              aData.isSharedWorker()
+                                                ? WorkerTypeShared
+                                                : WorkerTypeService,
+                                              aData.name(),
+                                              VoidCString(),
+                                              &info, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.StealNSResult();
+  }
+
+  RefPtr<InitializeWorkerRunnable> runnable =
+    new InitializeWorkerRunnable(mWorkerPrivate, this);
+  if (NS_WARN_IF(!runnable->Dispatch())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mWorkerPrivate->SetRemoteWorkerController(this);
+  return NS_OK;
+}
+
+void
+RemoteWorkerChild::InitializeOnWorker(WorkerPrivate* aWorkerPrivate)
+{
+  MOZ_ASSERT(aWorkerPrivate);
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  RefPtr<RemoteWorkerChild> self = this;
+  mWorkerRef = WeakWorkerRef::Create(mWorkerPrivate, [self]() {
+      self->ShutdownOnWorker();
+    });
+
+  if (NS_WARN_IF(!mWorkerRef)) {
+    CreationFailedOnAnyThread();
+    ShutdownOnWorker();
+    return;
+  }
+
+  CreationSucceededOnAnyThread();
+}
+
+void
+RemoteWorkerChild::ShutdownOnWorker()
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+
+  // This will release the worker.
+  mWorkerRef = nullptr;
+
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+
+  NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate",
+                  target, mWorkerPrivate.forget());
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ShutdownOnWorker",
+                           [self]() {
+      self->WorkerTerminated();
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::WorkerTerminated()
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  mWorkerState = eTerminated;
+  mPendingOps.Clear();
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  Unused << SendClose();
+  mIPCActive = false;
+}
+
+void
+RemoteWorkerChild::ErrorPropagationDispatch(nsresult aError)
+{
+  MOZ_ASSERT(NS_FAILED(aError));
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ErrorPropagationDispatch",
+                           [self, aError]() {
+      self->ErrorPropagation(aError);
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
+                                                bool aIsErrorEvent)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ErrorValue value;
+  if (aIsErrorEvent) {
+    nsTArray<ErrorDataNote> notes;
+    for (size_t i = 0, len = aReport->mNotes.Length(); i < len; i++) {
+      const WorkerErrorNote& note = aReport->mNotes.ElementAt(i);
+      notes.AppendElement(ErrorDataNote(note.mLineNumber, note.mColumnNumber,
+                                        note.mMessage, note.mFilename));
+    }
+
+    ErrorData data(aReport->mLineNumber,
+                   aReport->mColumnNumber,
+                   aReport->mFlags,
+                   aReport->mMessage,
+                   aReport->mFilename,
+                   aReport->mLine,
+                   notes);
+    value = data;
+  } else {
+    value = void_t();
+  }
+
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::ErrorPropagationOnMainThread",
+                           [self, value]() {
+    self->ErrorPropagation(value);
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::ErrorPropagation(const ErrorValue& aValue)
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  Unused << SendError(aValue);
+}
+
+void
+RemoteWorkerChild::CloseWorkerOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mWorkerState == ePending) {
+    mWorkerState = ePendingTerminated;
+    // Already released.
+    return;
+  }
+
+  // The holder will be notified by this.
+  if (mWorkerState == eRunning) {
+    MOZ_ASSERT(mWorkerPrivate);
+    mWorkerPrivate->Cancel();
+  }
+}
+
+void
+RemoteWorkerChild::FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  bool reportErrorToBrowserConsole = true;
+
+  // Flush the reports.
+  for (uint32_t i = 0, len = mWindowIDs.Length(); i < len; ++i) {
+    aReporter->FlushReportsToConsole(mWindowIDs[i],
+      nsIConsoleReportCollector::ReportAction::Save);
+    reportErrorToBrowserConsole = false;
+  }
+
+  // Finally report to browser console if there is no any window.
+  if (reportErrorToBrowserConsole) {
+    aReporter->FlushReportsToConsole(0);
+    return;
+  }
+
+  aReporter->ClearConsoleReports();
+}
+
+IPCResult
+RemoteWorkerChild::RecvExecOp(const RemoteWorkerOp& aOp)
+{
+  if (!mIPCActive) {
+    return IPC_OK();
+  }
+
+  // The worker is not ready yet.
+  if (mWorkerState == ePending) {
+    mPendingOps.AppendElement(aOp);
+    return IPC_OK();
+  }
+
+  if (mWorkerState == eTerminated || mWorkerState == ePendingTerminated) {
+    // No op.
+    return IPC_OK();
+  }
+
+  MOZ_ASSERT(mWorkerState == eRunning);
+
+  // Main-thread operations
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp ||
+      aOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
+    RefPtr<RemoteWorkerChild> self = this;
+    nsCOMPtr<nsIRunnable> r =
+      NS_NewRunnableFunction("RemoteWorkerChild::RecvExecOp",
+                             [self, aOp]() {
+        self->RecvExecOpOnMainThread(aOp);
+    });
+
+    nsCOMPtr<nsIEventTarget> target =
+      SystemGroup::EventTargetFor(TaskCategory::Other);
+    target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+    return IPC_OK();
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
+    const RemoteWorkerPortIdentifierOp& op =
+      aOp.get_RemoteWorkerPortIdentifierOp();
+    RefPtr<MessagePortIdentifierRunnable> runnable =
+      new MessagePortIdentifierRunnable(mWorkerPrivate, this,
+                                        op.portIdentifier());
+    if (NS_WARN_IF(!runnable->Dispatch())) {
+      ErrorPropagation(NS_ERROR_FAILURE);
+    }
+    return IPC_OK();
+  }
+
+  MOZ_CRASH("Unknown operation.");
+
+  return IPC_OK();
+}
+
+void
+RemoteWorkerChild::RecvExecOpOnMainThread(const RemoteWorkerOp& aOp)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->ParentWindowPaused();
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->ParentWindowResumed();
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->Freeze(nullptr);
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp) {
+    if (mWorkerPrivate) {
+      mWorkerPrivate->Thaw(nullptr);
+    }
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp) {
+    CloseWorkerOnMainThread();
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp) {
+    mWindowIDs.AppendElement(aOp.get_RemoteWorkerAddWindowIDOp().windowID());
+    return;
+  }
+
+  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
+    mWindowIDs.RemoveElement(aOp.get_RemoteWorkerRemoveWindowIDOp().windowID());
+    return;
+  }
+
+  MOZ_CRASH("No other operations should be scheduled on main-thread.");
+}
+
+void
+RemoteWorkerChild::AddPortIdentifier(JSContext* aCx,
+                                     WorkerPrivate* aWorkerPrivate,
+                                     const MessagePortIdentifier& aPortIdentifier)
+{
+  if (NS_WARN_IF(!aWorkerPrivate->ConnectMessagePort(aCx, aPortIdentifier))) {
+    ErrorPropagationDispatch(NS_ERROR_FAILURE);
+  }
+}
+
+void
+RemoteWorkerChild::CreationSucceededOnAnyThread()
+{
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceededOnAnyThread",
+                           [self]() {
+    self->CreationSucceeded();
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::CreationSucceeded()
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  // The worker is created but we need to terminate it already.
+  if (mWorkerState == ePendingTerminated) {
+    RefPtr<RemoteWorkerChild> self = this;
+    nsCOMPtr<nsIRunnable> r =
+      NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceeded",
+                             [self]() {
+        self->CloseWorkerOnMainThread();
+    });
+
+    nsCOMPtr<nsIEventTarget> target =
+      SystemGroup::EventTargetFor(TaskCategory::Other);
+    target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+    return;
+  }
+
+  mWorkerState = eRunning;
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  for (const RemoteWorkerOp& op : mPendingOps) {
+    RecvExecOp(op);
+  }
+
+  mPendingOps.Clear();
+
+  Unused << SendCreated(true);
+}
+
+void
+RemoteWorkerChild::CreationFailedOnAnyThread()
+{
+  RefPtr<RemoteWorkerChild> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerChild::CreationFailedOnAnyThread",
+                           [self]() {
+    self->CreationFailed();
+  });
+
+  RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteWorkerChild::CreationFailed()
+{
+  MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
+
+  mWorkerState = eTerminated;
+  mPendingOps.Clear();
+
+  if (!mIPCActive) {
+    return;
+  }
+
+  Unused << SendCreated(false);
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.h
@@ -0,0 +1,127 @@
+/* -*- 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_RemoteWorkerChild_h
+#define mozilla_dom_RemoteWorkerChild_h
+
+#include "mozilla/dom/PRemoteWorkerChild.h"
+#include "mozilla/UniquePtr.h"
+#include "nsISupportsImpl.h"
+
+class nsIConsoleReportCollector;
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWorkerData;
+class WeakWorkerRef;
+class WorkerErrorReport;
+class WorkerPrivate;
+class OptionalMessagePortIdentifier;
+
+class RemoteWorkerChild final : public PRemoteWorkerChild
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteWorkerChild)
+
+  RemoteWorkerChild();
+
+  void
+  ExecWorker(const RemoteWorkerData& aData);
+
+  void
+  InitializeOnWorker(WorkerPrivate* aWorkerPrivate);
+
+  void
+  ShutdownOnWorker();
+
+  void
+  AddPortIdentifier(JSContext* aCx,
+                    WorkerPrivate* aWorkerPrivate,
+                    const MessagePortIdentifier& aPortIdentifier);
+
+  void
+  ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
+                               bool aIsErrorEvent);
+
+  void
+  CloseWorkerOnMainThread();
+
+  void
+  FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter);
+
+private:
+  class InitializeWorkerRunnable;
+
+  ~RemoteWorkerChild();
+
+  void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  mozilla::ipc::IPCResult
+  RecvExecOp(const RemoteWorkerOp& aOp) override;
+
+  void
+  RecvExecOpOnMainThread(const RemoteWorkerOp& aOp);
+
+  nsresult
+  ExecWorkerOnMainThread(const RemoteWorkerData& aData);
+
+  void
+  ErrorPropagation(const ErrorValue& aValue);
+
+  void
+  ErrorPropagationDispatch(nsresult aError);
+
+  void
+  CreationSucceededOnAnyThread();
+
+  void
+  CreationSucceeded();
+
+  void
+  CreationFailedOnAnyThread();
+
+  void
+  CreationFailed();
+
+  void
+  WorkerTerminated();
+
+  // Touched on main-thread only.
+  nsTArray<uint64_t> mWindowIDs;
+
+  RefPtr<WorkerPrivate> mWorkerPrivate;
+  RefPtr<WeakWorkerRef> mWorkerRef;
+  bool mIPCActive;
+
+  enum WorkerState
+  {
+    // CreationSucceeded/CreationFailed not called yet.
+    ePending,
+
+    // The worker is not created yet, but we want to terminate as soon as
+    // possible.
+    ePendingTerminated,
+
+    // Worker up and running.
+    eRunning,
+
+    // Worker terminated.
+    eTerminated,
+  };
+
+  // Touched only on the owning thread (Worker Launcher).
+  WorkerState mWorkerState;
+
+  // Touched only on the owning thread (Worker Launcher).
+  nsTArray<RemoteWorkerOp> mPendingOps;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerChild_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerController.cpp
@@ -0,0 +1,345 @@
+/* -*- 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/MessagePort.h"
+#include "mozilla/dom/MessagePortParent.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "RemoteWorkerController.h"
+#include "RemoteWorkerManager.h"
+#include "RemoteWorkerParent.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+/* static */ already_AddRefed<RemoteWorkerController>
+RemoteWorkerController::Create(const RemoteWorkerData& aData,
+                               RemoteWorkerObserver* aObserver,
+                               base::ProcessId aProcessId)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aObserver);
+
+  RefPtr<RemoteWorkerController> controller =
+    new RemoteWorkerController(aObserver);
+
+  RefPtr<RemoteWorkerManager> manager = RemoteWorkerManager::GetOrCreate();
+  MOZ_ASSERT(manager);
+
+  manager->Launch(controller, aData, aProcessId);
+
+  return controller.forget();
+}
+
+RemoteWorkerController::RemoteWorkerController(RemoteWorkerObserver* aObserver)
+  : mObserver(aObserver)
+  , mState(ePending)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+RemoteWorkerController::~RemoteWorkerController()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+void
+RemoteWorkerController::SetWorkerActor(RemoteWorkerParent* aActor)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(!mActor);
+  MOZ_ASSERT(aActor);
+
+  mActor = aActor;
+}
+
+void
+RemoteWorkerController::CreationFailed()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == ePending || mState == eTerminated);
+
+  if (mState == eTerminated) {
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mPendingOps.IsEmpty());
+    // Nothing to do.
+    return;
+  }
+
+  Shutdown();
+  mObserver->CreationFailed();
+}
+
+void
+RemoteWorkerController::CreationSucceeded()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == ePending || mState == eTerminated);
+
+  if (mState == eTerminated) {
+    MOZ_ASSERT(!mActor);
+    MOZ_ASSERT(mPendingOps.IsEmpty());
+    // Nothing to do.
+    return;
+  }
+
+  MOZ_ASSERT(mActor);
+  mState = eReady;
+
+  mObserver->CreationSucceeded();
+
+  for (UniquePtr<Op>& op : mPendingOps) {
+    switch (op->mType) {
+      case Op::eTerminate:
+        Terminate();
+        break;
+
+      case Op::eSuspend:
+        Suspend();
+        break;
+
+      case Op::eResume:
+        Resume();
+        break;
+
+      case Op::eFreeze:
+        Freeze();
+        break;
+
+      case Op::eThaw:
+        Thaw();
+        break;
+
+      case Op::ePortIdentifier:
+        AddPortIdentifier(op->mPortIdentifier);
+        break;
+
+      case Op::eAddWindowID:
+        AddWindowID(op->mWindowID);
+        break;
+
+      case Op::eRemoveWindowID:
+        RemoveWindowID(op->mWindowID);
+        break;
+
+      default:
+        MOZ_CRASH("Unknown op.");
+    }
+
+    op->Completed();
+  }
+
+  mPendingOps.Clear();
+}
+
+void
+RemoteWorkerController::ErrorPropagation(const ErrorValue& aValue)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  mObserver->ErrorReceived(aValue);
+}
+
+void
+RemoteWorkerController::WorkerTerminated()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == eReady);
+
+  mObserver->Terminated();
+  Shutdown();
+}
+
+void
+RemoteWorkerController::Shutdown()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mState == ePending || mState == eReady);
+
+  mState = eTerminated;
+
+  mPendingOps.Clear();
+
+  if (mActor) {
+    mActor->SetController(nullptr);
+    Unused << mActor->SendExecOp(RemoteWorkerTerminateOp());
+    mActor = nullptr;
+  }
+}
+
+void
+RemoteWorkerController::AddWindowID(uint64_t aWindowID)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aWindowID);
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eAddWindowID, aWindowID));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerAddWindowIDOp(aWindowID));
+}
+
+void
+RemoteWorkerController::RemoveWindowID(uint64_t aWindowID)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aWindowID);
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eRemoveWindowID, aWindowID));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerRemoveWindowIDOp(aWindowID));
+}
+
+void
+RemoteWorkerController::AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(aPortIdentifier));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerPortIdentifierOp(aPortIdentifier));
+}
+
+void
+RemoteWorkerController::Terminate()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  Shutdown();
+}
+
+void
+RemoteWorkerController::Suspend()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eSuspend));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerSuspendOp());
+}
+
+void
+RemoteWorkerController::Resume()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eResume));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerResumeOp());
+}
+
+void
+RemoteWorkerController::Freeze()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eFreeze));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerFreezeOp());
+}
+
+void
+RemoteWorkerController::Thaw()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mState == ePending) {
+    mPendingOps.AppendElement(new Op(Op::eThaw));
+    return;
+  }
+
+  if (mState == eTerminated) {
+    return;
+  }
+
+  MOZ_ASSERT(mState == eReady);
+  Unused << mActor->SendExecOp(RemoteWorkerThawOp());
+}
+
+RemoteWorkerController::Op::~Op()
+{
+  MOZ_COUNT_DTOR(Op);
+
+  // We don't want to leak the port if the operation has not been processed.
+  if (!mCompleted && mType == ePortIdentifier) {
+    MessagePortParent::ForceClose(mPortIdentifier.uuid(),
+                                  mPortIdentifier.destinationUuid(),
+                                  mPortIdentifier.sequenceId());
+  }
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerController.h
@@ -0,0 +1,225 @@
+/* -*- 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_RemoteWorkerController_h
+#define mozilla_dom_RemoteWorkerController_h
+
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace dom {
+
+/* Here's a graph about this remote workers are spawned.
+ *
+ *  _________________________________    |   ________________________________
+ * |                                 |   |  |                                |
+ * |              Parent process     |  IPC |          Creation of Process X |
+ * |              PBackground thread |   |  |                                |
+ * |                                 |   |  | [RemoteWorkerService::Init()]  |
+ * |                                 |   |  |               |                |
+ * |                                 |   |  |               | (1)            |
+ * | [RemoteWorkerManager::  (2)     |   |  |               V                |
+ * |                RegisterActor()]<-------- [new RemoteWorkerServiceChild] |
+ * |                                 |   |  |                                |
+ * |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~   |   |  |________________________________|
+ * |                                 |   |
+ * |  new SharedWorker/ServiceWorker |   |
+ * |      |     ^                    |  IPC
+ * |  (3) |  (4)|                    |
+ * |      V     |                    |   |
+ * | [RemoteWorkerController::       |   |
+ * |         |         Create(data)] |   |
+ * |         | (5)                   |   |
+ * |         V                       |   |
+ * | [RemoteWorkerManager::Launch()] |   |
+ * |         |                       |  IPC   _____________________________
+ * |         | (6)                   |   |   |                             |
+ * |         |                       |       | Selected content process    |
+ * |         V                       |  (7)  |                             |
+ * | [SendPRemoteWorkerConstructor()]--------->[new RemoteWorkerChild()]   |
+ * |         |                       |   |   |             |               |
+ * |         | (8)                   |   |   |             |               |
+ * |         V                       |   |   |             V               |
+ * | [RemoteWorkerController->       |   |   | RemoteWorkerChild->Exec()   |
+ * |         | SetControllerActor()] |   |   |_____________________________|
+ * |     (9) |                       |  IPC
+ * |         V                       |   |
+ * | [RemoteWorkerObserver->         |   |
+ * |           CreationCompleted()]  |   |
+ * |_________________________________|   |
+ *                                       |
+ *
+ * 1. When a new process starts, it creates a RemoteWorkerService singleton.
+ *    This service creates a new thread (Worker Launcher) and from there, it
+ *    starts a PBackground RemoteWorkerServiceChild actor.
+ * 2. On the parent process, PBackground thread, RemoteWorkerServiceParent
+ *    actors are registered into the RemoteWorkerManager service.
+ *
+ * 3. At some point, a SharedWorker or a ServiceWorker must be executed.
+ *    RemoteWorkerController::Create() is used to start the launching. This
+ *    method must be called on the parent process, on the PBackground thread.
+ * 4. RemoteWorkerController object is immediately returned to the caller. Any
+ *    operation done with this controller object will be stored in a queue,
+ *    until the launching is correctly executed.
+ * 5. RemoteWorkerManager has the list of active RemoteWorkerServiceParent
+ *    actors. From them, it picks one.
+ *    In case we don't have any content process to select, a new one is
+ *    spawned. If this happens, the operation is suspended until a new
+ *    RemoteWorkerServiceParent is registered.
+ * 6. RemoteWorkerServiceParent is used to create a RemoteWorkerParent.
+ * 7. RemoteWorkerChild is created on a selected process and it executes the
+ *    WorkerPrivate.
+ * 8. The RemoteWorkerParent actor is passed to the RemoteWorkerController.
+ * 9. RemoteWorkerController now is ready to continue and it called
+ *    RemoteWorkerObserver to inform that the operation is completed.
+ *    In case there were pending operations, they are now executed.
+ */
+
+class ErrorValue;
+class MessagePortIdentifier;
+class RemoteWorkerManager;
+class RemoteWorkerParent;
+
+class RemoteWorkerObserver
+{
+public:
+  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
+
+  virtual void
+  CreationFailed() = 0;
+
+  virtual void
+  CreationSucceeded() = 0;
+
+  virtual void
+  ErrorReceived(const ErrorValue& aValue) = 0;
+
+  virtual void
+  Terminated() = 0;
+};
+
+class RemoteWorkerController final
+{
+  friend class RemoteWorkerManager;
+  friend class RemoteWorkerParent;
+
+public:
+  NS_INLINE_DECL_REFCOUNTING(RemoteWorkerController)
+
+  static already_AddRefed<RemoteWorkerController>
+  Create(const RemoteWorkerData& aData,
+         RemoteWorkerObserver* aObserver,
+         base::ProcessId = 0);
+
+  void
+  AddWindowID(uint64_t aWindowID);
+
+  void
+  RemoveWindowID(uint64_t aWindowID);
+
+  void
+  AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier);
+
+  void
+  Terminate();
+
+  void
+  Suspend();
+
+  void
+  Resume();
+
+  void
+  Freeze();
+
+  void
+  Thaw();
+
+private:
+  explicit RemoteWorkerController(RemoteWorkerObserver* aObserver);
+  ~RemoteWorkerController();
+
+  void
+  SetWorkerActor(RemoteWorkerParent* aActor);
+
+  void
+  ErrorPropagation(const ErrorValue& aValue);
+
+  void
+  WorkerTerminated();
+
+  void
+  Shutdown();
+
+  void
+  CreationFailed();
+
+  void
+  CreationSucceeded();
+
+  RefPtr<RemoteWorkerObserver> mObserver;
+  RefPtr<RemoteWorkerParent> mActor;
+
+  enum {
+    ePending,
+    eReady,
+    eTerminated,
+  } mState;
+
+  struct Op {
+    enum Type {
+      eTerminate,
+      eSuspend,
+      eResume,
+      eFreeze,
+      eThaw,
+      ePortIdentifier,
+      eAddWindowID,
+      eRemoveWindowID,
+    };
+
+    explicit Op(Type aType, uint64_t aWindowID = 0)
+      : mType(aType)
+      , mWindowID(aWindowID)
+      , mCompleted(false)
+    {
+       MOZ_COUNT_CTOR(Op);
+    }
+
+    explicit Op(const MessagePortIdentifier& aPortIdentifier)
+      : mType(ePortIdentifier)
+      , mPortIdentifier(aPortIdentifier)
+      , mCompleted(false)
+    {
+       MOZ_COUNT_CTOR(Op);
+    }
+
+    // This object cannot be copied.
+    Op(Op const&) = delete;
+    Op& operator=(Op const&) = delete;
+
+    ~Op();
+
+    void
+    Completed()
+    {
+      mCompleted = true;
+    }
+
+    Type mType;
+
+    MessagePortIdentifier mPortIdentifier;
+    uint64_t mWindowID;
+    bool mCompleted;
+  };
+
+  nsTArray<UniquePtr<Op>> mPendingOps;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerController_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerManager.cpp
@@ -0,0 +1,236 @@
+/* -*- 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 "RemoteWorkerManager.h"
+
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/RemoteWorkerParent.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/PBackgroundParent.h"
+#include "nsIXULRuntime.h"
+#include "RemoteWorkerServiceParent.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+namespace {
+
+// Raw pointer because this object is kept alive by RemoteWorkerServiceParent
+// actors.
+RemoteWorkerManager* sRemoteWorkerManager;
+
+} // anonymous
+
+/* static */ already_AddRefed<RemoteWorkerManager>
+RemoteWorkerManager::GetOrCreate()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (!sRemoteWorkerManager) {
+    sRemoteWorkerManager = new RemoteWorkerManager();
+  }
+
+  RefPtr<RemoteWorkerManager> rwm = sRemoteWorkerManager;
+  return rwm.forget();
+}
+
+RemoteWorkerManager::RemoteWorkerManager()
+  : mParentActor(nullptr)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(!sRemoteWorkerManager);
+}
+
+RemoteWorkerManager::~RemoteWorkerManager()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(sRemoteWorkerManager == this);
+  sRemoteWorkerManager = nullptr;
+}
+
+void
+RemoteWorkerManager::RegisterActor(RemoteWorkerServiceParent* aActor)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aActor);
+
+  if (!BackgroundParent::IsOtherProcessActor(aActor->Manager())) {
+    MOZ_ASSERT(!mParentActor);
+    mParentActor = aActor;
+    MOZ_ASSERT(mPendings.IsEmpty());
+    return;
+  }
+
+  MOZ_ASSERT(!mChildActors.Contains(aActor));
+  mChildActors.AppendElement(aActor);
+
+  if (!mPendings.IsEmpty()) {
+    // Flush pending launching.
+    for (const Pending& p : mPendings) {
+      LaunchInternal(p.mController, aActor, p.mData);
+    }
+
+    mPendings.Clear();
+
+    // We don't need to keep this manager alive manually. The Actor is doing it
+    // for us.
+    Release();
+  }
+}
+
+void
+RemoteWorkerManager::UnregisterActor(RemoteWorkerServiceParent* aActor)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aActor);
+
+  if (aActor == mParentActor) {
+    mParentActor = nullptr;
+  } else {
+    MOZ_ASSERT(mChildActors.Contains(aActor));
+    mChildActors.RemoveElement(aActor);
+  }
+}
+
+void
+RemoteWorkerManager::Launch(RemoteWorkerController* aController,
+                            const RemoteWorkerData& aData,
+                            base::ProcessId aProcessId)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  RemoteWorkerServiceParent* targetActor = SelectTargetActor(aData, aProcessId);
+
+  // If there is not an available actor, let's store the data, and let's spawn a
+  // new process.
+  if (!targetActor) {
+    // If this is the first time we have a pending launching, we must keep alive
+    // the manager.
+    if (mPendings.IsEmpty()) {
+      AddRef();
+    }
+
+    Pending* pending = mPendings.AppendElement();
+    pending->mController = aController;
+    pending->mData = aData;
+
+    LaunchNewContentProcess();
+    return;
+  }
+
+  LaunchInternal(aController, targetActor, aData);
+}
+
+void
+RemoteWorkerManager::LaunchInternal(RemoteWorkerController* aController,
+                                    RemoteWorkerServiceParent* aTargetActor,
+                                    const RemoteWorkerData& aData)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(aController);
+  MOZ_ASSERT(aTargetActor);
+  MOZ_ASSERT(aTargetActor == mParentActor ||
+             mChildActors.Contains(aTargetActor));
+
+  RemoteWorkerParent* workerActor =
+    static_cast<RemoteWorkerParent*>(
+      aTargetActor->Manager()->SendPRemoteWorkerConstructor(aData));
+  if (NS_WARN_IF(!workerActor)) {
+    AsyncCreationFailed(aController);
+    return;
+  }
+
+  workerActor->Initialize();
+
+  // This makes the link better the 2 actors.
+  aController->SetWorkerActor(workerActor);
+  workerActor->SetController(aController);
+}
+
+void
+RemoteWorkerManager::AsyncCreationFailed(RemoteWorkerController* aController)
+{
+  RefPtr<RemoteWorkerController> controller = aController;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("RemoteWorkerManager::AsyncCreationFailed",
+                           [controller]() {
+      controller->CreationFailed();
+  });
+
+  NS_DispatchToCurrentThread(r.forget());
+}
+
+RemoteWorkerServiceParent*
+RemoteWorkerManager::SelectTargetActor(const RemoteWorkerData& aData,
+                                       base::ProcessId aProcessId)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  // System principal workers should run on the parent process.
+  if (aData.principalInfo().type() == PrincipalInfo::TSystemPrincipalInfo) {
+    MOZ_ASSERT(mParentActor);
+    return mParentActor;
+  }
+
+  // If e10s is off, use the parent process.
+  if (!BrowserTabsRemoteAutostart()) {
+    MOZ_ASSERT(mParentActor);
+    return mParentActor;
+  }
+
+  // We shouldn't have to worry about content-principal parent-process workers.
+  MOZ_ASSERT(aProcessId != base::GetCurrentProcId());
+
+  if (mChildActors.IsEmpty()) {
+    return nullptr;
+  }
+
+  for (RemoteWorkerServiceParent* actor : mChildActors) {
+    // Let's execute the RemoteWorker on the same process.
+    if (actor->OtherPid() == aProcessId) {
+      return actor;
+    }
+  }
+
+  // Let's choose an actor, randomly.
+  uint32_t id = uint32_t(rand()) % mChildActors.Length();
+  return mChildActors[id];
+}
+
+void
+RemoteWorkerManager::LaunchNewContentProcess()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  // This runnable will spawn a new process if it doesn't exist yet.
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("LaunchNewContentProcess", [] () {
+      RefPtr<ContentParent> unused =
+        ContentParent::GetNewOrUsedBrowserProcess(
+          nullptr,
+          NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
+    }
+  );
+
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerManager.h
@@ -0,0 +1,80 @@
+/* -*- 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_RemoteWorkerManager_h
+#define mozilla_dom_RemoteWorkerManager_h
+
+#include "base/process.h"
+#include "mozilla/dom/RemoteWorkerTypes.h"
+#include "nsISupportsImpl.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWorkerController;
+class RemoteWorkerServiceParent;
+
+// This class is used on PBackground thread, on the parent process only.
+class RemoteWorkerManager final
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(RemoteWorkerManager)
+
+  static already_AddRefed<RemoteWorkerManager>
+  GetOrCreate();
+
+  void
+  RegisterActor(RemoteWorkerServiceParent* aActor);
+
+  void
+  UnregisterActor(RemoteWorkerServiceParent* aActor);
+
+  void
+  Launch(RemoteWorkerController* aController,
+         const RemoteWorkerData& aData,
+         base::ProcessId aProcessId);
+
+private:
+  RemoteWorkerManager();
+  ~RemoteWorkerManager();
+
+  RemoteWorkerServiceParent*
+  SelectTargetActor(const RemoteWorkerData& aData,
+                    base::ProcessId aProcessId);
+
+  void
+  LaunchInternal(RemoteWorkerController* aController,
+                 RemoteWorkerServiceParent* aTargetActor,
+                 const RemoteWorkerData& aData);
+
+  void
+  LaunchNewContentProcess();
+
+  void
+  AsyncCreationFailed(RemoteWorkerController* aController);
+
+  // The list of existing RemoteWorkerServiceParent actors for child processes.
+  // Raw pointers because RemoteWorkerServiceParent actors unregister themselves
+  // when destroyed.
+  // XXX For Fission, where we could have a lot of child actors, should we maybe
+  // instead keep either a hash table (PID->actor) or perhaps store the actors
+  // in order, sorted by PID, to avoid linear lookup times?
+  nsTArray<RemoteWorkerServiceParent*> mChildActors;
+  RemoteWorkerServiceParent* mParentActor;
+
+  struct Pending {
+    RefPtr<RemoteWorkerController> mController;
+    RemoteWorkerData mData;
+  };
+
+  nsTArray<Pending> mPendings;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerManager_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerParent.cpp
@@ -0,0 +1,155 @@
+/* -*- 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 "RemoteWorkerParent.h"
+#include "RemoteWorkerController.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/Unused.h"
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+namespace {
+
+class UnregisterActorRunnable final : public Runnable
+{
+public:
+  explicit UnregisterActorRunnable(already_AddRefed<ContentParent> aParent)
+    : Runnable("UnregisterActorRunnable")
+    , mContentParent(aParent)
+  {
+    AssertIsOnBackgroundThread();
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mContentParent->UnregisterRemoveWorkerActor();
+    mContentParent = nullptr;
+
+    return NS_OK;
+  }
+
+private:
+  RefPtr<ContentParent> mContentParent;
+};
+
+} // anonymous
+
+RemoteWorkerParent::RemoteWorkerParent()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+RemoteWorkerParent::~RemoteWorkerParent()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+void
+RemoteWorkerParent::Initialize()
+{
+  RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager());
+
+  // Parent is null if the child actor runs on the parent process.
+  if (parent) {
+    parent->RegisterRemoteWorkerActor();
+
+    nsCOMPtr<nsIEventTarget> target =
+      SystemGroup::EventTargetFor(TaskCategory::Other);
+
+    NS_ProxyRelease("RemoteWorkerParent::Initialize ContentParent",
+                    target, parent.forget());
+  }
+}
+
+void
+RemoteWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager());
+
+  // Parent is null if the child actor runs on the parent process.
+  if (parent) {
+    RefPtr<UnregisterActorRunnable> r =
+      new UnregisterActorRunnable(parent.forget());
+
+    nsCOMPtr<nsIEventTarget> target =
+      SystemGroup::EventTargetFor(TaskCategory::Other);
+    target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+  }
+
+  mController = nullptr;
+}
+
+IPCResult
+RemoteWorkerParent::RecvCreated(const bool& aStatus)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (!mController) {
+    return IPC_OK();
+  }
+
+  if (aStatus) {
+    mController->CreationSucceeded();
+  } else {
+    mController->CreationFailed();
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+RemoteWorkerParent::RecvError(const ErrorValue& aValue)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mController) {
+    mController->ErrorPropagation(aValue);
+  }
+
+  return IPC_OK();
+}
+
+IPCResult
+RemoteWorkerParent::RecvClose()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mController) {
+    mController->WorkerTerminated();
+  }
+
+  Unused << Send__delete__(this);
+  return IPC_OK();
+}
+
+void
+RemoteWorkerParent::SetController(RemoteWorkerController* aController)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  mController = aController;
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerParent.h
@@ -0,0 +1,51 @@
+/* -*- 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_RemoteWorkerParent_h
+#define mozilla_dom_RemoteWorkerParent_h
+
+#include "mozilla/dom/PRemoteWorkerParent.h"
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWorkerController;
+
+class RemoteWorkerParent final : public PRemoteWorkerParent
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(RemoteWorkerParent)
+
+  RemoteWorkerParent();
+
+  void
+  Initialize();
+
+  void
+  SetController(RemoteWorkerController* aController);
+
+private:
+  ~RemoteWorkerParent();
+
+  void
+  ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
+
+  mozilla::ipc::IPCResult
+  RecvError(const ErrorValue& aValue) override;
+
+  mozilla::ipc::IPCResult
+  RecvClose() override;
+
+  mozilla::ipc::IPCResult
+  RecvCreated(const bool& aStatus) override;
+
+  RefPtr<RemoteWorkerController> mController;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerParent_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerService.cpp
@@ -0,0 +1,212 @@
+/* -*- 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 "RemoteWorkerService.h"
+
+#include "mozilla/dom/PRemoteWorkerParent.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "mozilla/ipc/PBackgroundParent.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/SystemGroup.h"
+#include "nsIObserverService.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOMPrivate.h"
+#include "RemoteWorkerController.h"
+#include "RemoteWorkerServiceChild.h"
+#include "RemoteWorkerServiceParent.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+namespace {
+
+StaticMutex sRemoteWorkerServiceMutex;
+StaticRefPtr<RemoteWorkerService> sRemoteWorkerService;
+
+} // anonymous
+
+/* static */ void
+RemoteWorkerService::Initialize()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  StaticMutexAutoLock lock(sRemoteWorkerServiceMutex);
+  MOZ_ASSERT(!sRemoteWorkerService);
+
+  RefPtr<RemoteWorkerService> service = new RemoteWorkerService();
+
+  if (!XRE_IsParentProcess()) {
+    nsresult rv = service->InitializeOnMainThread();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    sRemoteWorkerService = service;
+    return;
+  }
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return;
+  }
+
+  nsresult rv = obs->AddObserver(service, "profile-after-change", false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  sRemoteWorkerService = service;
+}
+
+/* static */ nsIThread*
+RemoteWorkerService::Thread()
+{
+  StaticMutexAutoLock lock(sRemoteWorkerServiceMutex);
+  MOZ_ASSERT(sRemoteWorkerService);
+  MOZ_ASSERT(sRemoteWorkerService->mThread);
+  return sRemoteWorkerService->mThread;
+}
+
+nsresult
+RemoteWorkerService::InitializeOnMainThread()
+{
+  // I would like to call this thread "DOM Remote Worker Launcher", but the max
+  // length is 16 chars.
+  nsresult rv = NS_NewNamedThread("Worker Launcher",
+                                  getter_AddRefs(mThread));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  rv = obs->AddObserver(this,
+                        NS_XPCOM_SHUTDOWN_OBSERVER_ID,
+                        false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  RefPtr<RemoteWorkerService> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("InitializeThread", [self] () {
+    self->InitializeOnTargetThread();
+  });
+
+  rv = mThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+RemoteWorkerService::RemoteWorkerService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+RemoteWorkerService::~RemoteWorkerService() = default;
+
+void
+RemoteWorkerService::InitializeOnTargetThread()
+{
+  MOZ_ASSERT(mThread);
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
+
+  PBackgroundChild* actorChild =
+    BackgroundChild::GetOrCreateForCurrentThread();
+  if (NS_WARN_IF(!actorChild)) {
+    return;
+  }
+
+  RemoteWorkerServiceChild* actor =
+    static_cast<RemoteWorkerServiceChild*>(
+      actorChild->SendPRemoteWorkerServiceConstructor());
+  if (NS_WARN_IF(!actor)) {
+    return;
+  }
+
+  // Now we are ready!
+  mActor = actor;
+}
+
+void
+RemoteWorkerService::ShutdownOnTargetThread()
+{
+  MOZ_ASSERT(mThread);
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mActor);
+
+  // Here we need to shutdown the IPC protocol.
+  mActor->Send__delete__(mActor);
+  mActor = nullptr;
+
+  // Then we can terminate the thread on the main-thread.
+  RefPtr<RemoteWorkerService> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("ShutdownOnMainThread", [self] () {
+    self->mThread->Shutdown();
+    self->mThread = nullptr;
+  });
+
+  nsCOMPtr<nsIEventTarget> target =
+    SystemGroup::EventTargetFor(TaskCategory::Other);
+  target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+}
+
+NS_IMETHODIMP
+RemoteWorkerService::Observe(nsISupports* aSubject,
+                             const char* aTopic,
+                             const char16_t* aData)
+{
+  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+    MOZ_ASSERT(mThread);
+
+    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+    if (obs) {
+      obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+    }
+
+    RefPtr<RemoteWorkerService> self = this;
+    nsCOMPtr<nsIRunnable> r =
+      NS_NewRunnableFunction("ShutdownThread", [self] () {
+      self->ShutdownOnTargetThread();
+    });
+
+    mThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+
+    StaticMutexAutoLock lock(sRemoteWorkerServiceMutex);
+    sRemoteWorkerService = nullptr;
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(!strcmp(aTopic, "profile-after-change"));
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, "profile-after-change");
+  }
+
+  return InitializeOnMainThread();
+}
+
+NS_IMPL_ISUPPORTS(RemoteWorkerService, nsIObserver)
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerService.h
@@ -0,0 +1,53 @@
+/* -*- 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_RemoteWorkerService_h
+#define mozilla_dom_RemoteWorkerService_h
+
+#include "nsCOMPtr.h"
+#include "nsIObserver.h"
+
+class nsIThread;
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWorkerServiceChild;
+
+class RemoteWorkerService final : public nsIObserver
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  // To be called when a process is initialized on main-thread.
+  static void
+  Initialize();
+
+  static nsIThread*
+  Thread();
+
+private:
+  RemoteWorkerService();
+  ~RemoteWorkerService();
+
+  nsresult
+  InitializeOnMainThread();
+
+  void
+  InitializeOnTargetThread();
+
+  void
+  ShutdownOnTargetThread();
+
+  nsCOMPtr<nsIThread> mThread;
+  RefPtr<RemoteWorkerServiceChild> mActor;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerService_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerServiceChild.cpp
@@ -0,0 +1,19 @@
+/* -*- 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 "RemoteWorkerServiceChild.h"
+#include "RemoteWorkerController.h"
+
+namespace mozilla {
+namespace dom {
+
+RemoteWorkerServiceChild::RemoteWorkerServiceChild()
+{}
+
+RemoteWorkerServiceChild::~RemoteWorkerServiceChild() = default;
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerServiceChild.h
@@ -0,0 +1,33 @@
+/* -*- 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_RemoteWorkerServiceChild_h
+#define mozilla_dom_RemoteWorkerServiceChild_h
+
+#include "mozilla/dom/PRemoteWorkerServiceChild.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWorkerController;
+class RemoteWorkerData;
+
+class RemoteWorkerServiceChild final : public PRemoteWorkerServiceChild
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(RemoteWorkerServiceChild)
+
+  RemoteWorkerServiceChild();
+
+private:
+  ~RemoteWorkerServiceChild();
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerServiceChild_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerServiceParent.cpp
@@ -0,0 +1,38 @@
+/* -*- 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 "RemoteWorkerServiceParent.h"
+#include "RemoteWorkerManager.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+RemoteWorkerServiceParent::RemoteWorkerServiceParent()
+  : mManager(RemoteWorkerManager::GetOrCreate())
+{}
+
+RemoteWorkerServiceParent::~RemoteWorkerServiceParent()
+{}
+
+void
+RemoteWorkerServiceParent::Initialize()
+{
+  AssertIsOnBackgroundThread();
+  mManager->RegisterActor(this);
+}
+
+void
+RemoteWorkerServiceParent::ActorDestroy(IProtocol::ActorDestroyReason)
+{
+  AssertIsOnBackgroundThread();
+  mManager->UnregisterActor(this);
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerServiceParent.h
@@ -0,0 +1,36 @@
+/* -*- 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_RemoteWorkerServiceParent_h
+#define mozilla_dom_RemoteWorkerServiceParent_h
+
+#include "mozilla/dom/PRemoteWorkerServiceParent.h"
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWorkerManager;
+
+class RemoteWorkerServiceParent final : public PRemoteWorkerServiceParent
+{
+public:
+  RemoteWorkerServiceParent();
+  ~RemoteWorkerServiceParent();
+
+  void
+  ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
+
+  void
+  Initialize();
+
+private:
+  RefPtr<RemoteWorkerManager> mManager;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RemoteWorkerServiceParent_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh
@@ -0,0 +1,86 @@
+/* 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 ClientIPCTypes;
+include PBackgroundSharedTypes;
+include URIParams;
+
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+
+namespace mozilla {
+namespace dom {
+
+struct ContentSecurityPolicy
+{
+  nsString policy;
+  bool reportOnlyFlag;
+  bool deliveredViaMetaTagFlag;
+};
+
+struct RemoteWorkerData
+{
+  // This should only be used for devtools.
+  nsString originalScriptURL;
+
+  // It is important to pass these as URIParams instead of strings for blob
+  // URLs: they carry an additional bit of state with them (mIsRevoked) that
+  // gives us a chance to use them, even after they've been revoked. Because
+  // we're asynchronously calling into the parent process before potentially
+  // loading the worker, it is important to keep this state. Note that this
+  // isn't a panacea: once the URL has been revoked, it'll give the worker 5
+  // seconds to actually load it; so it's possible to still fail to load the
+  // blob URL if it takes too long to do the round trip.
+  URIParams baseScriptURL;
+  URIParams resolvedScriptURL;
+
+  nsString name;
+
+  PrincipalInfo loadingPrincipalInfo;
+  ContentSecurityPolicy[] loadingPrincipalCsp;
+  ContentSecurityPolicy[] loadingPrincipalPreloadCsp;
+
+  PrincipalInfo principalInfo;
+  ContentSecurityPolicy[] principalCsp;
+  ContentSecurityPolicy[] principalPreloadCsp;
+
+  nsCString domain;
+
+  bool isSecureContext;
+
+  OptionalIPCClientInfo clientInfo;
+
+  bool isSharedWorker;
+};
+
+// ErrorData/ErrorDataNote correspond to WorkerErrorReport/WorkerErrorNote
+// which in turn correspond to JSErrorReport/JSErrorNotes which allows JS to
+// report complicated errors such as redeclarations that involve multiple
+// distinct lines.  For more generic error-propagation IPC structures, see bug
+// 1357463 on making ErrorResult usable over IPC.
+
+struct ErrorDataNote {
+  uint32_t lineNumber;
+  uint32_t columnNumber;
+  nsString message;
+  nsString filename;
+};
+
+struct ErrorData {
+  uint32_t lineNumber;
+  uint32_t columnNumber;
+  uint32_t flags;
+  nsString message;
+  nsString filename;
+  nsString line;
+  ErrorDataNote[] notes;
+};
+
+union ErrorValue {
+  nsresult;
+  ErrorData;
+  void_t;
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/remoteworkers/moz.build
@@ -0,0 +1,38 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla.dom += [
+    'RemoteWorkerChild.h',
+    'RemoteWorkerController.h',
+    'RemoteWorkerParent.h',
+    'RemoteWorkerService.h',
+    'RemoteWorkerServiceChild.h',
+    'RemoteWorkerServiceParent.h',
+]
+
+UNIFIED_SOURCES += [
+    'RemoteWorkerChild.cpp',
+    'RemoteWorkerController.cpp',
+    'RemoteWorkerManager.cpp',
+    'RemoteWorkerParent.cpp',
+    'RemoteWorkerService.cpp',
+    'RemoteWorkerServiceChild.cpp',
+    'RemoteWorkerServiceParent.cpp',
+]
+