merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 12 Jul 2017 11:07:09 +0200
changeset 368400 09a4282d1172ac255038e7ccacfd772140b219e2
parent 368399 2ea915a5c474da35b3ab6cf828d6816d53e1347f (current diff)
parent 368296 218d346298695f533ef9056e9d7cf03e1372d1e3 (diff)
child 368401 235ab635d17254e70b629bfe106334442a9a728f
child 368511 c59cb9abed3885d87660332e94e43b477ac5fd0d
child 368598 25da67af538c066eac3facc1390ca7b48fe906b6
push id92469
push usercbook@mozilla.com
push dateWed, 12 Jul 2017 09:18:17 +0000
treeherdermozilla-inbound@235ab635d172 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone56.0a1
first release with
nightly linux32
09a4282d1172 / 56.0a1 / 20170712100301 / files
nightly linux64
09a4282d1172 / 56.0a1 / 20170712100301 / files
nightly mac
09a4282d1172 / 56.0a1 / 20170712100330 / files
nightly win32
09a4282d1172 / 56.0a1 / 20170712030204 / files
nightly win64
09a4282d1172 / 56.0a1 / 20170712030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/app/profile/firefox.js
browser/base/content/test/performance/browser_startup.js
dom/base/nsContentUtils.cpp
dom/security/test/sri/iframe_style_crossdomain_legacy.html
dom/security/test/sri/test_style_crossdomain_legacy.html
dom/xbl/test/test_bug379959_legacy.html
taskcluster/taskgraph/transforms/tests.py
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -211,17 +211,16 @@ static int do_main(int argc, char* argv[
     // no -app flag so we use the compiled-in app data
     config.appData = &sAppData;
     config.appDataPath = kDesktopFolder;
   }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   sandbox::BrokerServices* brokerServices =
     sandboxing::GetInitializedBrokerServices();
-  sandboxing::NetworkDriveCheck();
   sandboxing::PermissionsService* permissionsService =
     sandboxing::GetPermissionsService();
 #if defined(MOZ_CONTENT_SANDBOX)
   if (!brokerServices) {
     Output("Couldn't initialize the broker services.\n");
     return 255;
   }
 #endif
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -602,16 +602,19 @@ support-files =
 [browser_e10s_chrome_process.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_e10s_javascript.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_blockHPKP.js]
 tags = psm
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_windowactivation.js]
+support-files =
+  file_window_activation.html
+  file_window_activation2.html
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_contextmenu_childprocess.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug963945.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_domFullscreen_fullscreenMode.js]
 tags = fullscreen
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
--- a/browser/base/content/test/general/browser_windowactivation.js
+++ b/browser/base/content/test/general/browser_windowactivation.js
@@ -1,15 +1,16 @@
 /*
  * This test checks that window activation state is set properly with multiple tabs.
  */
 
 /* eslint-env mozilla/frame-script */
 
-var testPage = "data:text/html;charset=utf-8,<body><style>:-moz-window-inactive { background-color: red; }</style><div id='area'></div></body>";
+const testPage = getRootDirectory(gTestPath) + "file_window_activation.html";
+const testPage2 = getRootDirectory(gTestPath) + "file_window_activation2.html";
 
 var colorChangeNotifications = 0;
 var otherWindow;
 
 var browser1, browser2;
 
 add_task(async function reallyRunTests() {
 
@@ -102,17 +103,17 @@ add_task(async function reallyRunTests()
 });
 
 function sendGetBackgroundRequest(ifChanged) {
   browser1.messageManager.sendAsyncMessage("Test:GetBackgroundColor", { ifChanged });
   browser2.messageManager.sendAsyncMessage("Test:GetBackgroundColor", { ifChanged });
 }
 
 function runOtherWindowTests() {
-  otherWindow = window.open("data:text/html;charset=utf-8,<body>Hi</body>", "", "chrome");
+  otherWindow = window.open(testPage2, "", "chrome");
   waitForFocus(function() {
     sendGetBackgroundRequest(true);
   }, otherWindow);
 }
 
 function childFunction() {
   let oldColor = null;
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/file_window_activation.html
@@ -0,0 +1,4 @@
+<body>
+<style>:-moz-window-inactive { background-color: red; }</style>
+<div id='area'></div>
+</body>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/file_window_activation2.html
@@ -0,0 +1,1 @@
+<body>Hi</body>
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -66,16 +66,17 @@ const startupPhases = {
       "UnifiedComplete.js",
       "nsPlacesExpiration.js",
       "nsSearchService.js",
     ]),
     modules: new Set([
       "chrome://webcompat-reporter/content/TabListener.jsm",
       "resource:///modules/AboutNewTab.jsm",
       "resource:///modules/DirectoryLinksProvider.jsm",
+      "resource:///modules/RecentWindow.jsm",
       "resource://gre/modules/BookmarkHTMLUtils.jsm",
       "resource://gre/modules/Bookmarks.jsm",
       "resource://gre/modules/ContextualIdentityService.jsm",
       "resource://gre/modules/NewTabUtils.jsm",
       "resource://gre/modules/PageThumbs.jsm",
       "resource://gre/modules/PlacesSyncUtils.jsm",
       "resource://gre/modules/Promise.jsm",
       "resource://gre/modules/Sqlite.jsm",
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -3,17 +3,19 @@
  * 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/. */
 
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/AppConstants.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
-Components.utils.import("resource:///modules/RecentWindow.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
+                                  "resource:///modules/RecentWindow.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
                                   "resource:///modules/ShellService.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
                                   "resource://gre/modules/ContextualIdentityService.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -1583,16 +1583,31 @@
 
           // header is a xul:deck so collapsed doesn't work on it, see bug 589569.
           this.header.hidden = this.buttons.collapsed = !oneOffCount;
 
           if (!oneOffCount)
             return;
 
           let panelWidth = parseInt(this.popup.clientWidth);
+
+          // There's one weird thing to guard against: when layout pixels
+          // aren't an integral multiple of device pixels, the last button
+          // of each row sometimes gets pushed to the next row, depending on the
+          // panel and button widths.
+          // This is likely because the clientWidth getter rounds the value, but
+          // the panel's border width is not an integer.
+          // As a workaround, decrement the width if the scale is not an integer.
+          let scale = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIDOMWindowUtils)
+                            .screenPixelsPerCSSPixel;
+          if (Math.floor(scale) != scale) {
+            --panelWidth;
+          }
+
           // The + 1 is because the last button doesn't have a right border.
           let enginesPerRow = Math.floor((panelWidth + 1) / this.buttonWidth);
           let buttonWidth = Math.floor(panelWidth / enginesPerRow);
           // There will be an emtpy area of:
           //   panelWidth - enginesPerRow * buttonWidth  px
           // at the end of each row.
 
           // If the <description> tag with the list of search engines doesn't have
@@ -1654,30 +1669,17 @@
           if (this.compact) {
             this.settingsButtonCompact.setAttribute("width", buttonWidth);
             if (rowCount == 1 && hasDummyItems) {
               // When there's only one row, make the compact settings button
               // hug the right edge of the panel.  It may not due to the panel's
               // width not being an integral multiple of the button width.  (See
               // the "There will be an emtpy area" comment above.)  Increase the
               // width of the last dummy item by the remainder.
-              //
-              // There's one weird thing to guard against: when layout pixels
-              // aren't an integral multiple of device pixels, the settings
-              // button sometimes gets pushed to a new row, depending on the
-              // panel and button widths.  It's as if `remainder` is somehow
-              // too big, even though it's an integer.  To work around that,
-              // decrement the remainder if the scale is not an integer.
-              let scale = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindowUtils)
-                                .screenPixelsPerCSSPixel;
               let remainder = panelWidth - (enginesPerRow * buttonWidth);
-              if (Math.floor(scale) != scale) {
-                remainder--;
-              }
               let width = remainder + buttonWidth;
               let lastDummyItem = this.settingsButtonCompact.previousSibling;
               lastDummyItem.setAttribute("width", width);
             }
           }
         ]]></body>
       </method>
 
--- a/browser/components/shell/nsGNOMEShellService.cpp
+++ b/browser/components/shell/nsGNOMEShellService.cpp
@@ -27,16 +27,17 @@
 #include "nsIImageLoadingContent.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 #include "mozilla/Sprintf.h"
 #if defined(MOZ_WIDGET_GTK)
 #include "nsIImageToPixbuf.h"
 #endif
 #include "nsXULAppAPI.h"
+#include "gfxPlatform.h"
 
 #include <glib.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <limits.h>
 #include <stdlib.h>
@@ -81,16 +82,20 @@ static const MimeTypeAssociation appType
 #define kDesktopDrawBGGSKey "draw-background"
 #define kDesktopColorGSKey "primary-color"
 
 nsresult
 nsGNOMEShellService::Init()
 {
   nsresult rv;
 
+  if (gfxPlatform::IsHeadless()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   // GConf, GSettings or GIO _must_ be available, or we do not allow
   // CreateInstance to succeed.
 
   nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
   nsCOMPtr<nsIGIOService> giovfs =
     do_GetService(NS_GIOSERVICE_CONTRACTID);
   nsCOMPtr<nsIGSettingsService> gsettings =
     do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -300,27 +300,24 @@ this.BrowserUITelemetry = {
 
   _firstWindowMeasurements: null,
   _gatherFirstWindowMeasurements() {
     // We'll gather measurements as soon as the session has restored.
     // We do this here instead of waiting for UITelemetry to ask for
     // our measurements because at that point all browser windows have
     // probably been closed, since the vast majority of saved-session
     // pings are gathered during shutdown.
-    let win = RecentWindow.getMostRecentBrowserWindow({
-      private: false,
-      allowPopups: false,
-    });
-
     Services.search.init(rv => {
-      // If there are no such windows (or we've just about found one
-      // but it's closed already), we're out of luck. :(
-      let hasWindow = win && !win.closed;
-      this._firstWindowMeasurements = hasWindow ? this._getWindowMeasurements(win, rv)
-                                                : {};
+      let win = RecentWindow.getMostRecentBrowserWindow({
+        private: false,
+        allowPopups: false,
+      });
+      // If there are no such windows, we're out of luck. :(
+      this._firstWindowMeasurements = win ? this._getWindowMeasurements(win, rv)
+                                          : {};
     });
   },
 
   _registerWindow(aWindow) {
     aWindow.addEventListener("unload", this);
     let document = aWindow.document;
 
     for (let areaID of CustomizableUI.areas) {
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -42,17 +42,17 @@ this.ExtensionsUI = {
   async init() {
     this.histogram = Services.telemetry.getHistogramById("EXTENSION_INSTALL_PROMPT_RESULT");
 
     Services.obs.addObserver(this, "webextension-permission-prompt");
     Services.obs.addObserver(this, "webextension-update-permissions");
     Services.obs.addObserver(this, "webextension-install-notify");
     Services.obs.addObserver(this, "webextension-optional-permission-prompt");
 
-    await RecentWindow.getMostRecentBrowserWindow().delayedStartupPromise;
+    await Services.wm.getMostRecentWindow("navigator:browser").delayedStartupPromise;
 
     this._checkForSideloaded();
   },
 
   async _checkForSideloaded() {
     let sideloaded = await AddonManagerPrivate.getNewSideloads();
 
     if (!sideloaded.length) {
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -110,16 +110,17 @@ include('/ipc/chromium/chromium-config.m
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/docshell/shistory',
     '/dom/base',
     '/layout/base',
     '/layout/generic',
     '/layout/style',
     '/layout/xul',
+    '/netwerk/base',
     '/netwerk/protocol/viewsource',
     '/toolkit/components/browser',
     '/tools/profiler',
 ]
 
 if CONFIG['MOZ_TOOLKIT_SEARCH']:
     DEFINES['MOZ_TOOLKIT_SEARCH'] = True
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -200,16 +200,17 @@
 #include "nsICommandManager.h"
 #include "nsIDOMNode.h"
 #include "nsIClassOfService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIHttpChannel.h"
 #include "nsIIDNService.h"
 #include "nsIInputStreamChannel.h"
 #include "nsINestedURI.h"
+#include "nsIOService.h"
 #include "nsISHContainer.h"
 #include "nsISHistory.h"
 #include "nsISecureBrowserUI.h"
 #include "nsISocketProvider.h"
 #include "nsIStringBundle.h"
 #include "nsIURIFixup.h"
 #include "nsIURILoader.h"
 #include "nsIURL.h"
@@ -10957,21 +10958,27 @@ nsDocShell::DoURILoad(nsIURI* aURI,
   // the triggeringPrincipal for TYPE_DOCUMENT loads.
   MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
 
   bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
   // only inherit if we have a aPrincipalToInherit
   bool inherit = false;
 
   if (aPrincipalToInherit) {
+    bool isData;
+    bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() &&
+                             NS_SUCCEEDED(aURI->SchemeIs("data", &isData)) &&
+                             isData;
+    // If aURI is data: URI and is treated as a unique opaque origin, we don't
+    // want to inherit principal.
     inherit = nsContentUtils::ChannelShouldInheritPrincipal(
       aPrincipalToInherit,
       aURI,
       true, // aInheritForAboutBlank
-      isSrcdoc);
+      isSrcdoc) && !isURIUniqueOrigin ;
   }
 
   nsLoadFlags loadFlags = mDefaultLoadFlags;
   nsSecurityFlags securityFlags =
     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
 
   if (aFirstParty) {
     // tag first party URL loads
--- a/docshell/test/bug404548-subframe.html
+++ b/docshell/test/bug404548-subframe.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
-<body onload="setTimeout(function() { window.location = &quot;data:text/html,<body onload='window.opener.finishTest()'>&quot; }, 10)">
-<iframe src="data:text/html,<body onpagehide='var p = window.parent.opener; var e = window.frameElement; e.parentNode.removeChild(e); if (e.parentNode == null && e.contentWindow == null) { p.firstRemoved = true; }'>">
+<body onload="setTimeout(function() { window.location = 'bug404548-subframe_window.html'; }, 10)">
+<iframe srcdoc="<body onpagehide='var p = window.parent.opener; var e = window.frameElement; e.parentNode.removeChild(e); if (e.parentNode == null && e.contentWindow == null) { p.firstRemoved = true; }'>">
 </iframe>
-<iframe src="data:text/html,<body onpagehide='window.parent.opener.secondHidden = true;'>">
+<iframe srcdoc="<body onpagehide='window.parent.opener.secondHidden = true;'>">
 </iframe>
new file mode 100644
--- /dev/null
+++ b/docshell/test/bug404548-subframe_window.html
@@ -0,0 +1,1 @@
+<body onload='window.opener.finishTest()'>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bfcache_plus_hash_1.html
@@ -0,0 +1,1 @@
+<html><body onload="opener.childLoad(1)" onpageshow="opener.childPageshow(1)">Popup 1</body></html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bfcache_plus_hash_2.html
@@ -0,0 +1,1 @@
+<html><body onload="opener.childLoad(2)">Popup 2</body></html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug1121701_1.html
@@ -0,0 +1,1 @@
+<script>window.onpageshow = function(e) { opener.child1PageShow(e); } </script>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug1121701_2.html
@@ -0,0 +1,1 @@
+<script>window.onpageshow = function(e) { opener.child2PageShow(e); } </script>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug1186774.html
@@ -0,0 +1,1 @@
+<div style='height: 9000px;'></div>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug369814.html
@@ -0,0 +1,1 @@
+<script>window.onunload = function() { frameElement.unloading(); }</script>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug660404-1.html
@@ -0,0 +1,1 @@
+<script>window.onload = function() { opener.continueTest(); }</script>
--- a/docshell/test/historyframes.html
+++ b/docshell/test/historyframes.html
@@ -4,17 +4,17 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=602256
 -->
 <head>
   <title>Test for Bug 602256</title>
 </head>
 <body onload="SimpleTest.executeSoon(run_test)">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=602256">Mozilla Bug 602256</a>
 <div id="content">
-  <iframe id="iframe" src="data:text/html,<p%20id='text'>Start</p>"></iframe>
+  <iframe id="iframe" src="start_historyframe.html"></iframe>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 602256 **/
 
 var testWin = window.opener ? window.opener : window.parent;
 
@@ -45,19 +45,20 @@ function loadContent(aURL, aCallback) {
 function getURL() {
   return gFrame.contentDocument.documentURI;
 }
 
 function getContent() {
   return gFrame.contentDocument.getElementById("text").textContent;
 }
 
-var START = "data:text/html,<p%20id='text'>Start</p>";
-var URL1 = "data:text/html,<p%20id='text'>Test1</p>";
-var URL2 = "data:text/html,<p%20id='text'>Test2</p>";
+var BASE_URI = "http://mochi.test:8888/tests/docshell/test/";
+var START = BASE_URI + "start_historyframe.html";
+var URL1 = BASE_URI + "url1_historyframe.html";
+var URL2 = BASE_URI + "url2_historyframe.html";
 
 function run_test() {
   window.location.hash = "START";
 
   gFrame = document.getElementById("iframe");
 
   test_basic_inner_navigation();
 }
new file mode 100644
--- /dev/null
+++ b/docshell/test/iframesandbox/file_child_navigation_by_location.html
@@ -0,0 +1,1 @@
+<script>function onNav() { parent.parent.postMessage('childIframe', '*'); } window.onload = onNav; window.onhashchange = onNav;</script>
--- a/docshell/test/iframesandbox/mochitest.ini
+++ b/docshell/test/iframesandbox/mochitest.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 support-files =
+  file_child_navigation_by_location.html
   file_marquee_event_handlers.html
   file_other_auxiliary_navigation_by_location.html
   file_our_auxiliary_navigation_by_location.html
   file_parent_navigation_by_location.html
   file_sibling_navigation_by_location.html
   file_top_navigation_by_location.html
   file_top_navigation_by_location_exotic.html
 
--- a/docshell/test/iframesandbox/test_child_navigation_by_location.html
+++ b/docshell/test/iframesandbox/test_child_navigation_by_location.html
@@ -8,18 +8,17 @@ html5 sandboxed iframe should not be abl
 <meta charset="utf-8">
 <title>Test for Bug 785310 - iframe sandbox child navigation by location tests</title>
 <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
 <script>
   SimpleTest.waitForExplicitFinish();
 
-  var testHtml = "<script>function onNav() { parent.parent.postMessage('childIframe', '*'); } window.onload = onNav; window.onhashchange = onNav;<\/script>";
-  var testDataUri = "data:text/html," + testHtml;
+  var testDataUri = "file_child_navigation_by_location.html";
 
   function runScriptNavigationTest(testCase) {
     window.onmessage = function(event) {
       if (event.data != 'childIframe') {
         ok(false, "event.data: got '" + event.data + "', expected 'childIframe'");
       }
       ok(!testCase.shouldBeBlocked, testCase.desc, "child navigation was NOT blocked");
       runNextTest();
@@ -81,12 +80,12 @@ html5 sandboxed iframe should not be abl
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=785310">Mozilla Bug 785310</a>
 <p id="display"></p>
 <div id="content">
 Tests for Bug 785310
 </div>
 
-<iframe name="parentIframe" sandbox="allow-scripts allow-same-origin" src="data:text/html,<iframe name='sameOriginChildIframe'></iframe><iframe name='crossOriginChildIframe' sandbox='allow-scripts'></iframe>"</iframe>
+<iframe name="parentIframe" sandbox="allow-scripts allow-same-origin" srcdoc="<iframe name='sameOriginChildIframe'></iframe><iframe name='crossOriginChildIframe' sandbox='allow-scripts'></iframe>"</iframe>
 
 </body>
 </html>
--- a/docshell/test/mochitest.ini
+++ b/docshell/test/mochitest.ini
@@ -1,46 +1,57 @@
 [DEFAULT]
 support-files =
   bug123696-subframe.html
   bug369814.jar
   bug369814.zip
   bug404548-subframe.html
+  bug404548-subframe_window.html
   bug413310-post.sjs
   bug413310-subframe.html
   bug529119-window.html
   bug570341_recordevents.html
   bug668513_redirect.html
   bug668513_redirect.html^headers^
   bug691547_frame.html
   dummy_page.html
   file_anchor_scroll_after_document_open.html
+  file_bfcache_plus_hash_1.html
+  file_bfcache_plus_hash_2.html
+  file_bug369814.html
   file_bug385434_1.html
   file_bug385434_2.html
   file_bug385434_3.html
   file_bug475636.sjs
   file_bug509055.html
   file_bug540462.html
   file_bug580069_1.html
   file_bug580069_2.sjs
   file_bug590573_1.html
   file_bug590573_2.html
   file_bug634834.html
   file_bug640387.html
   file_bug653741.html
   file_bug660404
   file_bug660404^headers^
+  file_bug660404-1.html
   file_bug662170.html
   file_bug669671.sjs
   file_bug680257.html
   file_bug703855.html
   file_bug728939.html
+  file_bug1121701_1.html
+  file_bug1121701_2.html
+  file_bug1186774.html
   file_bug1151421.html
   file_pushState_after_document_open.html
   historyframes.html
+  start_historyframe.html
+  url1_historyframe.html
+  url2_historyframe.html
 
 [test_anchor_scroll_after_document_open.html]
 [test_bfcache_plus_hash.html]
 [test_bug123696.html]
 [test_bug369814.html]
 [test_bug384014.html]
 [test_bug385434.html]
 [test_bug387979.html]
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/bluebox_bug430723.html
@@ -0,0 +1,6 @@
+<html><head>
+<script> window.addEventListener("pageshow", function(){opener.nextTest();}, false); </script>
+</head><body>
+<div style="position:absolute; left:0px; top:0px; width:50%; height:150%; background-color:blue">
+<p>This is a very tall blue box.</p>
+</div></body></html>
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -1,14 +1,16 @@
 [DEFAULT]
 support-files =
   NavigationUtils.js
   blank.html
   file_bug386782_contenteditable.html
   file_bug386782_designmode.html
+  redbox_bug430723.html
+  bluebox_bug430723.html
   file_bug462076_1.html
   file_bug462076_2.html
   file_bug462076_3.html
   file_bug508537_1.html
   file_bug534178.html
   file_document_write_1.html
   file_fragment_handling_during_load.html
   file_nested_frames.html
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/redbox_bug430723.html
@@ -0,0 +1,6 @@
+<html><head>
+<script> window.addEventListener("pageshow", function(){opener.nextTest();}, false); </script> 
+</head><body>
+<div style="position:absolute; left:0px; top:0px; width:50%; height:150%; background-color:red">
+<p>This is a very tall red box.</p>
+</div></body></html>
--- a/docshell/test/navigation/test_bug430624.html
+++ b/docshell/test/navigation/test_bug430624.html
@@ -20,17 +20,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 430624 **/
 
 function onLoad() {
   window.frames[0].frameElement.onload = onReload;
-  window.frames[0].location = window.frames[0].location;
+  window.frames[0].frameElement.srcdoc = window.frames[0].frameElement.srcdoc;
 }
 
 function onReload() {
   var iframe = window.frames[0].frameElement;
   SimpleTest.waitForFocus(doTest, iframe.contentWindow);
   iframe.contentDocument.body.focus();
 }
 
@@ -44,13 +44,13 @@ function doTest() {
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 
-<iframe onload="onLoad()" src="data:text/html;charset=utf-8,<body contenteditable>contentEditable</body>"></iframe>
+<iframe onload="onLoad()" srcdoc="<body contenteditable>contentEditable</body>"></iframe>
 
 </body>
 </html>
 
--- a/docshell/test/navigation/test_bug430723.html
+++ b/docshell/test/navigation/test_bug430723.html
@@ -16,31 +16,19 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 //<![CDATA[
 
 /** Test for Bug 430723 **/
 
-var gTallRedBoxURI = "data:text/html;charset=utf-8;base64,PGh0bWw%2BPGhlYWQ%2BPHNjcmlwdD53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncGFnZXNob3cnLCBmdW5jdGlvbigpe29wZW5lci5uZXh0VGVzdCgpO30sIGZhbHNlKTs8L3NjcmlwdD48L2hlYWQ%2BPGJvZHk%2BPGRpdiBzdHlsZT0icG9zaXRpb246YWJzb2x1dGU7IGxlZnQ6MHB4OyB0b3A6MHB4OyB3aWR0aDo1MCU7IGhlaWdodDoxNTAlOyBiYWNrZ3JvdW5kLWNvbG9yOnJlZCI%2BPHA%2BVGhpcyBpcyBhIHZlcnkgdGFsbCByZWQgYm94LjwvcD48L2Rpdj48L2JvZHk%2BPC9odG1sPg%3D%3D";
-// <html><head>
-// < script > window.addEventListener("pageshow", function(){opener.nextTest();}, false); < /script > 
-// </head><body>
-// <div style="position:absolute; left:0px; top:0px; width:50%; height:150%; background-color:red">
-// <p>This is a very tall red box.</p>
-// </div></body></html>
-
-var gTallBlueBoxURI = "data:text/html;charset=utf-8;base64,PGh0bWw%2BPGhlYWQ%2BPHNjcmlwdD53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncGFnZXNob3cnLCBmdW5jdGlvbigpe29wZW5lci5uZXh0VGVzdCgpO30sIGZhbHNlKTs8L3NjcmlwdD48L2hlYWQ%2BPGJvZHk%2BPGRpdiBzdHlsZT0icG9zaXRpb246YWJzb2x1dGU7IGxlZnQ6MHB4OyB0b3A6MHB4OyB3aWR0aDo1MCU7IGhlaWdodDoxNTAlOyBiYWNrZ3JvdW5kLWNvbG9yOmJsdWUiPjxwPlRoaXMgaXMgYSB2ZXJ5IHRhbGwgYmx1ZSBib3guPC9wPjwvZGl2PjwvYm9keT48L2h0bWw%2B";
-// <html><head>
-// < script > window.addEventListener("pageshow", function(){opener.nextTest();}, false); < /script > 
-// </head><body>
-// <div style="position:absolute; left:0px; top:0px; width:50%; height:150%; background-color:blue">
-// <p>This is a very tall blue box.</p>
-// </div></body></html>
+var BASE_URI = "http://mochi.test:8888/tests/docshell/test/navigation/";
+var gTallRedBoxURI = BASE_URI + "redbox_bug430723.html";
+var gTallBlueBoxURI = BASE_URI + "bluebox_bug430723.html";
 
 window.onload = runTest;
 
 var testWindow;
 var testNum = 0;
 
 var smoothScrollPref = "general.smoothScroll";
 function runTest() {
new file mode 100644
--- /dev/null
+++ b/docshell/test/start_historyframe.html
@@ -0,0 +1,1 @@
+<p id='text'>Start</p>
--- a/docshell/test/test_bfcache_plus_hash.html
+++ b/docshell/test/test_bfcache_plus_hash.html
@@ -77,27 +77,23 @@ function waitForLoad(n) {
 }
 
 function waitForShow(n) {
   debug('Waiting for show ' + n);
   expectedPageshowNum = n;
 }
 
 function* test() {
-  var popup = window.open('data:text/html,' +
-                          '<html><body onload="opener.childLoad(1)" ' +
-                                      'onpageshow="opener.childPageshow(1)">' +
-                                'Popup 1' +
-                                '</body></html>');
+  var popup = window.open('file_bfcache_plus_hash_1.html');
   waitForLoad(1);
   yield undefined;
 
   popup.history.pushState('', '', '');
 
-  popup.location = 'data:text/html,<html><body onload="opener.childLoad(2)">Popup 2</body></html>';
+  popup.location = 'file_bfcache_plus_hash_2.html';
   waitForLoad(2);
   yield undefined;
 
   // Now go back 2.  The first page should be retrieved from bfcache.
   popup.history.go(-2);
   waitForShow(1);
   yield undefined;
 
--- a/docshell/test/test_bug1121701.html
+++ b/docshell/test/test_bug1121701.html
@@ -7,18 +7,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <meta charset="utf-8">
   <title>Test for Bug 1121701</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
 
   /** Test for Bug 1121701 **/
 
-  var testUrl1 = "data:text/html,<script>window.onpageshow = function(e) { opener.child1PageShow(e); } <" + "/script>";
-  var testUrl2 = "data:text/html,<script>window.onpageshow = function(e) { opener.child2PageShow(e); } <" + "/script>";
+  var testUrl1 = "file_bug1121701_1.html";
+  var testUrl2 = "file_bug1121701_2.html";
   var testWin;
 
   var page1LoadCount = 0;
   function child1PageShow(e) {
     ++page1LoadCount;
     if (page1LoadCount == 1) {
       SimpleTest.executeSoon(function() {
         is(e.persisted, false, "Initial page load shouldn't be persisted.");
--- a/docshell/test/test_bug1186774.html
+++ b/docshell/test/test_bug1186774.html
@@ -10,17 +10,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
 
   /** Test for Bug 1186774 **/
 
 var child;
 
 function runTest() {
-  child = window.open("data:text/html,<div style='height: 9000px;'></div>", "", "width=100,height=100");
+  child = window.open("file_bug1186774.html", "", "width=100,height=100");
   child.onload = function() {
     setTimeout(function() {
       child.scrollTo(0, 0);
       child.history.pushState({}, "initial");
       child.scrollTo(0, 3000);
       child.history.pushState({}, "scrolled");
       child.scrollTo(0, 6000);
       child.history.back();
--- a/docshell/test/test_bug369814.html
+++ b/docshell/test/test_bug369814.html
@@ -86,17 +86,17 @@ function loadErrorTest(test)
       } catch (e) {
         errorPage = true;
       }
       ok(errorPage, gCurrentTest["name"] + ": should block a suspicious JAR load.");
 
       finishTest();
     }, 0);
   }
-  var unloadDetector = "data:text/html,<script>window.onunload = function() { frameElement.unloading(); }</" + "script>";
+  var unloadDetector = "file_bug369814.html";
   gTestFrame.src = unloadDetector;
 }
 
 function iframeTest(test) {
   gTestFrame.src = test['url'];
   loadEvent(gTestFrame, function() {
       finishTest();
     });
--- a/docshell/test/test_bug660404.html
+++ b/docshell/test/test_bug660404.html
@@ -35,14 +35,14 @@ function continueTest() {
 function finishTest() {
   is(w.document.documentElement.textContent, "opener.finishTest();");
   is(w.document.documentElement.innerHTML, "<head><script>opener.finishTest();</"+"script></head>");
   w.close();
   SimpleTest.finish();
 }
 
 // Have to open a new window, since there's no bfcache in subframes
-w = window.open("data:text/html,<script>window.onload = function() { opener.continueTest(); }</"+"script>");
+w = window.open("file_bug660404-1.html");
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/url1_historyframe.html
@@ -0,0 +1,1 @@
+<p id='text'>Test1</p>
new file mode 100644
--- /dev/null
+++ b/docshell/test/url2_historyframe.html
@@ -0,0 +1,1 @@
+<p id='text'>Test2</p>
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -944,16 +944,18 @@ nsContentUtils::InitializeEventTable() {
   sAtomEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>(
       ArrayLength(eventArray));
   sStringEventTable = new nsDataHashtable<nsStringHashKey, EventNameMapping>(
       ArrayLength(eventArray));
   sUserDefinedEvents = new nsCOMArray<nsIAtom>(64);
 
   // Subtract one from the length because of the trailing null
   for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) {
+    MOZ_ASSERT(!sAtomEventTable->Lookup(eventArray[i].mAtom),
+               "Double-defining event name; fix your EventNameList.h");
     sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]);
     if (ShouldAddEventToStringEventTable(eventArray[i])) {
       sStringEventTable->Put(
         Substring(nsDependentAtomString(eventArray[i].mAtom), 2),
         eventArray[i]);
     }
   }
 
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -29,17 +29,18 @@ StaticRefPtr<nsWindowMemoryReporter> sWi
  * Don't trigger a ghost window check when a DOM window is detached if we've
  * run it this recently.
  */
 const int32_t kTimeBetweenChecks = 45; /* seconds */
 
 nsWindowMemoryReporter::nsWindowMemoryReporter()
   : mLastCheckForGhostWindows(TimeStamp::NowLoRes()),
     mCycleCollectorIsRunning(false),
-    mCheckTimerWaitingForCCEnd(false)
+    mCheckTimerWaitingForCCEnd(false),
+    mGhostWindowCount(0)
 {
 }
 
 nsWindowMemoryReporter::~nsWindowMemoryReporter()
 {
   KillCheckTimer();
 }
 
@@ -114,18 +115,17 @@ nsWindowMemoryReporter::Init()
     os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
                     /* weakRef = */ true);
     os->AddObserver(sWindowReporter, "cycle-collector-begin",
                     /* weakRef = */ true);
     os->AddObserver(sWindowReporter, "cycle-collector-end",
                     /* weakRef = */ true);
   }
 
-  RegisterStrongMemoryReporter(new GhostWindowsReporter());
-  RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
+  RegisterGhostWindowsDistinguishedAmount(GhostWindowsDistinguishedAmount);
 }
 
 /* static */ nsWindowMemoryReporter*
 nsWindowMemoryReporter::Get()
 {
   return sWindowReporter;
 }
 
@@ -486,16 +486,27 @@ nsWindowMemoryReporter::CollectReports(n
       path,
       nsIMemoryReporter::KIND_OTHER,
       nsIMemoryReporter::UNITS_COUNT,
       /* amount = */ 1,
       /* description = */ NS_LITERAL_CSTRING("A ghost window."),
       aData);
   }
 
+  MOZ_COLLECT_REPORT(
+    "ghost-windows", KIND_OTHER, UNITS_COUNT, ghostWindows.Count(),
+"The number of ghost windows present (the number of nodes underneath "
+"explicit/window-objects/top(none)/ghost, modulo race conditions).  A ghost "
+"window is not shown in any tab, does not share a domain with any non-detached "
+"windows, and has met these criteria for at least "
+"memory.ghost_window_timeout_seconds, or has survived a round of "
+"about:memory's minimize memory usage button.\n\n"
+"Ghost windows can happen legitimately, but they are often indicative of "
+"leaks in the browser or add-ons.");
+
   WindowPaths windowPaths;
   WindowPaths topWindowPaths;
 
   // Collect window memory usage.
   nsWindowSizes windowTotalSizes(nullptr);
   nsCOMPtr<amIAddonManager> addonManager;
   if (XRE_IsParentProcess()) {
     // Only try to access the service from the main process.
@@ -729,39 +740,46 @@ nsWindowMemoryReporter::CheckForGhostWin
     NS_WARNING("GetWindowsTable returned null");
     return;
   }
 
   mLastCheckForGhostWindows = TimeStamp::NowLoRes();
   KillCheckTimer();
 
   nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
+  nsDataHashtable<nsISupportsHashKey, nsCString> domainMap;
 
   // Populate nonDetachedWindowDomains.
   for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
     // Null outer window implies null top, but calling GetTop() when there's no
     // outer window causes us to spew debug warnings.
     nsGlobalWindow* window = iter.UserData();
     if (!window->GetOuterWindow() || !window->GetTopInternal()) {
       // This window is detached, so we don't care about its domain.
       continue;
     }
 
     nsCOMPtr<nsIURI> uri = GetWindowURI(window);
     nsAutoCString domain;
     if (uri) {
-      tldService->GetBaseDomain(uri, 0, domain);
+      domain = domainMap.LookupForAdd(uri).OrInsert([&]() {
+        nsCString d;
+        tldService->GetBaseDomain(uri, 0, d);
+        return d;
+      });
     }
+
     nonDetachedWindowDomains.PutEntry(domain);
   }
 
   // Update mDetachedWindows and write the ghost window IDs into aOutGhostIDs,
   // if it's not null.
   uint32_t ghostTimeout = GetGhostTimeout();
   TimeStamp now = mLastCheckForGhostWindows;
+  mGhostWindowCount = 0;
   for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
     nsWeakPtr weakKey = do_QueryInterface(iter.Key());
     nsCOMPtr<mozIDOMWindow> iwindow = do_QueryReferent(weakKey);
     if (!iwindow) {
       // The window object has been destroyed.  Stop tracking its weak ref in
       // our hashtable.
       iter.Remove();
       continue;
@@ -804,31 +822,27 @@ nsWindowMemoryReporter::CheckForGhostWin
       if (timeStamp.IsNull()) {
         // This may become a ghost window later; start its clock.
         timeStamp = now;
       } else if ((now - timeStamp).ToSeconds() > ghostTimeout) {
         // This definitely is a ghost window, so add it to aOutGhostIDs, if
         // that is not null.
         if (aOutGhostIDs && window) {
           aOutGhostIDs->PutEntry(window->WindowID());
+          mGhostWindowCount++;
         }
       }
     }
   }
 }
 
-NS_IMPL_ISUPPORTS(nsWindowMemoryReporter::GhostWindowsReporter,
-                  nsIMemoryReporter)
-
 /* static */ int64_t
-nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
+nsWindowMemoryReporter::GhostWindowsDistinguishedAmount()
 {
-  nsTHashtable<nsUint64HashKey> ghostWindows;
-  sWindowReporter->CheckForGhostWindows(&ghostWindows);
-  return ghostWindows.Count();
+  return sWindowReporter->mGhostWindowCount;
 }
 
 void
 nsWindowMemoryReporter::KillCheckTimer()
 {
   if (mCheckTimer) {
     mCheckTimer->Cancel();
     mCheckTimer = nullptr;
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -157,50 +157,21 @@ public:
    * to become ghost windows in the first place.
    */
   static void UnlinkGhostWindows();
 #endif
 
   static nsWindowMemoryReporter* Get();
   void ObserveDOMWindowDetached(nsGlobalWindow* aWindow);
 
+  static int64_t GhostWindowsDistinguishedAmount();
+
 private:
   ~nsWindowMemoryReporter();
 
-  /**
-   * nsGhostWindowReporter generates the "ghost-windows" report, which counts
-   * the number of ghost windows present.
-   */
-  class GhostWindowsReporter final : public nsIMemoryReporter
-  {
-    ~GhostWindowsReporter() {}
-  public:
-    NS_DECL_ISUPPORTS
-
-    static int64_t DistinguishedAmount();
-
-    NS_IMETHOD
-    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
-                   bool aAnonymize) override
-    {
-      MOZ_COLLECT_REPORT(
-        "ghost-windows", KIND_OTHER, UNITS_COUNT, DistinguishedAmount(),
-"The number of ghost windows present (the number of nodes underneath "
-"explicit/window-objects/top(none)/ghost, modulo race conditions).  A ghost "
-"window is not shown in any tab, does not share a domain with any non-detached "
-"windows, and has met these criteria for at least "
-"memory.ghost_window_timeout_seconds, or has survived a round of "
-"about:memory's minimize memory usage button.\n\n"
-"Ghost windows can happen legitimately, but they are often indicative of "
-"leaks in the browser or add-ons.");
-
-      return NS_OK;
-    }
-  };
-
   // Protect ctor, use Init() instead.
   nsWindowMemoryReporter();
 
   /**
    * Get the number of seconds for which a window must satisfy ghost criteria
    * (1) and (2) before we deem that it satisfies criterion (3).
    */
   uint32_t GetGhostTimeout();
@@ -253,12 +224,14 @@ private:
    */
   mozilla::TimeStamp mLastCheckForGhostWindows;
 
   nsCOMPtr<nsITimer> mCheckTimer;
 
   bool mCycleCollectorIsRunning;
 
   bool mCheckTimerWaitingForCCEnd;
+
+  int64_t mGhostWindowCount;
 };
 
 #endif // nsWindowMemoryReporter_h__
 
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -632,16 +632,17 @@ skip-if = toolkit == 'android' #bug 9041
 [test_copypaste.xhtml]
 subsuite = clipboard
 skip-if = toolkit == 'android' #bug 904183
 [test_createHTMLDocument.html]
 [test_declare_stylesheet_obsolete.html]
 [test_dialogArguments.html]
 tags = openwindow
 skip-if = toolkit == 'android' || e10s # showmodaldialog
+[test_data_uri.html]
 [test_document.all_iteration.html]
 [test_document.all_unqualified.html]
 [test_document_constructor.html]
 [test_document_importNode_document.html]
 [test_document_register.html]
 [test_domcursor.html]
 [test_domparser_null_char.html]
 [test_domparsing.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_data_uri.html
@@ -0,0 +1,102 @@
+<html>
+<head>
+  <title>Tests for Data URI</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+
+<script>
+SpecialPowers.setBoolPref("security.data_uri.unique_opaque_origin", true);
+SimpleTest.registerCleanupFunction(() => {
+  SpecialPowers.clearUserPref("security.data_uri.unique_opaque_origin");
+});
+
+SimpleTest.waitForExplicitFinish();
+
+function imgListener(img) {
+  return new Promise((resolve, reject) => {
+    img.addEventListener("load", () => resolve());
+    img.addEventListener("error", () => reject());
+  });
+}
+
+function runTests()
+{
+  var iframe = document.getElementById("iframe");
+  iframe.src="data:text/html,hello";
+  iframe.onload = function() {
+    ok(SpecialPowers.wrap(iframe).contentDocument.nodePrincipal.isNullPrincipal,
+       "iframe should have NullPrincipal.");
+  }
+  var iframe1 = document.getElementById("iframe1");
+  iframe1.src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82";
+  iframe1.onload = function() {
+    ok(SpecialPowers.wrap(iframe1).contentDocument.nodePrincipal.isNullPrincipal,
+       "iframe1 should have NullPrincipal.");
+  }
+
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+  ctx.fillRect(0, 0, canvas.height, canvas.width);
+  ctx.fillStyle = '#000';
+  var data = canvas.toDataURL('image/png');
+  var img = new Image();
+  img.src = data;
+  imgListener(img).then(() => {
+    dump("img onload\n");
+    ctx.drawImage(img, 0, 0);
+    return new Promise((resolve, reject) => {
+      try {
+        ctx.getImageData(0, 0, 1, 1);
+        ok(true, "data:image should be same origin.");
+        resolve();
+      } catch (e) {
+        ok(false, "data:image is cross-origin.");
+        reject();
+      }});
+  }).then(() => {
+    ctx.clearRect(0, 0, canvas.height, canvas.width);
+    ctx.drawImage(document.getElementById('img'), 0, 0);
+    return new Promise((resolve, reject) => {
+      try {
+        canvas.toDataURL();
+        ok(true, "data:image should be same origin.");
+        resolve();
+      } catch (e) {
+        ok(false, "data:image is cross-origin.");
+        reject();
+      }});
+  }).then(() => {
+    var win = window.open("data:text/html,<script>parent.opener.postMessage('ok', '*');<\/script>");
+    return new Promise(resolve => {
+      window.onmessage = function (evt) {
+        is(evt.origin, "null", "The origin of data:text/html should be null.");
+        win.close();
+        resolve();
+      }});
+  }).then(() => {
+    document.fonts.add(new FontFace("test", "url(data:font/opentype;base64,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AC4AIABDAG8AcAB5AHIAaQBnAGgAdAAgAGkAbgBmAG8AIABwAGUAbgBkAGkAbgBnAC4AbABvAGEAZAB0AGUAcwB0AFIAZQBnAHUAbABhAHIAdwBlAGIAZgBvAG4AdABsAG8AYQBkAHQAZQBzAHQAIABSAGUAZwB1AGwAYQByAFYAZQByAHMAaQBvAG4AIAAwADAAMQAuADAAMAAxAEIAYQBzAGUAZAAgAG8AbgAgAEwAZQBhAGcAdQBlACAARwBvAHQAaABpAGMAIABiAHkAIABMAGUAYQBnAHUAZQAgAG8AZgAgAE0AbwB2AGUAYQBiAGwAZQAgAFQAeQBwAGUALAAgAG0AbwBkAGkAZgBpAGUAZAAgAGIAeQAgAEoAbwBoAG4AIABEAGEAZwBnAGUAdAB0AGgAdAB0AHAAOgAvAC8AdwB3AHcALgB0AGgAZQBsAGUAYQBnAHUAZQBvAGYAbQBvAHYAZQBhAGIAbABlAHQAeQBwAGUALgBjAG8AbQAvAGwAZQBhAGcAdQBlAC0AZwBvAHQAaABpAGMAQQBsAGwAIABmAG8AbgB0AHMAIABmAHIAbwBtACAAVABoAGUAIABMAGUAYQBnAHUAZQAgAG8AZgAgAE0AbwB2AGUAYQBiAGwAZQAgAFQAeQBwAGUAIABhAHIAZQAgAHMAdQBiAGoAZQBjAHQAIAB0AG8AIAB0AGgAZQAgAE8AcABlAG4AIABGAG8AbgB0ACAATABpAGMAZQBuAHMAZQBoAHQAdABwADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAAgAAAAAAAP9nAGYAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgBfAGAAYQECAKMAhACFAJYAjgCLAQMAigDaAI0AwwDeAKIArQDJAMcArgBiAGMAkABkAMsAZQDIAMoAzwDMAM0AzgDpAGYA0wDQANEArwBnAJEA1gDUANUAaADrAO0AiQBqAGkAawBtAGwAbgCgAG8AcQBwAHIAcwB1AHQAdgB3AOoAeAB6AHkAewB9AHwAoQB/AH4AgACBAOwA7gC6ANcA4gDjALAAsQDkAOUAuwDmAOcA2ADhANsA3ADdAOAA2QDfAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQCyALMAtgC3AMQAtAC1AMUAhwCrARIBEwEUAIwA7wEVARYBFwd1bmkwMEEwB3VuaTAwQUQHdW5pMjAwMAd1bmkyMDAxB3VuaTIwMDIHdW5pMjAwMwd1bmkyMDA0B3VuaTIwMDUHdW5pMjAwNgd1bmkyMDA3B3VuaTIwMDgHdW5pMjAwOQd1bmkyMDBBB3VuaTIwMTAHdW5pMjAxMQpmaWd1cmVkYXNoB3VuaTIwMkYHdW5pMjA1RgRFdXJvB3VuaUUwMDAHdW5pRkIwMQd1bmlGQjAyAAAAAQAB//8ADwAAAAEAAAAAyYlvMQAAAADGp3m3AAAAAMrhKHcAAQAAAAwAAAAWAAAAAgABAAEA3wABAAQAAAABAAAAAAABAAAACgAuADwAAkRGTFQADmxhdG4AGAAEAAAAAP//AAAABAAAAAD//wABAAAAAVRTVDEACAAAAAEAAAABAAQAAQAAAAEACAACAA4ABABEADMANgBWAAEABAAkACkALAAvAAA=)"));
+    return document.fonts.ready;
+  }).then(() => {
+    is(document.fonts.size, 1, "should load data:font");
+    SimpleTest.finish();
+  }).catch((e) => {
+    ok(false, "throwing " + e);
+    SimpleTest.finish();
+  });
+}
+</script>
+
+<link rel="stylesheet" href="data:text/css,.green-text{color:rgb(0, 255, 0)}"
+      onload="ok(true, 'data:text/css should be same origin.');"
+      onerror="ok(false, 'data:text/css should be same origin');">
+
+<body onload="runTests()">
+<img style="width: 100px; height: 100px;"
+     src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
+     id="img">
+<iframe id="iframe"></iframe>
+<iframe id="iframe1" ></iframe>
+<canvas id="canvas" class="output" width="100" height="50">
+</body>
+</html>
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -177,17 +177,17 @@ EVENT(auxclick,
       EventNameType_All,
       eMouseEventClass)
 EVENT(click,
       eMouseClick,
       EventNameType_All,
       eMouseEventClass)
 EVENT(close,
       eClose,
-      EventNameType_HTML,
+      EventNameType_HTMLXUL,
       eBasicEventClass)
 EVENT(contextmenu,
       eContextMenu,
       EventNameType_HTMLXUL,
       eMouseEventClass)
 NON_IDL_EVENT(mouselongtap,
       eMouseLongTap,
       EventNameType_HTMLXUL,
@@ -779,20 +779,16 @@ NON_IDL_EVENT(compositionupdate,
 NON_IDL_EVENT(compositionend,
               eCompositionEnd,
               EventNameType_XUL,
               eCompositionEventClass)
 NON_IDL_EVENT(command,
               eXULCommand,
               EventNameType_XUL,
               eInputEventClass)
-NON_IDL_EVENT(close,
-              eWindowClose,
-              EventNameType_XUL,
-              eBasicEventClass)
 NON_IDL_EVENT(popupshowing,
               eXULPopupShowing,
               EventNameType_XUL,
               eBasicEventClass)
 NON_IDL_EVENT(popupshown,
               eXULPopupShown,
               EventNameType_XUL,
               eBasicEventClass)
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -7411,266 +7411,17 @@ HTMLInputElement::GetValidationMessage(n
 {
   aRv = GetValidationMessage(aValidationMessage);
 }
 
 nsresult
 HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
                                        ValidityStateType aType)
 {
-  nsresult rv = NS_OK;
-
-  switch (aType)
-  {
-    case VALIDITY_STATE_TOO_LONG:
-    {
-      nsXPIDLString message;
-      int32_t maxLength = MaxLength();
-      int32_t textLength = InputTextLength(CallerType::System);
-      nsAutoString strMaxLength;
-      nsAutoString strTextLength;
-
-      strMaxLength.AppendInt(maxLength);
-      strTextLength.AppendInt(textLength);
-
-      const char16_t* params[] = { strMaxLength.get(), strTextLength.get() };
-      rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                 "FormValidationTextTooLong",
-                                                 params, message);
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_TOO_SHORT:
-    {
-      nsXPIDLString message;
-      int32_t minLength = MinLength();
-      int32_t textLength = InputTextLength(CallerType::System);
-      nsAutoString strMinLength;
-      nsAutoString strTextLength;
-
-      strMinLength.AppendInt(minLength);
-      strTextLength.AppendInt(textLength);
-
-      const char16_t* params[] = { strMinLength.get(), strTextLength.get() };
-      rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                 "FormValidationTextTooShort",
-                                                 params, message);
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_VALUE_MISSING:
-    {
-      nsXPIDLString message;
-      nsAutoCString key;
-      switch (mType)
-      {
-        case NS_FORM_INPUT_FILE:
-          key.AssignLiteral("FormValidationFileMissing");
-          break;
-        case NS_FORM_INPUT_CHECKBOX:
-          key.AssignLiteral("FormValidationCheckboxMissing");
-          break;
-        case NS_FORM_INPUT_RADIO:
-          key.AssignLiteral("FormValidationRadioMissing");
-          break;
-        case NS_FORM_INPUT_NUMBER:
-          key.AssignLiteral("FormValidationBadInputNumber");
-          break;
-        default:
-          key.AssignLiteral("FormValidationValueMissing");
-      }
-      rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                              key.get(), message);
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_TYPE_MISMATCH:
-    {
-      nsXPIDLString message;
-      nsAutoCString key;
-      if (mType == NS_FORM_INPUT_EMAIL) {
-        key.AssignLiteral("FormValidationInvalidEmail");
-      } else if (mType == NS_FORM_INPUT_URL) {
-        key.AssignLiteral("FormValidationInvalidURL");
-      } else {
-        return NS_ERROR_UNEXPECTED;
-      }
-      rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                              key.get(), message);
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_PATTERN_MISMATCH:
-    {
-      nsXPIDLString message;
-      nsAutoString title;
-      GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
-      if (title.IsEmpty()) {
-        rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                "FormValidationPatternMismatch",
-                                                message);
-      } else {
-        if (title.Length() > nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
-          title.Truncate(nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
-        }
-        const char16_t* params[] = { title.get() };
-        rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                   "FormValidationPatternMismatchWithTitle",
-                                                   params, message);
-      }
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_RANGE_OVERFLOW:
-    {
-      static const char kNumberOverTemplate[] = "FormValidationNumberRangeOverflow";
-      static const char kDateOverTemplate[] = "FormValidationDateRangeOverflow";
-      static const char kTimeOverTemplate[] = "FormValidationTimeRangeOverflow";
-
-      const char* msgTemplate;
-      nsXPIDLString message;
-
-      nsAutoString maxStr;
-      if (mType == NS_FORM_INPUT_NUMBER ||
-          mType == NS_FORM_INPUT_RANGE) {
-        msgTemplate = kNumberOverTemplate;
-
-        //We want to show the value as parsed when it's a number
-        Decimal maximum = GetMaximum();
-        MOZ_ASSERT(!maximum.isNaN());
-
-        char buf[32];
-        DebugOnly<bool> ok = maximum.toString(buf, ArrayLength(buf));
-        maxStr.AssignASCII(buf);
-        MOZ_ASSERT(ok, "buf not big enough");
-      } else if (IsDateTimeInputType(mType)) {
-        msgTemplate = mType == NS_FORM_INPUT_TIME ? kTimeOverTemplate : kDateOverTemplate;
-        GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
-      } else {
-        msgTemplate = kNumberOverTemplate;
-        NS_NOTREACHED("Unexpected input type");
-      }
-
-      const char16_t* params[] = { maxStr.get() };
-      rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                 msgTemplate,
-                                                 params, message);
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_RANGE_UNDERFLOW:
-    {
-      static const char kNumberUnderTemplate[] = "FormValidationNumberRangeUnderflow";
-      static const char kDateUnderTemplate[] = "FormValidationDateRangeUnderflow";
-      static const char kTimeUnderTemplate[] = "FormValidationTimeRangeUnderflow";
-
-      const char* msgTemplate;
-      nsXPIDLString message;
-
-      nsAutoString minStr;
-      if (mType == NS_FORM_INPUT_NUMBER ||
-          mType == NS_FORM_INPUT_RANGE) {
-        msgTemplate = kNumberUnderTemplate;
-
-        Decimal minimum = GetMinimum();
-        MOZ_ASSERT(!minimum.isNaN());
-
-        char buf[32];
-        DebugOnly<bool> ok = minimum.toString(buf, ArrayLength(buf));
-        minStr.AssignASCII(buf);
-        MOZ_ASSERT(ok, "buf not big enough");
-      } else if (IsDateTimeInputType(mType)) {
-        msgTemplate = mType == NS_FORM_INPUT_TIME ? kTimeUnderTemplate : kDateUnderTemplate;
-        GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
-      } else {
-        msgTemplate = kNumberUnderTemplate;
-        NS_NOTREACHED("Unexpected input type");
-      }
-
-      const char16_t* params[] = { minStr.get() };
-      rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                 msgTemplate,
-                                                 params, message);
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_STEP_MISMATCH:
-    {
-      nsXPIDLString message;
-
-      Decimal value = GetValueAsDecimal();
-      MOZ_ASSERT(!value.isNaN());
-
-      Decimal step = GetStep();
-      MOZ_ASSERT(step != kStepAny && step > Decimal(0));
-
-      Decimal stepBase = GetStepBase();
-
-      Decimal valueLow = value - NS_floorModulo(value - stepBase, step);
-      Decimal valueHigh = value + step - NS_floorModulo(value - stepBase, step);
-
-      Decimal maximum = GetMaximum();
-
-      if (maximum.isNaN() || valueHigh <= maximum) {
-        nsAutoString valueLowStr, valueHighStr;
-        mInputType->ConvertNumberToString(valueLow, valueLowStr);
-        mInputType->ConvertNumberToString(valueHigh, valueHighStr);
-
-        if (valueLowStr.Equals(valueHighStr)) {
-          const char16_t* params[] = { valueLowStr.get() };
-          rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                     "FormValidationStepMismatchOneValue",
-                                                     params, message);
-        } else {
-          const char16_t* params[] = { valueLowStr.get(), valueHighStr.get() };
-          rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                     "FormValidationStepMismatch",
-                                                     params, message);
-        }
-      } else {
-        nsAutoString valueLowStr;
-        mInputType->ConvertNumberToString(valueLow, valueLowStr);
-
-        const char16_t* params[] = { valueLowStr.get() };
-        rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                   "FormValidationStepMismatchOneValue",
-                                                   params, message);
-      }
-
-      aValidationMessage = message;
-      break;
-    }
-    case VALIDITY_STATE_BAD_INPUT:
-    {
-      nsXPIDLString message;
-      nsAutoCString key;
-      if (mType == NS_FORM_INPUT_NUMBER) {
-        key.AssignLiteral("FormValidationBadInputNumber");
-      } else if (mType == NS_FORM_INPUT_EMAIL) {
-        key.AssignLiteral("FormValidationInvalidEmail");
-      } else if (mType == NS_FORM_INPUT_DATE && IsInputDateTimeEnabled()) {
-        // For input date and time, only date may have an invalid value, as
-        // we forbid or autocorrect values that are not in the valid range for
-        // time. For example, in 12hr format, if user enters '2' in the hour
-        // field, it will be treated as '02' and automatically advance to the
-        // next field.
-        key.AssignLiteral("FormValidationInvalidDate");
-      } else {
-        return NS_ERROR_UNEXPECTED;
-      }
-      rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                              key.get(), message);
-      aValidationMessage = message;
-      break;
-    }
-    default:
-      rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
-  }
-
-  return rv;
+  return mInputType->GetValidationMessage(aValidationMessage, aType);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLInputElement::IsSingleLineTextControl() const
 {
   return IsSingleLineTextControl(false);
 }
 
--- a/dom/html/input/CheckableInputTypes.cpp
+++ b/dom/html/input/CheckableInputTypes.cpp
@@ -3,21 +3,41 @@
 /* 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 "CheckableInputTypes.h"
 
 #include "mozilla/dom/HTMLInputElement.h"
 
+/* input type=checkbox */
+
 bool
 CheckboxInputType::IsValueMissing() const
 {
   if (!mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
     return false;
   }
 
   if (!IsMutable()) {
     return false;
   }
 
   return !mInputElement->Checked();
 }
+
+nsresult
+CheckboxInputType::GetValueMissingMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                            "FormValidationCheckboxMissing",
+                                            aMessage);
+}
+
+/* input type=radio */
+
+nsresult
+RadioInputType::GetValueMissingMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                            "FormValidationRadioMissing",
+                                            aMessage);
+}
--- a/dom/html/input/CheckableInputTypes.h
+++ b/dom/html/input/CheckableInputTypes.h
@@ -27,31 +27,35 @@ public:
   static InputType*
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) CheckboxInputType(aInputElement);
   }
 
   bool IsValueMissing() const override;
 
+  nsresult GetValueMissingMessage(nsXPIDLString& aMessage) override;
+
 private:
   explicit CheckboxInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : CheckableInputTypeBase(aInputElement)
   {}
 };
 
 // input type=radio
 class RadioInputType : public CheckableInputTypeBase
 {
 public:
   static InputType*
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) RadioInputType(aInputElement);
   }
 
+  nsresult GetValueMissingMessage(nsXPIDLString& aMessage) override;
+
 private:
   explicit RadioInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : CheckableInputTypeBase(aInputElement)
   {}
 };
 
 #endif /* CheckableInputTypes_h__ */
--- a/dom/html/input/DateTimeInputTypes.cpp
+++ b/dom/html/input/DateTimeInputTypes.cpp
@@ -11,16 +11,31 @@
 #include "nsDateTimeControlFrame.h"
 
 const double DateTimeInputTypeBase::kMinimumYear = 1;
 const double DateTimeInputTypeBase::kMaximumYear = 275760;
 const double DateTimeInputTypeBase::kMaximumMonthInMaximumYear = 9;
 const double DateTimeInputTypeBase::kMaximumWeekInMaximumYear = 37;
 const double DateTimeInputTypeBase::kMsPerDay = 24 * 60 * 60 * 1000;
 
+/* static */ bool
+DateTimeInputTypeBase::IsInputDateTimeEnabled()
+{
+  static bool sDateTimeEnabled = false;
+  static bool sDateTimePrefCached = false;
+  if (!sDateTimePrefCached) {
+    sDateTimePrefCached = true;
+    mozilla::Preferences::AddBoolVarCache(&sDateTimeEnabled,
+                                          "dom.forms.datetime",
+                                          false);
+  }
+
+  return sDateTimeEnabled;
+}
+
 bool
 DateTimeInputTypeBase::IsMutable() const
 {
   return !mInputElement->IsDisabled() &&
          !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
 }
 
 bool
@@ -98,16 +113,38 @@ DateTimeInputTypeBase::HasBadInput() con
   if (!frame) {
     return false;
   }
 
   return frame->HasBadInput();;
 }
 
 nsresult
+DateTimeInputTypeBase::GetRangeOverflowMessage(nsXPIDLString& aMessage)
+{
+  nsAutoString maxStr;
+  mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
+
+  const char16_t* params[] = { maxStr.get() };
+  return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationDateTimeRangeOverflow", params, aMessage);
+}
+
+nsresult
+DateTimeInputTypeBase::GetRangeUnderflowMessage(nsXPIDLString& aMessage)
+{
+  nsAutoString minStr;
+  mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
+
+  const char16_t* params[] = { minStr.get() };
+  return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationDateTimeRangeUnderflow", params, aMessage);
+}
+
+nsresult
 DateTimeInputTypeBase::MinMaxStepAttrChanged()
 {
   nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
   if (frame) {
     frame->OnMinMaxStepAttrChanged();
   }
 
   return NS_OK;
@@ -133,16 +170,27 @@ DateTimeInputTypeBase::GetTimeFromMs(dou
 
   *aHours = value;
 
   return true;
 }
 
 // input type=date
 
+nsresult
+DateInputType::GetBadInputMessage(nsXPIDLString& aMessage)
+{
+  if (!IsInputDateTimeEnabled()) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationInvalidDate", aMessage);
+}
+
 bool
 DateInputType::ConvertStringToNumber(nsAString& aValue,
                                      mozilla::Decimal& aResultValue) const
 {
   uint32_t year, month, day;
   if (!ParseDate(aValue, &year, &month, &day)) {
     return false;
   }
--- a/dom/html/input/DateTimeInputTypes.h
+++ b/dom/html/input/DateTimeInputTypes.h
@@ -15,23 +15,32 @@ public:
   ~DateTimeInputTypeBase() override {}
 
   bool IsValueMissing() const override;
   bool IsRangeOverflow() const override;
   bool IsRangeUnderflow() const override;
   bool HasStepMismatch(bool aUseZeroIfValueNaN) const override;
   bool HasBadInput() const override;
 
+  nsresult GetRangeOverflowMessage(nsXPIDLString& aMessage) override;
+  nsresult GetRangeUnderflowMessage(nsXPIDLString& aMessage) override;
+
   nsresult MinMaxStepAttrChanged() override;
 
 protected:
   explicit DateTimeInputTypeBase(mozilla::dom::HTMLInputElement* aInputElement)
     : InputType(aInputElement)
   {}
 
+  /**
+   * Checks preference "dom.forms.datetime" to determine if input date and time
+   * should be supported.
+   */
+  static bool IsInputDateTimeEnabled();
+
   bool IsMutable() const override;
 
   /**
    * This method converts aValue (milliseconds within a day) to hours, minutes,
    * seconds and milliseconds.
    */
   bool GetTimeFromMs(double aValue, uint16_t* aHours, uint16_t* aMinutes,
                      uint16_t* aSeconds, uint16_t* aMilliseconds) const;
@@ -53,16 +62,22 @@ class DateInputType : public DateTimeInp
 {
 public:
   static InputType*
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) DateInputType(aInputElement);
   }
 
+  // Currently, for input date and time, only date can have an invalid value, as
+  // we forbid or autocorrect values that are not in the valid range for time.
+  // For example, in 12hr format, if user enters '2' in the hour field, it will
+  // be treated as '02' and automatically advance to the next field.
+  nsresult GetBadInputMessage(nsXPIDLString& aMessage) override;
+
   bool ConvertStringToNumber(nsAString& aValue,
                              mozilla::Decimal& aResultValue) const override;
   bool ConvertNumberToString(mozilla::Decimal aValue,
                              nsAString& aResultString) const override;
 
 private:
   explicit DateInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : DateTimeInputTypeBase(aInputElement)
--- a/dom/html/input/FileInputType.cpp
+++ b/dom/html/input/FileInputType.cpp
@@ -16,8 +16,16 @@ FileInputType::IsValueMissing() const
   }
 
   if (!IsMutable()) {
     return false;
   }
 
   return mInputElement->GetFilesOrDirectoriesInternal().IsEmpty();
 }
+
+nsresult
+FileInputType::GetValueMissingMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                            "FormValidationFileMissing",
+                                            aMessage);
+}
--- a/dom/html/input/FileInputType.h
+++ b/dom/html/input/FileInputType.h
@@ -16,15 +16,17 @@ public:
   static InputType*
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) FileInputType(aInputElement);
   }
 
   bool IsValueMissing() const override;
 
+  nsresult GetValueMissingMessage(nsXPIDLString& aMessage) override;
+
 private:
   explicit FileInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : InputType(aInputElement)
   {}
 };
 
 #endif /* FileInputType_h__ */
--- a/dom/html/input/InputType.cpp
+++ b/dom/html/input/InputType.cpp
@@ -11,16 +11,18 @@
 #include "CheckableInputTypes.h"
 #include "ColorInputType.h"
 #include "DateTimeInputTypes.h"
 #include "FileInputType.h"
 #include "HiddenInputType.h"
 #include "NumericInputTypes.h"
 #include "SingleLineTextInputTypes.h"
 
+#include "nsContentUtils.h"
+
 const mozilla::Decimal InputType::kStepAny = mozilla::Decimal(0);
 
 /* static */ mozilla::UniquePtr<InputType, DoNotDelete>
 InputType::Create(mozilla::dom::HTMLInputElement* aInputElement, uint8_t aType,
                   void* aMemory)
 {
   mozilla::UniquePtr<InputType, DoNotDelete> inputType;
   switch(aType) {
@@ -196,16 +198,226 @@ InputType::HasStepMismatch(bool aUseZero
 
 bool
 InputType::HasBadInput() const
 {
   return false;
 }
 
 nsresult
+InputType::GetValidationMessage(nsAString& aValidationMessage,
+                                nsIConstraintValidation::ValidityStateType aType)
+{
+  nsresult rv = NS_OK;
+
+  switch (aType)
+  {
+    case nsIConstraintValidation::VALIDITY_STATE_TOO_LONG:
+    {
+      nsXPIDLString message;
+      int32_t maxLength = mInputElement->MaxLength();
+      int32_t textLength =
+        mInputElement->InputTextLength(mozilla::dom::CallerType::System);
+      nsAutoString strMaxLength;
+      nsAutoString strTextLength;
+
+      strMaxLength.AppendInt(maxLength);
+      strTextLength.AppendInt(textLength);
+
+      const char16_t* params[] = { strMaxLength.get(), strTextLength.get() };
+      rv = nsContentUtils::FormatLocalizedString(
+        nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong",
+        params, message);
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_TOO_SHORT:
+    {
+      nsXPIDLString message;
+      int32_t minLength = mInputElement->MinLength();
+      int32_t textLength =
+        mInputElement->InputTextLength(mozilla::dom::CallerType::System);
+      nsAutoString strMinLength;
+      nsAutoString strTextLength;
+
+      strMinLength.AppendInt(minLength);
+      strTextLength.AppendInt(textLength);
+
+      const char16_t* params[] = { strMinLength.get(), strTextLength.get() };
+      rv = nsContentUtils::FormatLocalizedString(
+        nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooShort",
+        params, message);
+
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING:
+    {
+      nsXPIDLString message;
+      rv = GetValueMissingMessage(message);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_TYPE_MISMATCH:
+    {
+      nsXPIDLString message;
+      rv = GetTypeMismatchMessage(message);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_PATTERN_MISMATCH:
+    {
+      nsXPIDLString message;
+      nsAutoString title;
+      mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
+      if (title.IsEmpty()) {
+        rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+          "FormValidationPatternMismatch", message);
+      } else {
+        if (title.Length() >
+            nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
+          title.Truncate(
+            nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
+        }
+        const char16_t* params[] = { title.get() };
+        rv = nsContentUtils::FormatLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES,
+          "FormValidationPatternMismatchWithTitle", params, message);
+      }
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_RANGE_OVERFLOW:
+    {
+      nsXPIDLString message;
+      rv = GetRangeOverflowMessage(message);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_RANGE_UNDERFLOW:
+    {
+      nsXPIDLString message;
+      rv = GetRangeUnderflowMessage(message);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_STEP_MISMATCH:
+    {
+      nsXPIDLString message;
+
+      mozilla::Decimal value = mInputElement->GetValueAsDecimal();
+      MOZ_ASSERT(!value.isNaN());
+
+      mozilla::Decimal step = mInputElement->GetStep();
+      MOZ_ASSERT(step != kStepAny && step > mozilla::Decimal(0));
+
+      mozilla::Decimal stepBase = mInputElement->GetStepBase();
+
+      mozilla::Decimal valueLow =
+        value - NS_floorModulo(value - stepBase, step);
+      mozilla::Decimal valueHigh =
+        value + step - NS_floorModulo(value - stepBase, step);
+
+      mozilla::Decimal maximum = mInputElement->GetMaximum();
+
+      if (maximum.isNaN() || valueHigh <= maximum) {
+        nsAutoString valueLowStr, valueHighStr;
+        ConvertNumberToString(valueLow, valueLowStr);
+        ConvertNumberToString(valueHigh, valueHighStr);
+
+        if (valueLowStr.Equals(valueHighStr)) {
+          const char16_t* params[] = { valueLowStr.get() };
+          rv = nsContentUtils::FormatLocalizedString(
+            nsContentUtils::eDOM_PROPERTIES,
+            "FormValidationStepMismatchOneValue", params, message);
+        } else {
+          const char16_t* params[] = { valueLowStr.get(), valueHighStr.get() };
+          rv = nsContentUtils::FormatLocalizedString(
+            nsContentUtils::eDOM_PROPERTIES,
+            "FormValidationStepMismatch", params, message);
+        }
+      } else {
+        nsAutoString valueLowStr;
+        ConvertNumberToString(valueLow, valueLowStr);
+
+        const char16_t* params[] = { valueLowStr.get() };
+        rv = nsContentUtils::FormatLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES,
+          "FormValidationStepMismatchOneValue", params, message);
+      }
+
+      aValidationMessage = message;
+      break;
+    }
+    case nsIConstraintValidation::VALIDITY_STATE_BAD_INPUT:
+    {
+      nsXPIDLString message;
+      rv = GetBadInputMessage(message);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      aValidationMessage = message;
+      break;
+    }
+    default:
+      return NS_ERROR_UNEXPECTED;
+  }
+
+  return rv;
+}
+
+nsresult
+InputType::GetValueMissingMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationValueMissing", aMessage);
+}
+
+nsresult
+InputType::GetTypeMismatchMessage(nsXPIDLString& aMessage)
+{
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+InputType::GetRangeOverflowMessage(nsXPIDLString& aMessage)
+{
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+InputType::GetRangeUnderflowMessage(nsXPIDLString& aMessage)
+{
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+InputType::GetBadInputMessage(nsXPIDLString& aMessage)
+{
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
 InputType::MinMaxStepAttrChanged()
 {
   return NS_OK;
 }
 
 bool
 InputType::ConvertStringToNumber(nsAString& aValue,
                                  mozilla::Decimal& aResultValue) const
--- a/dom/html/input/InputType.h
+++ b/dom/html/input/InputType.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef InputType_h__
 #define InputType_h__
 
 #include <stdint.h>
 #include "mozilla/Decimal.h"
 #include "mozilla/UniquePtr.h"
+#include "nsIConstraintValidation.h"
 #include "nsString.h"
 #include "nsError.h"
 
 // This must come outside of any namespace, or else it won't overload with the
 // double based version in nsMathUtils.h
 inline mozilla::Decimal
 NS_floorModulo(mozilla::Decimal x, mozilla::Decimal y)
 {
@@ -55,16 +56,24 @@ public:
   virtual bool IsValueMissing() const;
   virtual bool HasTypeMismatch() const;
   virtual bool HasPatternMismatch() const;
   virtual bool IsRangeOverflow() const;
   virtual bool IsRangeUnderflow() const;
   virtual bool HasStepMismatch(bool aUseZeroIfValueNaN) const;
   virtual bool HasBadInput() const;
 
+  nsresult GetValidationMessage(nsAString& aValidationMessage,
+                                nsIConstraintValidation::ValidityStateType aType);
+  virtual nsresult GetValueMissingMessage(nsXPIDLString& aMessage);
+  virtual nsresult GetTypeMismatchMessage(nsXPIDLString& aMessage);
+  virtual nsresult GetRangeOverflowMessage(nsXPIDLString& aMessage);
+  virtual nsresult GetRangeUnderflowMessage(nsXPIDLString& aMessage);
+  virtual nsresult GetBadInputMessage(nsXPIDLString& aMessage);
+
   virtual nsresult MinMaxStepAttrChanged();
 
   /**
    * Convert a string to a Decimal number in a type specific way,
    * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#concept-input-value-string-number
    * ie parse a date string to a timestamp if type=date,
    * or parse a number string to its value if type=number.
    * @param aValue the string to be parsed.
--- a/dom/html/input/NumericInputTypes.cpp
+++ b/dom/html/input/NumericInputTypes.cpp
@@ -6,23 +6,16 @@
 
 #include "NumericInputTypes.h"
 
 #include "mozilla/dom/HTMLInputElement.h"
 #include "nsNumberControlFrame.h"
 #include "nsTextEditorState.h"
 
 bool
-NumberInputType::IsMutable() const
-{
-  return !mInputElement->IsDisabled() &&
-         !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
-}
-
-bool
 NumericInputTypeBase::IsRangeOverflow() const
 {
   mozilla::Decimal maximum = mInputElement->GetMaximum();
   if (maximum.isNaN()) {
     return false;
   }
 
   mozilla::Decimal value = mInputElement->GetValueAsDecimal();
@@ -66,16 +59,53 @@ NumericInputTypeBase::HasStepMismatch(bo
   if (step == kStepAny) {
     return false;
   }
 
   // Value has to be an integral multiple of step.
   return NS_floorModulo(value - GetStepBase(), step) != mozilla::Decimal(0);
 }
 
+nsresult
+NumericInputTypeBase::GetRangeOverflowMessage(nsXPIDLString& aMessage)
+{
+  // We want to show the value as parsed when it's a number
+  mozilla::Decimal maximum = mInputElement->GetMaximum();
+  MOZ_ASSERT(!maximum.isNaN());
+
+  nsAutoString maxStr;
+  char buf[32];
+  mozilla::DebugOnly<bool> ok = maximum.toString(buf,
+                                                 mozilla::ArrayLength(buf));
+  maxStr.AssignASCII(buf);
+  MOZ_ASSERT(ok, "buf not big enough");
+
+  const char16_t* params[] = { maxStr.get() };
+  return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationNumberRangeOverflow", params, aMessage);
+}
+
+nsresult
+NumericInputTypeBase::GetRangeUnderflowMessage(nsXPIDLString& aMessage)
+{
+  mozilla::Decimal minimum = mInputElement->GetMinimum();
+  MOZ_ASSERT(!minimum.isNaN());
+
+  nsAutoString minStr;
+  char buf[32];
+  mozilla::DebugOnly<bool> ok = minimum.toString(buf,
+                                                 mozilla::ArrayLength(buf));
+  minStr.AssignASCII(buf);
+  MOZ_ASSERT(ok, "buf not big enough");
+
+  const char16_t* params[] = { minStr.get() };
+  return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationNumberRangeUnderflow", params, aMessage);
+}
+
 bool
 NumericInputTypeBase::ConvertStringToNumber(nsAString& aValue,
   mozilla::Decimal& aResultValue) const
 {
   aResultValue = mozilla::dom::HTMLInputElement::StringToDecimal(aValue);
   if (!aResultValue.isFinite()) {
     return false;
   }
@@ -131,16 +161,37 @@ NumberInputType::HasBadInput() const
   if (numberControlFrame &&
       !numberControlFrame->AnonTextControlIsEmpty()) {
     // The input the user entered failed to parse as a number.
     return true;
   }
   return false;
 }
 
+nsresult
+NumberInputType::GetValueMissingMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationBadInputNumber", aMessage);
+}
+
+nsresult
+NumberInputType::GetBadInputMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+    "FormValidationBadInputNumber", aMessage);
+}
+
+bool
+NumberInputType::IsMutable() const
+{
+  return !mInputElement->IsDisabled() &&
+         !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
+}
+
 /* input type=range */
 nsresult
 RangeInputType::MinMaxStepAttrChanged()
 {
   // The value may need to change when @min/max/step changes since the value may
   // have been invalid and can now change to a valid value, or vice versa. For
   // example, consider: <input type=range value=-1 max=1 step=3>. The valid
   // range is 0 to 1 while the nearest valid steps are -1 and 2 (the max value
--- a/dom/html/input/NumericInputTypes.h
+++ b/dom/html/input/NumericInputTypes.h
@@ -13,16 +13,19 @@ class NumericInputTypeBase : public ::In
 {
 public:
   ~NumericInputTypeBase() override {}
 
   bool IsRangeOverflow() const override;
   bool IsRangeUnderflow() const override;
   bool HasStepMismatch(bool aUseZeroIfValueNaN) const override;
 
+  nsresult GetRangeOverflowMessage(nsXPIDLString& aMessage) override;
+  nsresult GetRangeUnderflowMessage(nsXPIDLString& aMessage) override;
+
   bool ConvertStringToNumber(nsAString& aValue,
                              mozilla::Decimal& aResultValue) const override;
   bool ConvertNumberToString(mozilla::Decimal aValue,
                              nsAString& aResultString) const override;
 
 protected:
   explicit NumericInputTypeBase(mozilla::dom::HTMLInputElement* aInputElement)
     : InputType(aInputElement)
@@ -37,22 +40,26 @@ public:
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) NumberInputType(aInputElement);
   }
 
   bool IsValueMissing() const override;
   bool HasBadInput() const override;
 
+  nsresult GetValueMissingMessage(nsXPIDLString& aMessage) override;
+  nsresult GetBadInputMessage(nsXPIDLString& aMessage) override;
+
+protected:
+  bool IsMutable() const override;
+
 private:
   explicit NumberInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : NumericInputTypeBase(aInputElement)
   {}
-
-  bool IsMutable() const override;
 };
 
 // input type=range
 class RangeInputType : public NumericInputTypeBase
 {
 public:
   static InputType*
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
--- a/dom/html/input/SingleLineTextInputTypes.cpp
+++ b/dom/html/input/SingleLineTextInputTypes.cpp
@@ -115,16 +115,24 @@ URLInputType::HasTypeMismatch() const
   nsCOMPtr<nsIIOService> ioService = do_GetIOService();
   nsCOMPtr<nsIURI> uri;
 
   return !NS_SUCCEEDED(ioService->NewURI(NS_ConvertUTF16toUTF8(value), nullptr,
                                          nullptr, getter_AddRefs(uri)));
 
 }
 
+nsresult
+URLInputType::GetTypeMismatchMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                            "FormValidationInvalidURL",
+                                            aMessage);
+}
+
 /* input type=email */
 
 bool
 EmailInputType::HasTypeMismatch() const
 {
   nsAutoString value;
   GetNonFileValueInternal(value);
 
@@ -151,16 +159,32 @@ EmailInputType::HasBadInput() const
   while (tokenizer.hasMoreTokens()) {
     if (!PunycodeEncodeEmailAddress(tokenizer.nextToken(), unused, &unused2)) {
       return true;
     }
   }
   return false;
 }
 
+nsresult
+EmailInputType::GetTypeMismatchMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                            "FormValidationInvalidEmail",
+                                            aMessage);
+}
+
+nsresult
+EmailInputType::GetBadInputMessage(nsXPIDLString& aMessage)
+{
+  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                            "FormValidationInvalidEmail",
+                                            aMessage);
+}
+
 /* static */ bool
 EmailInputType::IsValidEmailAddressList(const nsAString& aValue)
 {
   HTMLSplitOnSpacesTokenizer tokenizer(aValue, ',');
 
   while (tokenizer.hasMoreTokens()) {
     if (!IsValidEmailAddress(tokenizer.nextToken())) {
       return false;
--- a/dom/html/input/SingleLineTextInputTypes.h
+++ b/dom/html/input/SingleLineTextInputTypes.h
@@ -83,16 +83,18 @@ public:
   static InputType*
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) URLInputType(aInputElement);
   }
 
   bool HasTypeMismatch() const override;
 
+  nsresult GetTypeMismatchMessage(nsXPIDLString& aMessage) override;
+
 private:
   explicit URLInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : SingleLineTextInputTypeBase(aInputElement)
   {}
 };
 
 // input type=email
 class EmailInputType : public SingleLineTextInputTypeBase
@@ -102,16 +104,19 @@ public:
   Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
   {
     return new (aMemory) EmailInputType(aInputElement);
   }
 
   bool HasTypeMismatch() const override;
   bool HasBadInput() const override;
 
+  nsresult GetTypeMismatchMessage(nsXPIDLString& aMessage) override;
+  nsresult GetBadInputMessage(nsXPIDLString& aMessage) override;
+
 private:
   explicit EmailInputType(mozilla::dom::HTMLInputElement* aInputElement)
     : SingleLineTextInputTypeBase(aInputElement)
   {}
 
   /**
    * This helper method returns true if aValue is a valid email address.
    * This is following the HTML5 specification:
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -598,16 +598,18 @@ static const char* sObserverTopics[] = {
 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::PreallocateProcess()
 {
   RefPtr<ContentParent> process =
     new ContentParent(/* aOpener = */ nullptr,
                       NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
 
+  PreallocatedProcessManager::AddBlocker(process);
+
   if (!process->LaunchSubprocess(PROCESS_PRIORITY_PREALLOC)) {
     return nullptr;
   }
 
   process->Init();
   return process.forget();
 }
 
@@ -875,16 +877,19 @@ ContentParent::GetNewOrUsedBrowserProces
       p->mActivateTS = TimeStamp::Now();
       return p.forget();
     }
   }
 
   // Create a new process from scratch.
   RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType);
 
+  // Until the new process is ready let's not allow to start up any preallocated processes.
+  PreallocatedProcessManager::AddBlocker(p);
+
   if (!p->LaunchSubprocess(aPriority)) {
     return nullptr;
   }
 
   p->Init();
 
   contentParents.AppendElement(p);
   p->mActivateTS = TimeStamp::Now();
@@ -2721,20 +2726,19 @@ ContentParent::RecvGetShowPasswordSettin
 #endif
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvFirstIdle()
 {
   // When the ContentChild goes idle, it sends us a FirstIdle message
-  // which we use as a good time to prelaunch another process. If we
-  // prelaunch any sooner than this, then we'll be competing with the
-  // child process and slowing it down.
-  PreallocatedProcessManager::AllocateAfterDelay();
+  // which we use as a good time to signal the PreallocatedProcessManager
+  // that it can start allocating processes from now on.
+  PreallocatedProcessManager::RemoveBlocker(this);
   return IPC_OK();
 }
 
 // We want ContentParent to show up in CC logs for debugging purposes, but we
 // don't actually cycle collect it.
 NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
--- a/dom/ipc/PreallocatedProcessManager.cpp
+++ b/dom/ipc/PreallocatedProcessManager.cpp
@@ -34,65 +34,61 @@ class PreallocatedProcessManagerImpl fin
 {
 public:
   static PreallocatedProcessManagerImpl* Singleton();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // See comments on PreallocatedProcessManager for these methods.
-  void AllocateAfterDelay();
-  void AllocateOnIdle();
-  void AllocateNow();
+  void AddBlocker(ContentParent* aParent);
+  void RemoveBlocker(ContentParent* aParent);
   already_AddRefed<ContentParent> Take();
   bool Provide(ContentParent* aParent);
 
 private:
   static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
 
   PreallocatedProcessManagerImpl();
   ~PreallocatedProcessManagerImpl() {}
   DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManagerImpl);
 
   void Init();
 
+  bool CanAllocate();
+  void AllocateAfterDelay();
+  void AllocateOnIdle();
+  void AllocateNow();
+
   void RereadPrefs();
   void Enable();
   void Disable();
   void CloseProcess();
 
   void ObserveProcessShutdown(nsISupports* aSubject);
 
   bool mEnabled;
   bool mShutdown;
   RefPtr<ContentParent> mPreallocatedProcess;
+  nsTHashtable<nsUint64HashKey> mBlockers;
 };
 
 /* static */ StaticRefPtr<PreallocatedProcessManagerImpl>
 PreallocatedProcessManagerImpl::sSingleton;
 
 /* static */ PreallocatedProcessManagerImpl*
 PreallocatedProcessManagerImpl::Singleton()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!sSingleton) {
     sSingleton = new PreallocatedProcessManagerImpl();
     sSingleton->Init();
     ClearOnShutdown(&sSingleton);
   }
 
-  // First time when we init sSingleton, the pref database might not be in a
-  // reliable state (we are too early), so despite dom.ipc.processPrelaunch.enabled
-  // is set to true Preferences::GetBool will return false (it cannot find the pref).
-  // Since Init() above will be called only once, and the pref will not be changed,
-  // the manger will stay disabled. To prevent that let's re-read the pref each time
-  // someone accessing the manager singleton. This is a hack but this is not a hot code
-  // so it should be fine.
-  sSingleton->RereadPrefs();
-
   return sSingleton;
 }
 
 NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver)
 
 PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
   : mEnabled(false)
   , mShutdown(false)
@@ -163,16 +159,21 @@ PreallocatedProcessManagerImpl::RereadPr
 
 already_AddRefed<ContentParent>
 PreallocatedProcessManagerImpl::Take()
 {
   if (!mEnabled || mShutdown) {
     return nullptr;
   }
 
+  if (mPreallocatedProcess) {
+    // The preallocated process is taken. Let's try to start up a new one soon.
+    AllocateOnIdle();
+  }
+
   return mPreallocatedProcess.forget();
 }
 
 bool
 PreallocatedProcessManagerImpl::Provide(ContentParent* aParent)
 {
   if (mEnabled && !mShutdown && !mPreallocatedProcess) {
     mPreallocatedProcess = aParent;
@@ -191,51 +192,80 @@ PreallocatedProcessManagerImpl::Enable()
     return;
   }
 
   mEnabled = true;
   AllocateAfterDelay();
 }
 
 void
+PreallocatedProcessManagerImpl::AddBlocker(ContentParent* aParent)
+{
+  uint64_t childID = aParent->ChildID();
+  MOZ_ASSERT(!mBlockers.Contains(childID));
+  mBlockers.PutEntry(childID);
+}
+
+void
+PreallocatedProcessManagerImpl::RemoveBlocker(ContentParent* aParent)
+{
+  uint64_t childID = aParent->ChildID();
+  MOZ_ASSERT(mBlockers.Contains(childID));
+  mBlockers.RemoveEntry(childID);
+  if (!mPreallocatedProcess && mBlockers.IsEmpty()) {
+    AllocateAfterDelay();
+  }
+}
+
+bool
+PreallocatedProcessManagerImpl::CanAllocate()
+{
+  return mEnabled &&
+         mBlockers.IsEmpty() &&
+         !mPreallocatedProcess &&
+         !mShutdown &&
+         !ContentParent::IsMaxProcessCountReached(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
+}
+
+void
 PreallocatedProcessManagerImpl::AllocateAfterDelay()
 {
-  if (!mEnabled || mPreallocatedProcess || mShutdown) {
+  if (!mEnabled) {
     return;
   }
 
-  // Originally AllocateOnIdle() was post here, but since the gecko parent
-  // message loop in practice never goes idle, that didn't work out well.
-  // Let's just launch the process after the delay.
   NS_DelayedDispatchToCurrentThread(
-    NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateNow",
+    NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateOnIdle",
                       this,
-                      &PreallocatedProcessManagerImpl::AllocateNow),
+                      &PreallocatedProcessManagerImpl::AllocateOnIdle),
     Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
                          DEFAULT_ALLOCATE_DELAY));
 }
 
 void
 PreallocatedProcessManagerImpl::AllocateOnIdle()
 {
-  if (!mEnabled || mPreallocatedProcess || mShutdown) {
+  if (!mEnabled) {
     return;
   }
 
   NS_IdleDispatchToCurrentThread(
     NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateNow",
                       this,
                       &PreallocatedProcessManagerImpl::AllocateNow));
 }
 
 void
 PreallocatedProcessManagerImpl::AllocateNow()
 {
-  if (!mEnabled || mPreallocatedProcess || mShutdown ||
-      ContentParent::IsMaxProcessCountReached(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE))) {
+  if (!CanAllocate()) {
+    if (mEnabled && !mShutdown && !mPreallocatedProcess && !mBlockers.IsEmpty()) {
+      // If it's too early to allocate a process let's retry later.
+      AllocateAfterDelay();
+    }
     return;
   }
 
   mPreallocatedProcess = ContentParent::PreallocateProcess();
 }
 
 void
 PreallocatedProcessManagerImpl::Disable()
@@ -255,53 +285,45 @@ PreallocatedProcessManagerImpl::ClosePro
     mPreallocatedProcess->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE);
     mPreallocatedProcess = nullptr;
   }
 }
 
 void
 PreallocatedProcessManagerImpl::ObserveProcessShutdown(nsISupports* aSubject)
 {
-  if (!mPreallocatedProcess) {
-    return;
-  }
-
   nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
   NS_ENSURE_TRUE_VOID(props);
 
   uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
   props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
   NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
 
-  if (childID == mPreallocatedProcess->ChildID()) {
+  if (mPreallocatedProcess && childID == mPreallocatedProcess->ChildID()) {
     mPreallocatedProcess = nullptr;
   }
+
+  mBlockers.RemoveEntry(childID);
 }
 
 inline PreallocatedProcessManagerImpl* GetPPMImpl()
 {
   return PreallocatedProcessManagerImpl::Singleton();
 }
 
 /* static */ void
-PreallocatedProcessManager::AllocateAfterDelay()
+PreallocatedProcessManager::AddBlocker(ContentParent* aParent)
 {
-  GetPPMImpl()->AllocateAfterDelay();
+  GetPPMImpl()->AddBlocker(aParent);
 }
 
 /* static */ void
-PreallocatedProcessManager::AllocateOnIdle()
+PreallocatedProcessManager::RemoveBlocker(ContentParent* aParent)
 {
-  GetPPMImpl()->AllocateOnIdle();
-}
-
-/* static */ void
-PreallocatedProcessManager::AllocateNow()
-{
-  GetPPMImpl()->AllocateNow();
+  GetPPMImpl()->RemoveBlocker(aParent);
 }
 
 /* static */ already_AddRefed<ContentParent>
 PreallocatedProcessManager::Take()
 {
   return GetPPMImpl()->Take();
 }
 
--- a/dom/ipc/PreallocatedProcessManager.h
+++ b/dom/ipc/PreallocatedProcessManager.h
@@ -28,41 +28,24 @@ class ContentParent;
  * We don't expect this pref to flip between true and false in production, but
  * flipping the pref is important for tests.
  */
 class PreallocatedProcessManager final
 {
   typedef mozilla::dom::ContentParent ContentParent;
 
 public:
-  /**
-   * Create a process after a delay.  We wait for a period of time (specified
-   * by the dom.ipc.processPrelaunch.delayMs pref), then wait for this process
-   * to go idle, then allocate the new process.
-   *
-   * If the dom.ipc.processPrelaunch.enabled pref is false, or if we already
-   * have a preallocated process, this function does nothing.
-   */
-  static void AllocateAfterDelay();
 
   /**
-   * Create a process once this process goes idle.
-   *
-   * If the dom.ipc.processPrelaunch.enabled pref is false, or if we already
-   * have a preallocated process, this function does nothing.
+   * Before first paint we don't want to allocate any processes in the background.
+   * To avoid that, the PreallocatedProcessManager won't start up any processes while
+   * there is a blocker active.
    */
-  static void AllocateOnIdle();
-
-  /**
-   * Create a process right now.
-   *
-   * If the dom.ipc.processPrelaunch.enabled pref is false, or if we already
-   * have a preallocated process, this function does nothing.
-   */
-  static void AllocateNow();
+  static void AddBlocker(ContentParent* aParent);
+  static void RemoveBlocker(ContentParent* aParent);
 
   /**
    * Take the preallocated process, if we have one.  If we don't have one, this
    * returns null.
    *
    * If you call Take() twice in a row, the second call is guaranteed to return
    * null.
    *
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -34,26 +34,22 @@ FormValidationSelectMissing=Please selec
 FormValidationInvalidEmail=Please enter an email address.
 FormValidationInvalidURL=Please enter a URL.
 FormValidationInvalidDate =Please enter a valid date.
 FormValidationPatternMismatch=Please match the requested format.
 # LOCALIZATION NOTE (FormValidationPatternMismatchWithTitle): %S is the (possibly truncated) title attribute value.
 FormValidationPatternMismatchWithTitle=Please match the requested format: %S.
 # LOCALIZATION NOTE (FormValidationNumberRangeOverflow): %S is a number.
 FormValidationNumberRangeOverflow=Please select a value that is no more than %S.
-# LOCALIZATION NOTE (FormValidationDateRangeOverflow): %S is a date.
-FormValidationDateRangeOverflow=Please select a value that is no later than %S.
-# LOCALIZATION NOTE (FormValidationTimeRangeOverflow): %S is a time.
-FormValidationTimeRangeOverflow=Please select a value that is no later than %S.
+# LOCALIZATION NOTE (FormValidationDateRangeOverflow): %S is a date or time.
+FormValidationDateTimeRangeOverflow=Please select a value that is no later than %S.
 # LOCALIZATION NOTE (FormValidationNumberRangeUnderflow): %S is a number.
 FormValidationNumberRangeUnderflow=Please select a value that is no less than %S.
-# LOCALIZATION NOTE (FormValidationDateRangeUnderflow): %S is a date.
-FormValidationDateRangeUnderflow=Please select a value that is no earlier than %S.
-# LOCALIZATION NOTE (FormValidationTimeRangeUnderflow): %S is a time.
-FormValidationTimeRangeUnderflow=Please select a value that is no earlier than %S.
+# LOCALIZATION NOTE (FormValidationDateRangeUnderflow): %S is a date or time.
+FormValidationDateTimeRangeUnderflow=Please select a value that is no earlier than %S.
 # LOCALIZATION NOTE (FormValidationStepMismatch): both %S can be a number, a date or a time.
 FormValidationStepMismatch=Please select a valid value. The two nearest valid values are %S and %S.
 # LOCALIZATION NOTE (FormValidationStepMismatchOneValue): %S can be a number, a date or a time. This is called instead of FormValidationStepMismatch when the second value is the same as the first.
 FormValidationStepMismatchOneValue=Please select a valid value. The nearest valid value is %S.
 FormValidationBadInputNumber=Please enter a number.
 GetAttributeNodeWarning=Use of getAttributeNode() is deprecated. Use getAttribute() instead.
 SetAttributeNodeWarning=Use of setAttributeNode() is deprecated. Use setAttribute() instead.
 GetAttributeNodeNSWarning=Use of getAttributeNodeNS() is deprecated. Use getAttributeNS() instead.
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -454,16 +454,24 @@ public:
   void NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack) override
   {
     LOG(LogLevel::Warning, ("Session.NotifyTrackAdded %p Raising error due to track set change", this));
     DoSessionEndTask(NS_ERROR_ABORT);
   }
 
   void NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack) override
   {
+    // Handle possible early removal of direct video listener
+    if (mEncoder) {
+      RefPtr<VideoStreamTrack> videoTrack = aTrack->AsVideoStreamTrack();
+      if (videoTrack) {
+        videoTrack->RemoveDirectListener(mEncoder->GetVideoSink());
+      }
+    }
+
     RefPtr<MediaInputPort> foundInputPort;
     for (RefPtr<MediaInputPort> inputPort : mInputPorts) {
       if (aTrack->IsForwardedThrough(inputPort)) {
         foundInputPort = inputPort;
         break;
       }
     }
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -6,17 +6,16 @@
 #include "nsPluginTags.h"
 
 #include "prlink.h"
 #include "plstr.h"
 #include "nsIPluginInstanceOwner.h"
 #include "nsPluginsDir.h"
 #include "nsPluginHost.h"
 #include "nsIBlocklistService.h"
-#include "nsIPlatformCharset.h"
 #include "nsPluginLogging.h"
 #include "nsNPAPIPlugin.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 #include "nsNetUtil.h"
 #include <cctype>
 #include "mozilla/Encoding.h"
--- a/dom/security/test/sri/iframe_style_crossdomain.html
+++ b/dom/security/test/sri/iframe_style_crossdomain.html
@@ -40,21 +40,21 @@
 
     function good_incorrectHashBlocked() {
       ok(true, "A non-CORS cross-domain stylesheet with incorrect hash was correctly blocked.");
     }
     function bad_incorrectHashLoaded() {
       ok(false, "We should load non-CORS cross-domain stylesheets with incorrect hashes!");
     }
 
-    function good_correctDataBlocked() {
-      ok(true, "We should block CORS cross-domain stylesheets in data: URI!");
+    function bad_correctDataBlocked() {
+      ok(false, "We should not block non-CORS cross-domain stylesheets in data: URI!");
     }
-    function bad_correctDataLoaded() {
-      ok(false, "A CORS cross-domain stylesheet with data: URI was correctly loaded.");
+    function good_correctDataLoaded() {
+      ok(true, "A non-CORS cross-domain stylesheet with data: URI was correctly loaded.");
     }
     function bad_correctDataCORSBlocked() {
       ok(false, "We should not block CORS stylesheets in data: URI!");
     }
     function good_correctDataCORSLoaded() {
       ok(true, "A CORS stylesheet with data: URI was correctly loaded.");
     }
 
@@ -80,28 +80,21 @@
         onload="bad_correctHashLoaded()">
 
   <!-- invalid non-CORS sha256 hash -->
   <link rel="stylesheet" href="style_301.css?again"
         integrity="sha256-bogus"
         onerror="good_incorrectHashBlocked()"
         onload="bad_incorrectHashLoaded()">
 
-  <!-- valid CORS sha256 hash in a data: URL, but didn't specify crossorigin -->
+  <!-- valid non-CORS sha256 hash in a data: URL -->
   <link rel="stylesheet" href="data:text/css,.green-text{color:rgb(0, 255, 0)}"
         integrity="sha256-EhVtGGyovvffvYdhyqJxUJ/ekam7zlxxo46iM13cwP0="
-        onerror="good_correctDataBlocked()"
-        onload="bad_correctDataLoaded()">
-
-  <!-- valid CORS sha256 hash in a data: URL -->
-  <link rel="stylesheet" href="data:text/css,.green-text{color:rgb(0, 255, 0)}"
-        integrity="sha256-EhVtGGyovvffvYdhyqJxUJ/ekam7zlxxo46iM13cwP0="
-        crossorigin="anonymous"
-        onerror="bad_correctDataCORSBlocked()"
-        onload="good_correctDataCORSLoaded()">
+        onerror="bad_correctDataBlocked()"
+        onload="good_correctDataLoaded()">
 
   <!-- valid CORS sha256 hash in a data: URL -->
   <link rel="stylesheet" href="data:text/css,.blue-text{color:rgb(0, 0, 255)}"
         crossorigin="anonymous"
         integrity="sha256-m0Fs2hNSyPOn1030Dp+c8pJFHNmwpeTbB+8J/DcqLss="
         onerror="bad_correctDataCORSBlocked()"
         onload="good_correctDataCORSLoaded()">
 
deleted file mode 100644
--- a/dom/security/test/sri/iframe_style_crossdomain_legacy.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE HTML>
-<!-- Any copyright is dedicated to the Public Domain.
-     http://creativecommons.org/publicdomain/zero/1.0/ -->
-<html>
-<head>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-    function check_styles() {
-      var redText = document.getElementById('red-text');
-      var greenText = document.getElementById('green-text');
-      var blueText = document.getElementById('blue-text');
-      var redTextColor = window.getComputedStyle(redText).getPropertyValue('color');
-      var greenTextColor = window.getComputedStyle(greenText).getPropertyValue('color');
-      var blueTextColor = window.getComputedStyle(blueText).getPropertyValue('color');
-      ok(redTextColor == 'rgb(255, 0, 0)', "The first part should be red.");
-      ok(greenTextColor == 'rgb(0, 255, 0)', "The second part should be green.");
-      ok(blueTextColor == 'rgb(0, 0, 255)', "The third part should be blue.");
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    window.onload = function() {
-      check_styles();
-      SimpleTest.finish();
-    }
-  </script>
-  <script>
-    function good_correctHashCORSLoaded() {
-      ok(true, "A CORS cross-domain stylesheet with correct hash was correctly loaded.");
-    }
-    function bad_correctHashCORSBlocked() {
-      ok(false, "We should load CORS cross-domain stylesheets with hashes that match!");
-    }
-    function good_correctHashBlocked() {
-      ok(true, "A non-CORS cross-domain stylesheet with correct hash was correctly blocked.");
-    }
-    function bad_correctHashLoaded() {
-      ok(false, "We should block non-CORS cross-domain stylesheets with hashes that match!");
-    }
-
-    function good_incorrectHashBlocked() {
-      ok(true, "A non-CORS cross-domain stylesheet with incorrect hash was correctly blocked.");
-    }
-    function bad_incorrectHashLoaded() {
-      ok(false, "We should load non-CORS cross-domain stylesheets with incorrect hashes!");
-    }
-
-    function bad_correctDataBlocked() {
-      ok(false, "We should not block non-CORS cross-domain stylesheets in data: URI!");
-    }
-    function good_correctDataLoaded() {
-      ok(true, "A non-CORS cross-domain stylesheet with data: URI was correctly loaded.");
-    }
-    function bad_correctDataCORSBlocked() {
-      ok(false, "We should not block CORS stylesheets in data: URI!");
-    }
-    function good_correctDataCORSLoaded() {
-      ok(true, "A CORS stylesheet with data: URI was correctly loaded.");
-    }
-
-    function good_correctHashOpaqueBlocked() {
-      ok(true, "A non-CORS(Opaque) cross-domain stylesheet with correct hash was correctly blocked.");
-    }
-    function bad_correctHashOpaqueLoaded() {
-      ok(false, "We should not load non-CORS(Opaque) cross-domain stylesheets with correct hashes!");
-    }
-  </script>
-
-  <!-- valid CORS sha256 hash -->
-  <link rel="stylesheet" href="http://example.com/tests/dom/security/test/sri/style1.css"
-        crossorigin="anonymous"
-        integrity="sha256-qs8lnkunWoVldk5d5E+652yth4VTSHohlBKQvvgGwa8="
-        onerror="bad_correctHashCORSBlocked()"
-        onload="good_correctHashCORSLoaded()">
-
-  <!-- valid non-CORS sha256 hash -->
-  <link rel="stylesheet" href="style_301.css"
-        integrity="sha256-qs8lnkunWoVldk5d5E+652yth4VTSHohlBKQvvgGwa8="
-        onerror="good_correctHashBlocked()"
-        onload="bad_correctHashLoaded()">
-
-  <!-- invalid non-CORS sha256 hash -->
-  <link rel="stylesheet" href="style_301.css?again"
-        integrity="sha256-bogus"
-        onerror="good_incorrectHashBlocked()"
-        onload="bad_incorrectHashLoaded()">
-
-  <!-- valid non-CORS sha256 hash in a data: URL -->
-  <link rel="stylesheet" href="data:text/css,.green-text{color:rgb(0, 255, 0)}"
-        integrity="sha256-EhVtGGyovvffvYdhyqJxUJ/ekam7zlxxo46iM13cwP0="
-        onerror="bad_correctDataBlocked()"
-        onload="good_correctDataLoaded()">
-
-  <!-- valid CORS sha256 hash in a data: URL -->
-  <link rel="stylesheet" href="data:text/css,.blue-text{color:rgb(0, 0, 255)}"
-        crossorigin="anonymous"
-        integrity="sha256-m0Fs2hNSyPOn1030Dp+c8pJFHNmwpeTbB+8J/DcqLss="
-        onerror="bad_correctDataCORSBlocked()"
-        onload="good_correctDataCORSLoaded()">
-
-  <!-- valid non-CORS sha256 hash -->
-  <link rel="stylesheet" href="http://example.com/tests/dom/security/test/sri/style1.css"
-        integrity="sha256-qs8lnkunWoVldk5d5E+652yth4VTSHohlBKQvvgGwa8="
-        onerror="good_correctHashOpaqueBlocked()"
-        onload="bad_correctHashOpaqueLoaded()">
-</head>
-<body>
-<p><span id="red-text">This should be red</span> but
-  <span id="green-text" class="green-text">this should be green</span> and
-  <span id="blue-text" class="blue-text">this should be blue</span></p>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
--- a/dom/security/test/sri/mochitest.ini
+++ b/dom/security/test/sri/mochitest.ini
@@ -5,17 +5,16 @@ support-files =
   iframe_csp_directive_style_imports.html^headers^
   iframe_require-sri-for_main.html
   iframe_require-sri-for_main.html^headers^
   iframe_require-sri-for_no_csp.html
   iframe_script_crossdomain.html
   iframe_script_sameorigin.html
   iframe_sri_disabled.html
   iframe_style_crossdomain.html
-  iframe_style_crossdomain_legacy.html
   iframe_style_sameorigin.html
   rsf_csp_worker.js
   rsf_csp_worker.js^headers^
   rsf_imported.js
   rsf_worker.js
   script_crossdomain1.js
   script_crossdomain1.js^headers^
   script_crossdomain2.js
@@ -46,15 +45,14 @@ support-files =
   style_301.css^headers^
   style_importing.css
   style_imported.css
 
 [test_script_sameorigin.html]
 [test_script_crossdomain.html]
 [test_sri_disabled.html]
 [test_style_crossdomain.html]
-[test_style_crossdomain_legacy.html]
 [test_style_sameorigin.html]
 [test_require-sri-for_csp_directive.html]
 [test_require-sri-for_csp_directive_disabled.html]
 [test_bug_1271796.html]
 [test_csp_directive_style_imports.html]
 [test_bug_1364262.html]
--- a/dom/security/test/sri/test_style_crossdomain.html
+++ b/dom/security/test/sri/test_style_crossdomain.html
@@ -2,18 +2,16 @@
 <!-- Any copyright is dedicated to the Public Domain.
      http://creativecommons.org/publicdomain/zero/1.0/ -->
 <html>
 <head>
   <meta charset="utf-8">
   <title>Cross-domain stylesheet tests for Bug 1196740</title>
   <script>
     SpecialPowers.setBoolPref("security.sri.enable", true);
-    // TODO: Bug 1324406: Treat 'data:' documents as unique, opaque origins
-    SpecialPowers.setBoolPref("security.data_uri.unique_opaque_origin", true);
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196740">Mozilla Bug 1196740</a>
 <div>
   <iframe src="iframe_style_crossdomain.html" height="100%" width="90%" frameborder="0"></iframe>
 </div>
 </body>
deleted file mode 100644
--- a/dom/security/test/sri/test_style_crossdomain_legacy.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE HTML>
-<!-- Any copyright is dedicated to the Public Domain.
-     http://creativecommons.org/publicdomain/zero/1.0/ -->
-<html>
-<head>
-  <meta charset="utf-8">
-  <title>Cross-domain stylesheet tests for Bug 1196740</title>
-  <script>
-    SpecialPowers.setBoolPref("security.sri.enable", true);
-    // TODO: Bug 1324406: Treat 'data:' documents as unique, opaque origins
-    SpecialPowers.setBoolPref("security.data_uri.unique_opaque_origin", false);
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196740">Mozilla Bug 1196740</a>
-<div>
-  <iframe src="iframe_style_crossdomain_legacy.html" height="100%" width="90%" frameborder="0"></iframe>
-</div>
-</body>
-</html>
--- a/dom/webauthn/U2FHIDTokenManager.cpp
+++ b/dom/webauthn/U2FHIDTokenManager.cpp
@@ -31,23 +31,22 @@ U2FHIDTokenManager::~U2FHIDTokenManager(
 // Bytes  Value
 // 1      0x05
 // 65     public key
 // 1      key handle length
 // *      key handle
 // ASN.1  attestation certificate
 // *      attestation signature
 //
-RefPtr<ResultPromise>
+RefPtr<U2FRegisterPromise>
 U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                              const nsTArray<uint8_t>& aApplication,
-                             const nsTArray<uint8_t>& aChallenge,
-                             /* out */ nsTArray<uint8_t>& aRegistration)
+                             const nsTArray<uint8_t>& aChallenge)
 {
-  return ResultPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
+  return U2FRegisterPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
 }
 
 // A U2F Sign operation creates a signature over the "param" arguments (plus
 // some other stuff) using the private key indicated in the key handle argument.
 //
 // The format of the signed data is as follows:
 //
 //  32    Application parameter
@@ -56,24 +55,22 @@ U2FHIDTokenManager::Register(const nsTAr
 //  32    Challenge parameter
 //
 // The format of the signature data is as follows:
 //
 //  1     User presence
 //  4     Counter
 //  *     Signature
 //
-RefPtr<ResultPromise>
+RefPtr<U2FSignPromise>
 U2FHIDTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                          const nsTArray<uint8_t>& aApplication,
-                         const nsTArray<uint8_t>& aChallenge,
-                         /* out */ nsTArray<uint8_t>& aKeyHandle,
-                         /* out */ nsTArray<uint8_t>& aSignature)
+                         const nsTArray<uint8_t>& aChallenge)
 {
-  return ResultPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
+  return U2FSignPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
 }
 
 void
 U2FHIDTokenManager::Cancel()
 {
 }
 
 }
--- a/dom/webauthn/U2FHIDTokenManager.h
+++ b/dom/webauthn/U2FHIDTokenManager.h
@@ -17,28 +17,25 @@
 namespace mozilla {
 namespace dom {
 
 class U2FHIDTokenManager final : public U2FTokenTransport
 {
 public:
   explicit U2FHIDTokenManager();
 
-  virtual RefPtr<ResultPromise>
+  virtual RefPtr<U2FRegisterPromise>
   Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
            const nsTArray<uint8_t>& aApplication,
-           const nsTArray<uint8_t>& aChallenge,
-           /* out */ nsTArray<uint8_t>& aRegistration) override;
+           const nsTArray<uint8_t>& aChallenge) override;
 
-  virtual RefPtr<ResultPromise>
+  virtual RefPtr<U2FSignPromise>
   Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
        const nsTArray<uint8_t>& aApplication,
-       const nsTArray<uint8_t>& aChallenge,
-       /* out */ nsTArray<uint8_t>& aKeyHandle,
-       /* out */ nsTArray<uint8_t>& aSignature) override;
+       const nsTArray<uint8_t>& aChallenge) override;
 
   void Cancel() override;
 
 private:
   ~U2FHIDTokenManager();
 };
 
 } // namespace dom
--- a/dom/webauthn/U2FSoftTokenManager.cpp
+++ b/dom/webauthn/U2FSoftTokenManager.cpp
@@ -628,86 +628,85 @@ U2FSoftTokenManager::IsRegistered(const 
 // Bytes  Value
 // 1      0x05
 // 65     public key
 // 1      key handle length
 // *      key handle
 // ASN.1  attestation certificate
 // *      attestation signature
 //
-RefPtr<ResultPromise>
+RefPtr<U2FRegisterPromise>
 U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                               const nsTArray<uint8_t>& aApplication,
-                              const nsTArray<uint8_t>& aChallenge,
-                              /* out */ nsTArray<uint8_t>& aRegistration)
+                              const nsTArray<uint8_t>& aChallenge)
 {
   nsNSSShutDownPreventionLock locker;
   if (NS_WARN_IF(isAlreadyShutDown())) {
-    return ResultPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
   }
 
   if (!mInitialized) {
     nsresult rv = Init();
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      return ResultPromise::CreateAndReject(rv, __func__);
+      return U2FRegisterPromise::CreateAndReject(rv, __func__);
     }
   }
 
   // Optional exclusion list.
   for (auto desc: aDescriptors) {
     bool isRegistered = false;
     nsresult rv = IsRegistered(desc.id(), aApplication, isRegistered);
     if (NS_FAILED(rv)) {
-      return ResultPromise::CreateAndReject(rv, __func__);
+      return U2FRegisterPromise::CreateAndReject(rv, __func__);
     }
     if (isRegistered) {
-      return ResultPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
+      return U2FRegisterPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
     }
   }
 
   // We should already have a wrapping key
   MOZ_ASSERT(mWrappingKey);
 
   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
   MOZ_ASSERT(slot.get());
 
   // Construct a one-time-use Attestation Certificate
   UniqueSECKEYPrivateKey attestPrivKey;
   UniqueCERTCertificate attestCert;
   nsresult rv = GetAttestationCertificate(slot, attestPrivKey, attestCert,
                                           locker);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
   MOZ_ASSERT(attestCert);
   MOZ_ASSERT(attestPrivKey);
 
   // Generate a new keypair; the private will be wrapped into a Key Handle
   UniqueSECKEYPrivateKey privKey;
   UniqueSECKEYPublicKey pubKey;
   rv = GenEcKeypair(slot, privKey, pubKey, locker);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   // The key handle will be the result of keywrap(privKey, key=mWrappingKey)
   UniqueSECItem keyHandleItem = KeyHandleFromPrivateKey(slot, mWrappingKey,
                                                         const_cast<uint8_t*>(aApplication.Elements()),
                                                         aApplication.Length(),
                                                         privKey, locker);
   if (NS_WARN_IF(!keyHandleItem.get())) {
-    return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   // Sign the challenge using the Attestation privkey (from attestCert)
   mozilla::dom::CryptoBuffer signedDataBuf;
   if (NS_WARN_IF(!signedDataBuf.SetCapacity(1 + aApplication.Length() + aChallenge.Length() +
                                             keyHandleItem->len + kPublicKeyLen,
                                             mozilla::fallible))) {
-    return ResultPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
   }
 
   // // It's OK to ignore the return values here because we're writing into
   // // pre-allocated space
   signedDataBuf.AppendElement(0x00, mozilla::fallible);
   signedDataBuf.AppendElements(aApplication, mozilla::fallible);
   signedDataBuf.AppendElements(aChallenge, mozilla::fallible);
   signedDataBuf.AppendSECItem(keyHandleItem.get());
@@ -715,35 +714,35 @@ U2FSoftTokenManager::Register(const nsTA
 
   ScopedAutoSECItem signatureItem;
   SECStatus srv = SEC_SignData(&signatureItem, signedDataBuf.Elements(),
                                signedDataBuf.Length(), attestPrivKey.get(),
                                SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
   if (NS_WARN_IF(srv != SECSuccess)) {
     MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
             ("Signature failure: %d", PORT_GetError()));
-    return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   // Serialize the registration data
   mozilla::dom::CryptoBuffer registrationBuf;
   if (NS_WARN_IF(!registrationBuf.SetCapacity(1 + kPublicKeyLen + 1 + keyHandleItem->len +
                                               attestCert.get()->derCert.len +
                                               signatureItem.len, mozilla::fallible))) {
-    return ResultPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
+    return U2FRegisterPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
   }
   registrationBuf.AppendElement(0x05, mozilla::fallible);
   registrationBuf.AppendSECItem(pubKey->u.ec.publicValue);
   registrationBuf.AppendElement(keyHandleItem->len, mozilla::fallible);
   registrationBuf.AppendSECItem(keyHandleItem.get());
   registrationBuf.AppendSECItem(attestCert.get()->derCert);
   registrationBuf.AppendSECItem(signatureItem);
-  aRegistration = registrationBuf;
 
-  return ResultPromise::CreateAndResolve(NS_OK, __func__);
+  U2FRegisterResult result((nsTArray<uint8_t>(registrationBuf)));
+  return U2FRegisterPromise::CreateAndResolve(Move(result), __func__);
 }
 
 // A U2F Sign operation creates a signature over the "param" arguments (plus
 // some other stuff) using the private key indicated in the key handle argument.
 //
 // The format of the signed data is as follows:
 //
 //  32    Application parameter
@@ -752,65 +751,64 @@ U2FSoftTokenManager::Register(const nsTA
 //  32    Challenge parameter
 //
 // The format of the signature data is as follows:
 //
 //  1     User presence
 //  4     Counter
 //  *     Signature
 //
-RefPtr<ResultPromise>
+RefPtr<U2FSignPromise>
 U2FSoftTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
                           const nsTArray<uint8_t>& aApplication,
-                          const nsTArray<uint8_t>& aChallenge,
-                          nsTArray<uint8_t>& aKeyHandle,
-                          nsTArray<uint8_t>& aSignature)
+                          const nsTArray<uint8_t>& aChallenge)
 {
   nsNSSShutDownPreventionLock locker;
   if (NS_WARN_IF(isAlreadyShutDown())) {
-    return ResultPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
+    return U2FSignPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
   }
 
+  nsTArray<uint8_t> keyHandle;
   for (auto desc: aDescriptors) {
     bool isRegistered = false;
     nsresult rv = IsRegistered(desc.id(), aApplication, isRegistered);
     if (NS_SUCCEEDED(rv) && isRegistered) {
-      aKeyHandle.Assign(desc.id());
+      keyHandle.Assign(desc.id());
       break;
     }
   }
 
   // Fail if we didn't recognize a key id.
-  if (aKeyHandle.IsEmpty()) {
-    return ResultPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
+  if (keyHandle.IsEmpty()) {
+    return U2FSignPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
   }
 
   MOZ_ASSERT(mWrappingKey);
 
   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
   MOZ_ASSERT(slot.get());
 
   if (NS_WARN_IF((aChallenge.Length() != kParamLen) || (aApplication.Length() != kParamLen))) {
     MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
             ("Parameter lengths are wrong! challenge=%d app=%d expected=%d",
              (uint32_t)aChallenge.Length(), (uint32_t)aApplication.Length(), kParamLen));
 
-    return ResultPromise::CreateAndReject(NS_ERROR_ILLEGAL_VALUE, __func__);
+    return U2FSignPromise::CreateAndReject(NS_ERROR_ILLEGAL_VALUE, __func__);
   }
 
   // Decode the key handle
   UniqueSECKEYPrivateKey privKey = PrivateKeyFromKeyHandle(slot, mWrappingKey,
-                                                           const_cast<uint8_t*>(aKeyHandle.Elements()),
-                                                           aKeyHandle.Length(),
+                                                           const_cast<uint8_t*>(keyHandle.Elements()),
+                                                           keyHandle.Length(),
                                                            const_cast<uint8_t*>(aApplication.Elements()),
                                                            aApplication.Length(),
                                                            locker);
   if (NS_WARN_IF(!privKey.get())) {
     MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Couldn't get the priv key!"));
-    return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return U2FSignPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   // Increment the counter and turn it into a SECItem
   mCounter += 1;
   ScopedAutoSECItem counterItem(4);
   counterItem.data[0] = (mCounter >> 24) & 0xFF;
   counterItem.data[1] = (mCounter >> 16) & 0xFF;
   counterItem.data[2] = (mCounter >>  8) & 0xFF;
@@ -821,65 +819,65 @@ U2FSoftTokenManager::Sign(const nsTArray
                                            [counter] () {
                                              MOZ_ASSERT(NS_IsMainThread());
                                              Preferences::SetUint(PREF_U2F_NSSTOKEN_COUNTER, counter);
                                            }));
 
   // Compute the signature
   mozilla::dom::CryptoBuffer signedDataBuf;
   if (NS_WARN_IF(!signedDataBuf.SetCapacity(1 + 4 + (2 * kParamLen), mozilla::fallible))) {
-    return ResultPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
+    return U2FSignPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
   }
 
   // It's OK to ignore the return values here because we're writing into
   // pre-allocated space
   signedDataBuf.AppendElements(aApplication.Elements(), aApplication.Length(),
                                mozilla::fallible);
   signedDataBuf.AppendElement(0x01, mozilla::fallible);
   signedDataBuf.AppendSECItem(counterItem);
   signedDataBuf.AppendElements(aChallenge.Elements(), aChallenge.Length(),
                                mozilla::fallible);
 
   if (MOZ_LOG_TEST(gNSSTokenLog, LogLevel::Debug)) {
     nsAutoCString base64;
     nsresult rv = Base64URLEncode(signedDataBuf.Length(), signedDataBuf.Elements(),
                                   Base64URLEncodePaddingPolicy::Omit, base64);
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+      return U2FSignPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     }
 
     MOZ_LOG(gNSSTokenLog, LogLevel::Debug,
             ("U2F Token signing bytes (base64): %s", base64.get()));
   }
 
   ScopedAutoSECItem signatureItem;
   SECStatus srv = SEC_SignData(&signatureItem, signedDataBuf.Elements(),
                                signedDataBuf.Length(), privKey.get(),
                                SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
   if (NS_WARN_IF(srv != SECSuccess)) {
     MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
             ("Signature failure: %d", PORT_GetError()));
-    return ResultPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    return U2FSignPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   // Assemble the signature data into a buffer for return
   mozilla::dom::CryptoBuffer signatureBuf;
   if (NS_WARN_IF(!signatureBuf.SetCapacity(1 + counterItem.len + signatureItem.len,
                                            mozilla::fallible))) {
-    return ResultPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
+    return U2FSignPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
   }
 
   // It's OK to ignore the return values here because we're writing into
   // pre-allocated space
   signatureBuf.AppendElement(0x01, mozilla::fallible);
   signatureBuf.AppendSECItem(counterItem);
   signatureBuf.AppendSECItem(signatureItem);
 
-  aSignature = signatureBuf;
-  return ResultPromise::CreateAndResolve(NS_OK, __func__);
+  U2FSignResult result(Move(keyHandle), nsTArray<uint8_t>(signatureBuf));
+  return U2FSignPromise::CreateAndResolve(Move(result), __func__);
 }
 
 void
 U2FSoftTokenManager::Cancel()
 {
   // This implementation is sync, requests can't be aborted.
 }
 
--- a/dom/webauthn/U2FSoftTokenManager.h
+++ b/dom/webauthn/U2FSoftTokenManager.h
@@ -20,28 +20,25 @@ namespace mozilla {
 namespace dom {
 
 class U2FSoftTokenManager final : public U2FTokenTransport,
                                   public nsNSSShutDownObject
 {
 public:
   explicit U2FSoftTokenManager(uint32_t aCounter);
 
-  virtual RefPtr<ResultPromise>
+  virtual RefPtr<U2FRegisterPromise>
   Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
            const nsTArray<uint8_t>& aApplication,
-           const nsTArray<uint8_t>& aChallenge,
-           /* out */ nsTArray<uint8_t>& aRegistration) override;
+           const nsTArray<uint8_t>& aChallenge) override;
 
-  virtual RefPtr<ResultPromise>
+  virtual RefPtr<U2FSignPromise>
   Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
        const nsTArray<uint8_t>& aApplication,
-       const nsTArray<uint8_t>& aChallenge,
-       /* out */ nsTArray<uint8_t>& aKeyHandle,
-       /* out */ nsTArray<uint8_t>& aSignature) override;
+       const nsTArray<uint8_t>& aChallenge) override;
 
   virtual void Cancel() override;
 
   // For nsNSSShutDownObject
   virtual void virtualDestroyNSSReference() override;
   void destructorSafeDestroyNSSReference();
 
 private:
--- a/dom/webauthn/U2FTokenManager.cpp
+++ b/dom/webauthn/U2FTokenManager.cpp
@@ -186,18 +186,19 @@ U2FTokenManager::MaybeClearTransaction(W
 }
 
 void
 U2FTokenManager::ClearTransaction()
 {
   mTransactionParent = nullptr;
   // Drop managers at the end of all transactions
   mTokenManagerImpl = nullptr;
-  // Drop promise.
-  mResultPromise = nullptr;
+  // Drop promises.
+  mRegisterPromise = nullptr;
+  mSignPromise = nullptr;
   // Increase in case we're called by the WebAuthnTransactionParent.
   mTransactionId++;
 }
 
 RefPtr<U2FTokenTransport>
 U2FTokenManager::GetTokenManagerImpl()
 {
   if (mTokenManagerImpl) {
@@ -246,44 +247,44 @@ U2FTokenManager::Register(WebAuthnTransa
   // UnknownError and terminate the operation.
 
   if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
       (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
     AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
     return;
   }
 
-  nsTArray<uint8_t> reg;
-  mResultPromise = mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
-                                               aTransactionInfo.RpIdHash(),
-                                               aTransactionInfo.ClientDataHash(),
-                                               reg);
+  mRegisterPromise = mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
+                                                 aTransactionInfo.RpIdHash(),
+                                                 aTransactionInfo.ClientDataHash());
 
-  mResultPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
-                       [tid, reg](nsresult rv) {
-                         MOZ_ASSERT(NS_SUCCEEDED(rv));
-                         U2FTokenManager* mgr = U2FTokenManager::Get();
-                         mgr->MaybeConfirmRegister(tid, reg);
-                       },
-                       [tid](nsresult rv) {
-                         MOZ_ASSERT(NS_FAILED(rv));
-                         U2FTokenManager* mgr = U2FTokenManager::Get();
-                         mgr->MaybeAbortTransaction(tid, rv);
-                       });
+  mRegisterPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
+                         [tid](U2FRegisterResult&& aResult) {
+                           U2FTokenManager* mgr = U2FTokenManager::Get();
+                           mgr->MaybeConfirmRegister(tid, aResult);
+                         },
+                         [tid](nsresult rv) {
+                           MOZ_ASSERT(NS_FAILED(rv));
+                           U2FTokenManager* mgr = U2FTokenManager::Get();
+                           mgr->MaybeAbortTransaction(tid, rv);
+                         });
 }
 
 void
 U2FTokenManager::MaybeConfirmRegister(uint64_t aTransactionId,
-                                      const nsTArray<uint8_t>& aRegister)
+                                      U2FRegisterResult& aResult)
 {
   if (mTransactionId != aTransactionId) {
     return;
   }
 
-  Unused << mTransactionParent->SendConfirmRegister(aRegister);
+  nsTArray<uint8_t> registration;
+  aResult.ConsumeRegistration(registration);
+
+  Unused << mTransactionParent->SendConfirmRegister(registration);
   ClearTransaction();
 }
 
 void
 U2FTokenManager::Sign(WebAuthnTransactionParent* aTransactionParent,
                       const WebAuthnTransactionInfo& aTransactionInfo)
 {
   MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
@@ -299,47 +300,46 @@ U2FTokenManager::Sign(WebAuthnTransactio
   }
 
   if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
       (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
     AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
     return;
   }
 
-  nsTArray<uint8_t> id;
-  nsTArray<uint8_t> sig;
-  mResultPromise = mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
-                                           aTransactionInfo.RpIdHash(),
-                                           aTransactionInfo.ClientDataHash(),
-                                           id,
-                                           sig);
+  mSignPromise = mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
+                                         aTransactionInfo.RpIdHash(),
+                                         aTransactionInfo.ClientDataHash());
 
-  mResultPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
-                       [tid, id, sig](nsresult rv) {
-                         MOZ_ASSERT(NS_SUCCEEDED(rv));
-                         U2FTokenManager* mgr = U2FTokenManager::Get();
-                         mgr->MaybeConfirmSign(tid, id, sig);
-                       },
-                       [tid](nsresult rv) {
-                         MOZ_ASSERT(NS_FAILED(rv));
-                         U2FTokenManager* mgr = U2FTokenManager::Get();
-                         mgr->MaybeAbortTransaction(tid, rv);
-                       });
+  mSignPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
+                     [tid](U2FSignResult&& aResult) {
+                       U2FTokenManager* mgr = U2FTokenManager::Get();
+                       mgr->MaybeConfirmSign(tid, aResult);
+                     },
+                     [tid](nsresult rv) {
+                       MOZ_ASSERT(NS_FAILED(rv));
+                       U2FTokenManager* mgr = U2FTokenManager::Get();
+                       mgr->MaybeAbortTransaction(tid, rv);
+                     });
 }
 
 void
 U2FTokenManager::MaybeConfirmSign(uint64_t aTransactionId,
-                                  const nsTArray<uint8_t>& aKeyHandle,
-                                  const nsTArray<uint8_t>& aSignature)
+                                  U2FSignResult& aResult)
 {
   if (mTransactionId != aTransactionId) {
     return;
   }
 
-  Unused << mTransactionParent->SendConfirmSign(aKeyHandle, aSignature);
+  nsTArray<uint8_t> keyHandle;
+  aResult.ConsumeKeyHandle(keyHandle);
+  nsTArray<uint8_t> signature;
+  aResult.ConsumeSignature(signature);
+
+  Unused << mTransactionParent->SendConfirmSign(keyHandle, signature);
   ClearTransaction();
 }
 
 void
 U2FTokenManager::Cancel(WebAuthnTransactionParent* aParent)
 {
   if (mTransactionParent == aParent) {
     mTokenManagerImpl->Cancel();
--- a/dom/webauthn/U2FTokenManager.h
+++ b/dom/webauthn/U2FTokenManager.h
@@ -47,26 +47,25 @@ private:
   U2FTokenManager();
   ~U2FTokenManager();
   RefPtr<U2FTokenTransport> GetTokenManagerImpl();
   void AbortTransaction(const nsresult& aError);
   void ClearTransaction();
   void MaybeAbortTransaction(uint64_t aTransactionId,
                              const nsresult& aError);
   void MaybeConfirmRegister(uint64_t aTransactionId,
-                            const nsTArray<uint8_t>& aRegister);
-  void MaybeConfirmSign(uint64_t aTransactionId,
-                        const nsTArray<uint8_t>& aKeyHandle,
-                        const nsTArray<uint8_t>& aSignature);
+                            U2FRegisterResult& aResult);
+  void MaybeConfirmSign(uint64_t aTransactionId, U2FSignResult& aResult);
   // Using a raw pointer here, as the lifetime of the IPC object is managed by
   // the PBackground protocol code. This means we cannot be left holding an
   // invalid IPC protocol object after the transaction is finished.
   WebAuthnTransactionParent* mTransactionParent;
   RefPtr<U2FTokenTransport> mTokenManagerImpl;
-  RefPtr<ResultPromise> mResultPromise;
+  RefPtr<U2FRegisterPromise> mRegisterPromise;
+  RefPtr<U2FSignPromise> mSignPromise;
   // Guards the asynchronous promise resolution of token manager impls.
   // We don't need to protect this with a lock as it will only be modified
   // and checked on the PBackground thread in the parent process.
   uint64_t mTransactionId;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/webauthn/U2FTokenTransport.h
+++ b/dom/webauthn/U2FTokenTransport.h
@@ -13,36 +13,69 @@
  * Abstract class representing a transport manager for U2F Keys (software,
  * bluetooth, usb, etc.). Hides the implementation details for specific key
  * transport types.
  */
 
 namespace mozilla {
 namespace dom {
 
-typedef MozPromise<nsresult, nsresult, false> ResultPromise;
+class U2FRegisterResult {
+public:
+  explicit U2FRegisterResult(nsTArray<uint8_t>&& aRegistration)
+    : mRegistration(aRegistration)
+  { }
+
+  void ConsumeRegistration(nsTArray<uint8_t>& aBuffer) {
+    aBuffer = Move(mRegistration);
+  }
+
+private:
+  nsTArray<uint8_t> mRegistration;
+};
+
+class U2FSignResult {
+public:
+  explicit U2FSignResult(nsTArray<uint8_t>&& aKeyHandle,
+                         nsTArray<uint8_t>&& aSignature)
+    : mKeyHandle(aKeyHandle)
+    , mSignature(aSignature)
+  { }
+
+  void ConsumeKeyHandle(nsTArray<uint8_t>& aBuffer) {
+    aBuffer = Move(mKeyHandle);
+  }
+
+  void ConsumeSignature(nsTArray<uint8_t>& aBuffer) {
+    aBuffer = Move(mSignature);
+  }
+
+private:
+  nsTArray<uint8_t> mKeyHandle;
+  nsTArray<uint8_t> mSignature;
+};
+
+typedef MozPromise<U2FRegisterResult, nsresult, true> U2FRegisterPromise;
+typedef MozPromise<U2FSignResult, nsresult, true> U2FSignPromise;
 
 class U2FTokenTransport
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(U2FTokenTransport);
   U2FTokenTransport() {}
 
-  virtual RefPtr<ResultPromise>
+  virtual RefPtr<U2FRegisterPromise>
   Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
            const nsTArray<uint8_t>& aApplication,
-           const nsTArray<uint8_t>& aChallenge,
-           /* out */ nsTArray<uint8_t>& aRegistration) = 0;
+           const nsTArray<uint8_t>& aChallenge) = 0;
 
-  virtual RefPtr<ResultPromise>
+  virtual RefPtr<U2FSignPromise>
   Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
        const nsTArray<uint8_t>& aApplication,
-       const nsTArray<uint8_t>& aChallenge,
-       /* out */ nsTArray<uint8_t>& aKeyHandle,
-       /* out */ nsTArray<uint8_t>& aSignature) = 0;
+       const nsTArray<uint8_t>& aChallenge) = 0;
 
   virtual void Cancel() = 0;
 
 protected:
   virtual ~U2FTokenTransport() = default;
 };
 
 } // namespace dom
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -149,17 +149,16 @@ partial interface Document {
   //(HTML only)boolean queryCommandSupported(DOMString commandId);
   //(HTML only)DOMString queryCommandValue(DOMString commandId);
   //(Not implemented)readonly attribute HTMLCollection commands;
 
   // special event handler IDL attributes that only apply to Document objects
   [LenientThis] attribute EventHandler onreadystatechange;
 
   // Gecko extensions?
-                attribute EventHandler onwheel;
                 attribute EventHandler onbeforescriptexecute;
                 attribute EventHandler onafterscriptexecute;
 
                 [Pref="dom.select_events.enabled"]
                 attribute EventHandler onselectionchange;
 
   /**
    * True if this document is synthetic : stand alone image, video, audio file,
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -85,20 +85,16 @@ interface Element : Node {
    *
    * @note The font size inflation ratio that is returned is actually the
    *       font size inflation data for the element's _primary frame_, not the
    *       element itself, but for most purposes, this should be sufficient.
    */
   [ChromeOnly]
   readonly attribute float fontSizeInflation;
 
-  // Mozilla specific stuff
-  [Pure]
-           attribute EventHandler onwheel;
-
   // Selectors API
   /**
    * Returns whether this element would be selected by the given selector
    * string.
    *
    * See <http://dev.w3.org/2006/webapi/selectors-api2/#matchesselector>
    */
   [Throws, Pure, BinaryName="matches"]
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -63,17 +63,17 @@ interface GlobalEventHandlers {
            attribute EventHandler onloadstart;
            attribute EventHandler onmousedown;
   [LenientThis] attribute EventHandler onmouseenter;
   [LenientThis] attribute EventHandler onmouseleave;
            attribute EventHandler onmousemove;
            attribute EventHandler onmouseout;
            attribute EventHandler onmouseover;
            attribute EventHandler onmouseup;
-           //(Not implemented)attribute EventHandler onmousewheel;
+           attribute EventHandler onwheel;
            attribute EventHandler onpause;
            attribute EventHandler onplay;
            attribute EventHandler onplaying;
            attribute EventHandler onprogress;
            attribute EventHandler onratechange;
            attribute EventHandler onreset;
            attribute EventHandler onresize;
            attribute EventHandler onscroll;
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -319,19 +319,16 @@ partial interface Window {
   /**
    * This property exists because static attributes don't yet work for
    * JS-implemented WebIDL (see bugs 1058606 and 863952). With this hack, we
    * can use `MozSelfSupport.something(...)`, which will continue to work
    * after we ditch this property and switch to static attributes. See
    */
   [ChromeOnly, Throws] readonly attribute MozSelfSupport MozSelfSupport;
 
-  [Pure]
-           attribute EventHandler onwheel;
-
            attribute EventHandler ondevicemotion;
            attribute EventHandler ondeviceorientation;
            attribute EventHandler onabsolutedeviceorientation;
            attribute EventHandler ondeviceproximity;
            attribute EventHandler onuserproximity;
            attribute EventHandler ondevicelight;
 
 #ifdef MOZ_B2G
--- a/dom/xbl/test/mochitest.ini
+++ b/dom/xbl/test/mochitest.ini
@@ -19,17 +19,16 @@ support-files =
   file_bug950909.html
 
 [test_bug310107.html]
 [test_bug366770.html]
 [test_bug371724.xhtml]
 [test_bug372769.html]
 [test_bug378866.xhtml]
 [test_bug379959.html]
-[test_bug379959_legacy.html]
 [test_bug389322.xhtml]
 [test_bug397934.html]
 [test_bug400705.xhtml]
 [test_bug401907.xhtml]
 [test_bug403162.xhtml]
 [test_bug468210.xhtml]
 [test_bug481558.html]
 [test_bug526178.xhtml]
--- a/dom/xbl/test/test_bug379959.html
+++ b/dom/xbl/test/test_bug379959.html
@@ -1,20 +1,16 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=379959
 -->
 <head>
   <title>Test for Bug 379959</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script>
-    // TODO: Bug 1324406: Treat 'data:' documents as unique, opaque origins
-    SpecialPowers.setBoolPref("security.data_uri.unique_opaque_origin", true);
-  </script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onload="runTest();">
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=379959">Mozilla Bug 379959</a>
   <p id="display">
     Note: In order to re-run this test correctly you need to shift-reload
     rather than simply reload. If you just reload we will restore the
     previous url in the iframe which will result in an extra unexpected
@@ -32,17 +28,17 @@ SimpleTest.waitForExplicitFinish();
 var seenData = false;
 var seenSameOrigin = false;
 var seenCrossOrign = false;
 
 function receiveMessage(e) {
   is(e.origin, "http://mochi.test:8888", "wrong sender!");
 
   if (e.data.test === "dataIsAllowed") {
-    is(e.data.result, 0, "data-url load should have blocked");
+    is(e.data.result, 1, "data-url load should have succeeded");
     seenData = true;
   }
   else if (e.data.test === "sameOriginIsAllowed") {
     is(e.data.result, 1, "same site load should have succeeded");
     seenSameOrigin = true;
   }
   else if (e.data.test === "crossOriginIsBlocked") {
     is(e.data.result, 0, "cross site load should have failed");
deleted file mode 100644
--- a/dom/xbl/test/test_bug379959_legacy.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=379959
--->
-<head>
-  <title>Test for Bug 379959</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script>
-    // TODO: Bug 1324406: Treat 'data:' documents as unique, opaque origins
-    SpecialPowers.setBoolPref("security.data_uri.unique_opaque_origin", false);
-  </script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="runTest();">
-  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=379959">Mozilla Bug 379959</a>
-  <p id="display">
-    Note: In order to re-run this test correctly you need to shift-reload
-    rather than simply reload. If you just reload we will restore the
-    previous url in the iframe which will result in an extra unexpected
-    message.
-  </p>
-  <div id="content" style="display: none"></div>
-  <iframe id="dataFrame"></iframe>
-  <iframe id="originFrame"></iframe>
-
-  <pre id="test">
-    <script class="testbody" type="application/javascript">
-
-SimpleTest.waitForExplicitFinish();
-
-var seenData = false;
-var seenSameOrigin = false;
-var seenCrossOrign = false;
-
-function receiveMessage(e) {
-  is(e.origin, "http://mochi.test:8888", "wrong sender!");
-
-  if (e.data.test === "dataIsAllowed") {
-    is(e.data.result, 1, "data-url load should have succeeded");
-    seenData = true;
-  }
-  else if (e.data.test === "sameOriginIsAllowed") {
-    is(e.data.result, 1, "same site load should have succeeded");
-    seenSameOrigin = true;
-  }
-  else if (e.data.test === "crossOriginIsBlocked") {
-    is(e.data.result, 0, "cross site load should have failed");
-    seenCrossOrign = true;
-  }
-  else {
-    ok (false, "unrecognized test");
-  }
-
-  if (seenData && seenSameOrigin && seenCrossOrign) {
-    window.removeEventListener("message", receiveMessage);
-    SimpleTest.finish();
-  }
-}
-
-window.addEventListener("message", receiveMessage);
-
-function runTest() {
-  // make sure data: is allowed
-  document.getElementById('dataFrame').src = "file_bug379959_data.html";
-  // make sure same-origin is allowed but cross site is blocked
-  document.getElementById('originFrame').src = "file_bug379959_cross.html";
-}
-
-    </script>
-  </pre>
-</body>
-</html>
--- a/editor/libeditor/crashtests/430624-1.html
+++ b/editor/libeditor/crashtests/430624-1.html
@@ -6,9 +6,9 @@ function crash() {
   window.frames[0].location = 'data:text/html;charset=utf-8,2nd%20page';
 }
 </script>
 </head>
 <body onload="crash()">
   <!-- iframe contents: <html><body onload="document.body.setAttribute('spellcheck', true);"></body></html> -->
   <iframe src="data:text/html;charset=utf-8;base64,PGh0bWw%2BPGJvZHkgb25sb2FkPSJkb2N1bWVudC5ib2R5LnNldEF0dHJpYnV0ZSgnc3BlbGxjaGVjaycsIHRydWUpOyI%2BPC9ib2R5PjwvaHRtbD4%3D"></iframe>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -258,19 +258,21 @@ ClientPaintedLayer::CapturePaintedConten
 
   // DrawTargetCapture requires a reference DT
   // That is used when some API requires a snapshot.
   // TODO: Fixup so DrawTargetCapture lazily creates a reference DT
   RefPtr<DrawTarget> refDT =
     Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetDefaultContentBackend(),
                               imageSize, gfx::SurfaceFormat::B8G8R8A8);
 
+  // We don't clear the rect here like WRPaintedBlobLayers do
+  // because ContentClient already clears the surface for us during BeginPaint.
   RefPtr<DrawTargetCapture> captureDT = refDT->CreateCaptureDT(imageSize);
-  captureDT->ClearRect(Rect(0, 0, imageSize.width, imageSize.height));
   captureDT->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
+
   RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
   MOZ_ASSERT(ctx); // already checked the target above
 
   ClientManager()->GetPaintedLayerCallback()(this,
                                              ctx,
                                              visibleRegion.ToUnknownRegion(),
                                              visibleRegion.ToUnknownRegion(),
                                              DrawRegionClip::DRAW,
--- a/gfx/layers/mlgpu/BufferCache.cpp
+++ b/gfx/layers/mlgpu/BufferCache.cpp
@@ -1,127 +1,101 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * 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 "BufferCache.h"
 #include "MLGDevice.h"
+#include "ShaderDefinitionsMLGPU.h"
 #include "mozilla/MathAlgorithms.h"
 
 namespace mozilla {
 namespace layers {
 
+using namespace mlg;
+
 BufferCache::BufferCache(MLGDevice* aDevice)
- : mDevice(aDevice)
+ : mDevice(aDevice),
+   mFirstSizeClass(CeilingLog2(kConstantBufferElementSize)),
+   mFrameNumber(0),
+   mNextSizeClassToShrink(0)
 {
+  // Create a cache of buffers for each size class, where each size class is a
+  // power of 2 between the minimum and maximum size of a constant buffer.
+  size_t maxBindSize = mDevice->GetMaxConstantBufferBindSize();
+  MOZ_ASSERT(IsPowerOfTwo(maxBindSize));
+
+  size_t lastSizeClass = CeilingLog2(maxBindSize);
+  MOZ_ASSERT(lastSizeClass >= mFirstSizeClass);
+
+  mCaches.resize(lastSizeClass - mFirstSizeClass + 1);
 }
 
 BufferCache::~BufferCache()
 {
 }
 
 RefPtr<MLGBuffer>
 BufferCache::GetOrCreateBuffer(size_t aBytes)
 {
-  // Try to take a buffer from the expired frame. If none exists, make a new one.
-  RefPtr<MLGBuffer> buffer = mExpired.Take(aBytes);
-  if (!buffer) {
-    // Round up to the nearest size class, but not over 1024 bytes.
-    size_t roundedUp = std::max(std::min(RoundUpPow2(aBytes), size_t(1024)), aBytes);
-    buffer = mDevice->CreateBuffer(MLGBufferType::Constant, roundedUp, MLGUsage::Dynamic, nullptr);
-    if (!buffer) {
-      return nullptr;
-    }
+  size_t sizeClass = CeilingLog2(aBytes);
+  size_t sizeClassIndex = sizeClass - mFirstSizeClass;
+  if (sizeClassIndex >= mCaches.size()) {
+    return mDevice->CreateBuffer(MLGBufferType::Constant, aBytes, MLGUsage::Dynamic, nullptr);
   }
 
-  MOZ_ASSERT(buffer->GetSize() >= aBytes);
+  CachePool& pool = mCaches[sizeClassIndex];
 
-  // Assign this buffer to the current frame, so it becomes available again once
-  // this frame expires.
-  mCurrent.Put(buffer);
+  // See if we've cached a buffer that wasn't used in the past 2 frames. A buffer
+  // used this frame could have already been mapped and written to, and a buffer
+  // used the previous frame might still be in-use by the GPU. While the latter
+  // case is okay, it causes aliasing in the driver. Since content is double
+  // buffered we do not let the compositor get more than 1 frames ahead, and a
+  // count of 2 frames should ensure the buffer is unused.
+  if (!pool.empty() && mFrameNumber >= pool.front().mLastUsedFrame + 2) {
+    RefPtr<MLGBuffer> buffer = pool.front().mBuffer;
+    pool.pop_front();
+    pool.push_back(CacheEntry(mFrameNumber, buffer));
+    MOZ_RELEASE_ASSERT(buffer->GetSize() >= aBytes);
+    return buffer;
+  }
+
+  // Allocate a new buffer and cache it.
+  size_t bytes = (size_t(1) << sizeClass);
+  MOZ_ASSERT(bytes >= aBytes);
+
+  RefPtr<MLGBuffer> buffer =
+    mDevice->CreateBuffer(MLGBufferType::Constant, bytes, MLGUsage::Dynamic, nullptr);
+  if (!buffer) {
+    return nullptr;
+  }
+
+  pool.push_back(CacheEntry(mFrameNumber, buffer));
   return buffer;
 }
 
 void
 BufferCache::EndFrame()
 {
-  BufferPool empty;
-  mExpired = Move(mPrevious);
-  mPrevious = Move(mCurrent);
-  mCurrent = Move(empty);
-}
-
-RefPtr<MLGBuffer>
-BufferPool::Take(size_t aBytes)
-{
-  MOZ_ASSERT(aBytes >= 16);
-
-  // We need to bump the request up to the nearest size class. For example,
-  // a request of 24 bytes must allocate from the 32 byte pool.
-  SizeClass sc = GetSizeClassFromHighBit(CeilingLog2(aBytes));
-  if (sc == SizeClass::Huge) {
-    return TakeHugeBuffer(aBytes);
-  }
-
-  if (mClasses[sc].IsEmpty()) {
-    return nullptr;
-  }
-
-  RefPtr<MLGBuffer> buffer = mClasses[sc].LastElement();
-  mClasses[sc].RemoveElementAt(mClasses[sc].Length() - 1);
-  return buffer.forget();
-}
-
-void
-BufferPool::Put(MLGBuffer* aBuffer)
-{
-  MOZ_ASSERT(aBuffer->GetSize() >= 16);
+  // Consider a buffer dead after ~5 seconds assuming 60 fps.
+  static size_t kMaxUnusedFrameCount = 60 * 5;
 
-  // When returning buffers, we bump them into a lower size class. For example
-  // a 24 byte buffer cannot be re-used for a 32-byte allocation, so it goes
-  // into the 16-byte class.
-  SizeClass sc = GetSizeClassFromHighBit(FloorLog2(aBuffer->GetSize()));
-  if (sc == SizeClass::Huge) {
-    mHugeBuffers.push_back(aBuffer);
-  } else {
-    mClasses[sc].AppendElement(aBuffer);
+  // At the end of each frame we pick one size class and see if it has any
+  // buffers that haven't been used for many frames. If so we clear them.
+  // The next frame we'll search the next size class. (This is just to spread
+  // work over more than one frame.)
+  CachePool& pool = mCaches[mNextSizeClassToShrink];
+  while (!pool.empty()) {
+    // Since the deque is sorted oldest-to-newest, front-to-back, we can stop
+    // searching as soon as a buffer is active.
+    if (mFrameNumber - pool.front().mLastUsedFrame < kMaxUnusedFrameCount) {
+      break;
+    }
+    pool.pop_front();
   }
-}
-
-RefPtr<MLGBuffer>
-BufferPool::TakeHugeBuffer(size_t aBytes)
-{
-  static const size_t kMaxSearches = 3;
-  size_t numSearches = std::min(kMaxSearches, mHugeBuffers.size());
-
-  for (size_t i = 0; i < numSearches; i++) {
-    RefPtr<MLGBuffer> buffer = mHugeBuffers.front();
-    mHugeBuffers.pop_front();
+  mNextSizeClassToShrink = (mNextSizeClassToShrink + 1) % mCaches.size();
 
-    // Don't pick buffers that are massively overallocated.
-    if (buffer->GetSize() >= aBytes && buffer->GetSize() <= aBytes * 2) {
-      return buffer.forget();
-    }
-
-    // Return the buffer to the list.
-    mHugeBuffers.push_back(buffer);
-  }
-
-  return nullptr;
-}
-
-/* static */ BufferPool::SizeClass
-BufferPool::GetSizeClassFromHighBit(size_t aBit)
-{
-  // If the size is smaller than our smallest size class (which should
-  // never happen), or bigger than our largest size class, we dump it
-  // in the catch-all "huge" list.
-  static const size_t kBitForFirstClass = 4;
-  static const size_t kBitForLastClass = kBitForFirstClass + size_t(SizeClass::Huge);
-  if (aBit < kBitForFirstClass || aBit >= kBitForLastClass) {
-    return SizeClass::Huge;
-  }
-  return SizeClass(aBit - kBitForFirstClass);
+  mFrameNumber++;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/mlgpu/BufferCache.h
+++ b/gfx/layers/mlgpu/BufferCache.h
@@ -2,98 +2,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/. */
 
 #ifndef mozilla_gfx_layers_mlgpu_BufferCache_h
 #define mozilla_gfx_layers_mlgpu_BufferCache_h
 
 #include "mozilla/EnumeratedArray.h"
-#include "nsTArray.h"
 #include <deque>
+#include <vector>
 
 namespace mozilla {
 namespace layers {
 
 class MLGBuffer;
 class MLGDevice;
 
-// This file defines a buffer caching mechanism for systems where constant
-// buffer offset binding is not allowed. On those systems we must allocate
-// new buffers each frame, and this cache allows us to re-use them.
-
-// Track buffers based on their size class, for small buffers.
-class BufferPool
-{
-public:
-  // Remove a buffer from the pool holding at least |aBytes|.
-  RefPtr<MLGBuffer> Take(size_t aBytes);
-
-  // Put a buffer into the pool holding at least |aBytes|.
-  void Put(MLGBuffer* aBuffer);
-
-  BufferPool& operator =(BufferPool&& aOther) {
-    mClasses = Move(aOther.mClasses);
-    mHugeBuffers = Move(aOther.mHugeBuffers);
-    return *this;
-  }
-
-private:
-  // Try to see if we can quickly re-use any buffer that didn't fit into a
-  // pre-existing size class.
-  RefPtr<MLGBuffer> TakeHugeBuffer(size_t aBytes);
-
-  enum class SizeClass {
-    One,    // 16+ bytes (one constant)
-    Two,    // 32+ bytes (two constants)
-    Four,   // 64+ bytes (four constants)
-    Eight,  // 128+ bytes (eight constants)
-    Medium,  // 256+ bytes (16 constants)
-    Large,   // 512+ bytes (32 constants)
-    Huge     // 1024+ bytes (64+ constants)
-  };
-  static SizeClass GetSizeClassFromHighBit(size_t bit);
-
-private:
-  typedef nsTArray<RefPtr<MLGBuffer>> BufferList;
-  EnumeratedArray<SizeClass, SizeClass::Huge, BufferList> mClasses;
-  std::deque<RefPtr<MLGBuffer>> mHugeBuffers;
-};
-
-// Cache buffer pools based on how long ago they were last used.
+// Cache MLGBuffers based on how long ago they were last used.
 class BufferCache
 {
 public:
   explicit BufferCache(MLGDevice* aDevice);
   ~BufferCache();
 
   // Get a buffer that has at least |aBytes|, or create a new one
   // if none can be re-used.
   RefPtr<MLGBuffer> GetOrCreateBuffer(size_t aBytes);
 
-  // Rotate buffers after a frame has been completed.
+  // Age out old buffers after a frame has been completed.
   void EndFrame();
 
 private:
   // Not RefPtr since this would create a cycle.
   MLGDevice* mDevice;
 
-  // We keep three active buffer pools:
-  //   The "expired" pool, which was used two frames ago.
-  //   The "previous" pool, which is being used by the previous frame.
-  //   The "current" pool, which is being used for the current frame.
+  // The first size class is Log2(N), where 16 is the minimum size of a
+  // constant buffer (currently 16 bytes).
+  size_t mFirstSizeClass;
+
+  // Each size class is a power of 2. Each pool of buffers is represented as a
+  // deque, with the least-recently-used (i.e., oldest) buffers at the front,
+  // and most-recently-used (i.e., newest) buffers at the back. To re-use a
+  // buffer it is popped off the front and re-added to the back.
   //
-  // We always allocate from the expired pool into the current pool.
-  // After a frame is completed, the current is moved into the previous,
-  // and the previous is moved into the expired. The expired buffers
-  // are deleted if still alive.
-  //
-  // Since Layers does not allow us to composite more than one frame
-  // ahead, this system ensures the expired buffers are always free.
-  BufferPool mExpired;
-  BufferPool mPrevious;
-  BufferPool mCurrent;
+  // This is not always efficient use of storage: if a single frame allocates
+  // 300 buffers of the same size, we may keep recycling through all those
+  // buffers for a long time, as long as at least one gets used per frame.
+  // But since buffers use tiny amounts of memory, and they are only mapped
+  // while drawing, it shouldn't be a big deal.
+  struct CacheEntry {
+    CacheEntry() : mLastUsedFrame(0)
+    {}
+    CacheEntry(const CacheEntry& aEntry)
+     : mLastUsedFrame(aEntry.mLastUsedFrame),
+       mBuffer(aEntry.mBuffer)
+    {}
+    CacheEntry(CacheEntry&& aEntry)
+     : mLastUsedFrame(aEntry.mLastUsedFrame),
+       mBuffer(Move(aEntry.mBuffer))
+    {}
+    CacheEntry(size_t aLastUsedFrame, MLGBuffer* aBuffer)
+     : mLastUsedFrame(aLastUsedFrame),
+       mBuffer(aBuffer)
+    {}
+
+    uint64_t mLastUsedFrame;
+    RefPtr<MLGBuffer> mBuffer;
+  };
+  typedef std::deque<CacheEntry> CachePool;
+
+  // We track how many frames have occurred to determine the age of cache entries.
+  uint64_t mFrameNumber;
+
+  // To avoid doing too much work in one frame, we only shrink one size class
+  // per frame.
+  uint64_t mNextSizeClassToShrink;
+
+  // There is one pool of buffers for each power of 2 allocation size. The
+  // maximum buffer size is at most 64KB on Direct3D 11.
+  std::vector<CachePool> mCaches;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_gfx_layers_mlgpu_BufferCache_h
--- a/gfx/layers/mlgpu/MLGDevice.h
+++ b/gfx/layers/mlgpu/MLGDevice.h
@@ -404,16 +404,18 @@ public:
   // a given run of bytes. This is only supported on Windows 8+ for Direct3D 11.
   bool CanUseConstantBufferOffsetBinding() const {
     return mCanUseConstantBufferOffsetBinding;
   }
 
   // Return the maximum number of elements that can be bound to a constant
   // buffer. This is different than the maximum size of a buffer (there is
   // no such limit on Direct3D 11.1).
+  //
+  // The return value must be a power of two.
   size_t GetMaxConstantBufferBindSize() const {
     return mMaxConstantBufferBindSize;
   }
 
 protected:
   virtual ~MLGDevice();
 
   virtual void SetPrimitiveTopology(MLGPrimitiveTopology aTopology) = 0;
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -23,19 +23,16 @@ using namespace mozilla::gfx;
 gfxAlphaBoxBlur::gfxAlphaBoxBlur()
   : mData(nullptr),
     mAccelerated(false)
 {
 }
 
 gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
 {
-  if (mData) {
-    free(mData);
-  }
 }
 
 already_AddRefed<gfxContext>
 gfxAlphaBoxBlur::Init(gfxContext* aDestinationCtx,
                       const gfxRect& aRect,
                       const IntSize& aSpreadRadius,
                       const IntSize& aBlurRadius,
                       const gfxRect* aDirtyRect,
@@ -86,16 +83,17 @@ gfxAlphaBoxBlur::InitDrawTarget(const Dr
     mAccelerated = true;
     mDrawTarget =
       aReferenceDT->CreateShadowDrawTarget(mBlur.GetSize(),
                                            SurfaceFormat::A8,
                                            AlphaBoxBlur::CalculateBlurSigma(aBlurRadius.width));
   } else {
     // Make an alpha-only surface to draw on. We will play with the data after
     // everything is drawn to create a blur effect.
+    // This will be freed when the DrawTarget dies
     mData = static_cast<uint8_t*>(calloc(1, blurDataSize));
     if (!mData) {
       return nullptr;
     }
     mDrawTarget =
       Factory::DoesBackendSupportDataDrawtarget(backend) ?
         Factory::CreateDrawTargetForData(backend,
                                          mData,
@@ -104,18 +102,29 @@ gfxAlphaBoxBlur::InitDrawTarget(const Dr
                                          SurfaceFormat::A8) :
         gfxPlatform::CreateDrawTargetForData(mData,
                                              mBlur.GetSize(),
                                              mBlur.GetStride(),
                                              SurfaceFormat::A8);
   }
 
   if (!mDrawTarget || !mDrawTarget->IsValid()) {
+    if (mData) {
+      free(mData);
+    }
+
     return nullptr;
   }
+
+  if (mData) {
+    mDrawTarget->AddUserData(reinterpret_cast<UserDataKey*>(mDrawTarget.get()),
+                              mData,
+                              free);
+  }
+
   mDrawTarget->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft()));
   return do_AddRef(mDrawTarget);
 }
 
 already_AddRefed<SourceSurface>
 gfxAlphaBoxBlur::DoBlur(const Color* aShadowColor, IntPoint* aOutTopLeft)
 {
   if (mData) {
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -124,53 +124,52 @@ class CPOWProxyHandler : public BaseProx
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                               AutoIdVector& props) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy,
                              MutableHandleValue v, bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject obj, js::ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject obj,
                          IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<RegExpShared*> shared) const override;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const override;
     virtual void objectMoved(JSObject* proxy, const JSObject* old) const override;
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
     virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const override;
     virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
                                         MutableHandleObject protop) const override;
 
     static const char family;
     static const CPOWProxyHandler singleton;
 };
 
 const char CPOWProxyHandler::family = 0;
 const CPOWProxyHandler CPOWProxyHandler::singleton;
 
-#define FORWARD(call, args)                                             \
+#define FORWARD(call, args, failRetVal)                                 \
     AUTO_PROFILER_LABEL(__func__, JS);                                  \
     WrapperOwner* owner = OwnerOf(proxy);                               \
     if (!owner->active()) {                                             \
         JS_ReportErrorASCII(cx, "cannot use a CPOW whose process is gone"); \
-        return false;                                                   \
+        return failRetVal;                                              \
     }                                                                   \
     if (!owner->allowMessage(cx)) {                                     \
-        return false;                                                   \
+        return failRetVal;                                              \
     }                                                                   \
     {                                                                   \
         CPOWTimer timer(cx);                                            \
         return owner->call args;                                        \
     }
 
 bool
 CPOWProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                         MutableHandle<PropertyDescriptor> desc) const
 {
-    FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
+    FORWARD(getPropertyDescriptor, (cx, proxy, id, desc), false);
 }
 
 bool
 WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                     MutableHandle<PropertyDescriptor> desc)
 {
     ObjectId objId = idOf(proxy);
 
@@ -190,17 +189,17 @@ WrapperOwner::getPropertyDescriptor(JSCo
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                            MutableHandle<PropertyDescriptor> desc) const
 {
-    FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc));
+    FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc), false);
 }
 
 bool
 WrapperOwner::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                        MutableHandle<PropertyDescriptor> desc)
 {
     ObjectId objId = idOf(proxy);
 
@@ -221,17 +220,17 @@ WrapperOwner::getOwnPropertyDescriptor(J
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                                  Handle<PropertyDescriptor> desc,
                                  ObjectOpResult& result) const
 {
-    FORWARD(defineProperty, (cx, proxy, id, desc, result));
+    FORWARD(defineProperty, (cx, proxy, id, desc, result), false);
 }
 
 bool
 WrapperOwner::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                              Handle<PropertyDescriptor> desc,
                              ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
@@ -252,30 +251,30 @@ WrapperOwner::defineProperty(JSContext* 
 
     return ok(cx, status, result);
 }
 
 bool
 CPOWProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
                                   AutoIdVector& props) const
 {
-    FORWARD(ownPropertyKeys, (cx, proxy, props));
+    FORWARD(ownPropertyKeys, (cx, proxy, props), false);
 }
 
 bool
 WrapperOwner::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
 {
     return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 bool
 CPOWProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
                           ObjectOpResult& result) const
 {
-    FORWARD(delete_, (cx, proxy, id, result));
+    FORWARD(delete_, (cx, proxy, id, result), false);
 }
 
 bool
 WrapperOwner::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
@@ -298,17 +297,17 @@ CPOWProxyHandler::enumerate(JSContext* c
     // call the base hook, that will use our implementation of getOwnEnumerablePropertyKeys
     // and follow the proto chain.
     return BaseProxyHandler::enumerate(cx, proxy);
 }
 
 bool
 CPOWProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
 {
-    FORWARD(has, (cx, proxy, id, bp));
+    FORWARD(has, (cx, proxy, id, bp), false);
 }
 
 bool
 WrapperOwner::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
@@ -322,17 +321,17 @@ WrapperOwner::has(JSContext* cx, HandleO
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
 {
-    FORWARD(hasOwn, (cx, proxy, id, bp));
+    FORWARD(hasOwn, (cx, proxy, id, bp), false);
 }
 
 bool
 WrapperOwner::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
@@ -347,30 +346,30 @@ WrapperOwner::hasOwn(JSContext* cx, Hand
 
     return !!ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                       HandleId id, MutableHandleValue vp) const
 {
-    FORWARD(get, (cx, proxy, receiver, id, vp));
+    FORWARD(get, (cx, proxy, receiver, id, vp), false);
 }
 
 static bool
 CPOWDOMQI(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) {
         JS_ReportErrorASCII(cx, "bad this object passed to special QI");
         return false;
     }
 
     RootedObject proxy(cx, &args.thisv().toObject());
-    FORWARD(DOMQI, (cx, proxy, args));
+    FORWARD(DOMQI, (cx, proxy, args), false);
 }
 
 static bool
 CPOWToString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject callee(cx, &args.callee());
     RootedValue cpowValue(cx);
@@ -378,17 +377,17 @@ CPOWToString(JSContext* cx, unsigned arg
         return false;
 
     if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) {
         JS_ReportErrorASCII(cx, "CPOWToString called on an incompatible object");
         return false;
     }
 
     RootedObject proxy(cx, &cpowValue.toObject());
-    FORWARD(toString, (cx, proxy, args));
+    FORWARD(toString, (cx, proxy, args), false);
 }
 
 bool
 WrapperOwner::toString(JSContext* cx, HandleObject cpow, JS::CallArgs& args)
 {
     // Ask the other side to call its toString method. Update the callee so that
     // it points to the CPOW and not to the synthesized CPOWToString function.
     args.setCallee(ObjectValue(*cpow));
@@ -525,17 +524,17 @@ WrapperOwner::get(JSContext* cx, HandleO
 
     return true;
 }
 
 bool
 CPOWProxyHandler::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
                       JS::HandleValue receiver, JS::ObjectOpResult& result) const
 {
-    FORWARD(set, (cx, proxy, id, v, receiver, result));
+    FORWARD(set, (cx, proxy, id, v, receiver, result), false);
 }
 
 bool
 WrapperOwner::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
                   JS::HandleValue receiver, JS::ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
 
@@ -559,29 +558,29 @@ WrapperOwner::set(JSContext* cx, JS::Han
 
     return ok(cx, status, result);
 }
 
 bool
 CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                                AutoIdVector& props) const
 {
-    FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props));
+    FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props), false);
 }
 
 bool
 WrapperOwner::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
 {
     return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool
 CPOWProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const
 {
-    FORWARD(preventExtensions, (cx, proxy, result));
+    FORWARD(preventExtensions, (cx, proxy, result), false);
 }
 
 bool
 WrapperOwner::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
@@ -591,17 +590,17 @@ WrapperOwner::preventExtensions(JSContex
     LOG_STACK();
 
     return ok(cx, status, result);
 }
 
 bool
 CPOWProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
 {
-    FORWARD(isExtensible, (cx, proxy, extensible));
+    FORWARD(isExtensible, (cx, proxy, extensible), false);
 }
 
 bool
 WrapperOwner::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
@@ -611,23 +610,23 @@ WrapperOwner::isExtensible(JSContext* cx
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
 {
-    FORWARD(callOrConstruct, (cx, proxy, args, false));
+    FORWARD(callOrConstruct, (cx, proxy, args, false), false);
 }
 
 bool
 CPOWProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
 {
-    FORWARD(callOrConstruct, (cx, proxy, args, true));
+    FORWARD(callOrConstruct, (cx, proxy, args, true), false);
 }
 
 bool
 WrapperOwner::callOrConstruct(JSContext* cx, HandleObject proxy, const CallArgs& args,
                               bool construct)
 {
     ObjectId objId = idOf(proxy);
 
@@ -700,17 +699,17 @@ WrapperOwner::callOrConstruct(JSContext*
         return false;
 
     return true;
 }
 
 bool
 CPOWProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const
 {
-    FORWARD(hasInstance, (cx, proxy, v, bp));
+    FORWARD(hasInstance, (cx, proxy, v, bp), false);
 }
 
 bool
 WrapperOwner::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp)
 {
     ObjectId objId = idOf(proxy);
 
     JSVariant vVar;
@@ -724,17 +723,17 @@ WrapperOwner::hasInstance(JSContext* cx,
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
 {
-    FORWARD(getBuiltinClass, (cx, proxy, cls));
+    FORWARD(getBuiltinClass, (cx, proxy, cls), false);
 }
 
 bool
 WrapperOwner::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls)
 {
     ObjectId objId = idOf(proxy);
 
     uint32_t classValue = uint32_t(ESClass::Other);
@@ -747,17 +746,17 @@ WrapperOwner::getBuiltinClass(JSContext*
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::isArray(JSContext* cx, HandleObject proxy,
                           IsArrayAnswer* answer) const
 {
-    FORWARD(isArray, (cx, proxy, answer));
+    FORWARD(isArray, (cx, proxy, answer), false);
 }
 
 bool
 WrapperOwner::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer)
 {
     ObjectId objId = idOf(proxy);
 
     uint32_t ans;
@@ -798,17 +797,17 @@ WrapperOwner::className(JSContext* cx, H
     }
 
     return data->className.get();
 }
 
 bool
 CPOWProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const
 {
-    FORWARD(getPrototype, (cx, proxy, objp));
+    FORWARD(getPrototype, (cx, proxy, objp), false);
 }
 
 bool
 WrapperOwner::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp)
 {
     ObjectId objId = idOf(proxy);
 
     ObjectOrNullVariant val;
@@ -825,17 +824,17 @@ WrapperOwner::getPrototype(JSContext* cx
 
     return true;
 }
 
 bool
 CPOWProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
                                          MutableHandleObject objp) const
 {
-    FORWARD(getPrototypeIfOrdinary, (cx, proxy, isOrdinary, objp));
+    FORWARD(getPrototypeIfOrdinary, (cx, proxy, isOrdinary, objp), false);
 }
 
 bool
 WrapperOwner::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
                                      MutableHandleObject objp)
 {
     ObjectId objId = idOf(proxy);
 
@@ -849,45 +848,45 @@ WrapperOwner::getPrototypeIfOrdinary(JSC
     if (!ok(cx, status))
         return false;
 
     objp.set(fromObjectOrNullVariant(cx, val));
 
     return true;
 }
 
-bool
-CPOWProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
-                                  MutableHandle<RegExpShared*> shared) const
+RegExpShared*
+CPOWProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
 {
-    FORWARD(regexp_toShared, (cx, proxy, shared));
+    FORWARD(regexp_toShared, (cx, proxy), nullptr);
 }
 
-bool
-WrapperOwner::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandle<RegExpShared*> shared)
+RegExpShared*
+WrapperOwner::regexp_toShared(JSContext* cx, HandleObject proxy)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
     nsString source;
     unsigned flags = 0;
-    if (!SendRegExpToShared(objId, &status, &source, &flags))
-        return ipcfail(cx);
-
+    if (!SendRegExpToShared(objId, &status, &source, &flags)) {
+        MOZ_ALWAYS_FALSE(ipcfail(cx));
+        return nullptr;
+    }
     LOG_STACK();
 
     if (!ok(cx, status))
-        return false;
+        return nullptr;
 
     RootedObject regexp(cx);
     regexp = JS_NewUCRegExpObject(cx, source.get(), source.Length(), flags);
     if (!regexp)
-        return false;
+        return nullptr;
 
-    return js::RegExpToSharedNonInline(cx, regexp, shared);
+    return js::RegExpToSharedNonInline(cx, regexp);
 }
 
 void
 CPOWProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
 {
     AuxCPOWData* aux = AuxCPOWDataOf(proxy);
 
     OwnerOf(proxy)->drop(proxy);
@@ -1010,17 +1009,17 @@ InstanceOf(JSObject* proxy, const nsID* 
         return NS_ERROR_UNEXPECTED;
     return parent->instanceOf(proxy, id, bp);
 }
 
 bool
 DOMInstanceOf(JSContext* cx, JSObject* proxyArg, int prototypeID, int depth, bool* bp)
 {
     RootedObject proxy(cx, proxyArg);
-    FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
+    FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp), false);
 }
 
 } /* namespace jsipc */
 } /* namespace mozilla */
 
 nsresult
 WrapperOwner::instanceOf(JSObject* obj, const nsID* id, bool* bp)
 {
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -55,18 +55,17 @@ class WrapperOwner : public virtual Java
     bool hasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp);
     bool getBuiltinClass(JSContext* cx, JS::HandleObject proxy, js::ESClass* cls);
     bool isArray(JSContext* cx, JS::HandleObject proxy, JS::IsArrayAnswer* answer);
     const char* className(JSContext* cx, JS::HandleObject proxy);
     bool getPrototype(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleObject protop);
     bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy, bool* isOrdinary,
                                 JS::MutableHandleObject protop);
 
-    bool regexp_toShared(JSContext* cx, JS::HandleObject proxy,
-                         js::MutableHandle<js::RegExpShared*> shared);
+    js::RegExpShared* regexp_toShared(JSContext* cx, JS::HandleObject proxy);
 
     nsresult instanceOf(JSObject* obj, const nsID* id, bool* bp);
 
     bool toString(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
     bool DOMQI(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
 
     /*
      * Check that |obj| is a DOM wrapper whose prototype chain contains
--- a/js/public/CharacterEncoding.h
+++ b/js/public/CharacterEncoding.h
@@ -227,43 +227,43 @@ LossyTwoByteCharsToNewLatin1CharsZ(JSCon
     const mozilla::Range<const char16_t> tbchars(begin, length);
     return JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars);
 }
 
 template <typename CharT>
 extern UTF8CharsZ
 CharsToNewUTF8CharsZ(JSContext* maybeCx, const mozilla::Range<CharT> chars);
 
-uint32_t
+JS_PUBLIC_API(uint32_t)
 Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length);
 
 /*
  * Inflate bytes in UTF-8 encoding to char16_t.
  * - On error, returns an empty TwoByteCharsZ.
  * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold
  *   its length;  the length value excludes the trailing null.
  */
-extern TwoByteCharsZ
+extern JS_PUBLIC_API(TwoByteCharsZ)
 UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
 
 /*
  * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ.
  */
-extern TwoByteCharsZ
+extern JS_PUBLIC_API(TwoByteCharsZ)
 UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen);
 
 /*
  * The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 characters
  * will be replaced by \uFFFD. No exception will be thrown for malformed UTF-8
  * input.
  */
-extern TwoByteCharsZ
+extern JS_PUBLIC_API(TwoByteCharsZ)
 LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
 
-extern TwoByteCharsZ
+extern JS_PUBLIC_API(TwoByteCharsZ)
 LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen);
 
 /*
  * Returns the length of the char buffer required to encode |s| as UTF8.
  * Does not include the null-terminator.
  */
 JS_PUBLIC_API(size_t)
 GetDeflatedUTF8StringLength(JSFlatString* s);
@@ -303,32 +303,32 @@ JS_PUBLIC_API(SmallestEncoding)
 FindSmallestEncoding(UTF8Chars utf8);
 
 /*
   * Return a null-terminated Latin-1 string copied from the input string,
   * storing its length (excluding null terminator) in |*outlen|.  Fail and
   * report an error if the string contains non-Latin-1 codepoints.  Returns
   * Latin1CharsZ() on failure.
  */
-extern Latin1CharsZ
+extern JS_PUBLIC_API(Latin1CharsZ)
 UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
 
 /*
  * Return a null-terminated Latin-1 string copied from the input string,
  * storing its length (excluding null terminator) in |*outlen|.  Non-Latin-1
  * codepoints are replaced by '?'.  Returns Latin1CharsZ() on failure.
  */
-extern Latin1CharsZ
+extern JS_PUBLIC_API(Latin1CharsZ)
 LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
 
 /*
  * Returns true if all characters in the given null-terminated string are
  * ASCII, i.e. < 0x80, false otherwise.
  */
-extern bool
+extern JS_PUBLIC_API(bool)
 StringIsASCII(const char* s);
 
 } // namespace JS
 
 inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); }
 inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); }
 
 #endif /* js_CharacterEncoding_h */
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -51,17 +51,17 @@ typedef enum JSGCInvocationKind {
 
 namespace JS {
 
 #define GCREASONS(D)                            \
     /* Reasons internal to the JS engine */     \
     D(API)                                      \
     D(EAGER_ALLOC_TRIGGER)                      \
     D(DESTROY_RUNTIME)                          \
-    D(UNUSED0)                                  \
+    D(ROOTS_REMOVED)                            \
     D(LAST_DITCH)                               \
     D(TOO_MUCH_MALLOC)                          \
     D(ALLOC_TRIGGER)                            \
     D(DEBUG_GC)                                 \
     D(COMPARTMENT_REVIVED)                      \
     D(RESET)                                    \
     D(OUT_OF_NURSERY)                           \
     D(EVICT_NURSERY)                            \
@@ -697,21 +697,19 @@ static MOZ_ALWAYS_INLINE void
 ExposeScriptToActiveJS(JSScript* script)
 {
     MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&script));
     js::gc::ExposeGCThingToActiveJS(GCCellPtr(script));
 }
 
 /*
  * Internal to Firefox.
- *
- * Note: this is not related to the PokeGC in nsJSEnvironment.
  */
 extern JS_FRIEND_API(void)
-PokeGC(JSContext* cx);
+NotifyGCRootsRemoved(JSContext* cx);
 
 /*
  * Internal to Firefox.
  */
 extern JS_FRIEND_API(void)
 NotifyDidPaint(JSContext* cx);
 
 } /* namespace JS */
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -405,16 +405,19 @@ static MOZ_ALWAYS_INLINE Zone*
 GetStringZone(JSString* str)
 {
     return js::gc::detail::GetGCThingZone(uintptr_t(str));
 }
 
 extern JS_PUBLIC_API(Zone*)
 GetObjectZone(JSObject* obj);
 
+extern JS_PUBLIC_API(Zone*)
+GetValueZone(const Value& value);
+
 static MOZ_ALWAYS_INLINE bool
 GCThingIsMarkedGray(GCCellPtr thing)
 {
     if (thing.mayBeOwnedByOtherRuntime())
         return false;
     return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell());
 }
 
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -175,16 +175,23 @@ struct GCPolicy<jsid>
 
 } // namespace JS
 
 namespace js {
 
 template <>
 struct BarrierMethods<jsid>
 {
+    static gc::Cell* asGCThingOrNull(jsid id) {
+        if (JSID_IS_STRING(id))
+            return reinterpret_cast<gc::Cell*>(JSID_TO_STRING(id));
+        if (JSID_IS_SYMBOL(id))
+            return reinterpret_cast<gc::Cell*>(JSID_TO_SYMBOL(id));
+        return nullptr;
+    }
     static void postBarrier(jsid* idp, jsid prev, jsid next) {}
     static void exposeToJS(jsid id) {
         if (JSID_IS_GCTHING(id))
             js::gc::ExposeGCThingToActiveJS(JSID_TO_GCTHING(id));
     }
 };
 
 // If the jsid is a GC pointer type, convert to that type and call |f| with
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -326,18 +326,17 @@ class JS_FRIEND_API(BaseProxyHandler)
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
                                  ESClass* cls) const;
     virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const;
     virtual const char* className(JSContext* cx, HandleObject proxy) const;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<js::RegExpShared*> shared) const;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const;
     virtual void trace(JSTracer* trc, JSObject* proxy) const;
     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const;
     virtual void objectMoved(JSObject* proxy, const JSObject* old) const;
 
     // Allow proxies, wrappers in particular, to specify callability at runtime.
     // Note: These do not take const JSObject*, but they do in spirit.
     //       We are not prepared to do this, as there's little const correctness
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -332,38 +332,59 @@ class MOZ_RAII AutoTracingDetails
 
 JS::CallbackTracer*
 JSTracer::asCallbackTracer()
 {
     MOZ_ASSERT(isCallbackTracer());
     return static_cast<JS::CallbackTracer*>(this);
 }
 
+namespace js {
+namespace gc {
+template <typename T>
+JS_PUBLIC_API(void) TraceExternalEdge(JSTracer* trc, T* thingp, const char* name);
+} // namespace gc
+} // namespace js
+
 namespace JS {
 
 // The JS::TraceEdge family of functions traces the given GC thing reference.
 // This performs the tracing action configured on the given JSTracer: typically
 // calling the JSTracer::callback or marking the thing as live.
 //
 // The argument to JS::TraceEdge is an in-out param: when the function returns,
 // the garbage collector might have moved the GC thing. In this case, the
 // reference passed to JS::TraceEdge will be updated to the thing's new
 // location. Callers of this method are responsible for updating any state that
 // is dependent on the object's address. For example, if the object's address
 // is used as a key in a hashtable, then the object must be removed and
 // re-inserted with the correct hash.
 //
 // Note that while |edgep| must never be null, it is fine for |*edgep| to be
 // nullptr.
+
 template <typename T>
-extern JS_PUBLIC_API(void)
-TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
+inline void
+TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
+{
+    MOZ_ASSERT(thingp);
+    if (*thingp)
+        js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name);
+}
 
-extern JS_PUBLIC_API(void)
-TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
+template <typename T>
+inline void
+TraceEdge(JSTracer* trc, JS::TenuredHeap<T>* thingp, const char* name)
+{
+    MOZ_ASSERT(thingp);
+    if (T ptr = thingp->unbarrieredGetPtr()) {
+        js::gc::TraceExternalEdge(trc, &ptr, name);
+        thingp->setPtr(ptr);
+    }
+}
 
 // Edges that are always traced as part of root marking do not require
 // incremental barriers. This function allows for marking non-barriered
 // pointers, but asserts that this happens during root marking.
 //
 // Note that while |edgep| must never be null, it is fine for |*edgep| to be
 // nullptr.
 template <typename T>
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -73,17 +73,17 @@ enum ThreadType {
 
 /*
  * Getter/Setter functions to encapsulate mozilla::ThreadLocal,
  * implementation is in jsutil.cpp.
  */
 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
 extern bool InitThreadType(void);
 extern void SetThreadType(ThreadType);
-extern uint32_t GetThreadType(void);
+extern JS_FRIEND_API(uint32_t) GetThreadType(void);
 # else
 inline bool InitThreadType(void) { return true; }
 inline void SetThreadType(ThreadType t) {};
 inline uint32_t GetThreadType(void) { return 0; }
 # endif
 
 } /* namespace oom */
 } /* namespace js */
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -141,18 +141,18 @@ ExecuteRegExpImpl(JSContext* cx, RegExpS
 }
 
 /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */
 bool
 js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj,
                         HandleLinearString input, size_t* lastIndex, bool test,
                         MutableHandleValue rval)
 {
-    RootedRegExpShared shared(cx);
-    if (!RegExpObject::getShared(cx, reobj, &shared))
+    RootedRegExpShared shared(cx, RegExpObject::getShared(cx, reobj));
+    if (!shared)
         return false;
 
     ScopedMatchPairs matches(&cx->tempLifoAlloc());
 
     RegExpRunStatus status = ExecuteRegExpImpl(cx, res, &shared, input, *lastIndex,
                                                &matches, nullptr);
     if (status == RegExpRunStatus_Error)
         return false;
@@ -229,18 +229,18 @@ RegExpInitializeIgnoringLastIndex(JSCont
 
         /* Step 5. */
         if (!ParseRegExpFlags(cx, flagStr, &flags))
             return false;
     }
 
     if (sharedUse == UseRegExpShared) {
         /* Steps 7-8. */
-        RootedRegExpShared re(cx);
-        if (!cx->zone()->regExps.get(cx, pattern, flags, &re))
+        RegExpShared* re = cx->zone()->regExps.get(cx, pattern, flags);
+        if (!re)
             return false;
 
         /* Steps 9-12. */
         obj->initIgnoringLastIndex(pattern, flags);
 
         obj->setShared(*re);
     } else {
         /* Steps 7-8. */
@@ -335,22 +335,22 @@ regexp_compile_impl(JSContext* cx, const
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
         // don't reuse the RegExpShared below.
         RootedObject patternObj(cx, &patternValue.toObject());
 
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
             // Step 3b.
-            RootedRegExpShared g(cx);
-            if (!RegExpToShared(cx, patternObj, &g))
+            RegExpShared* shared = RegExpToShared(cx, patternObj);
+            if (!shared)
                 return false;
 
-            sourceAtom = g->getSource();
-            flags = g->getFlags();
+            sourceAtom = shared->getSource();
+            flags = shared->getFlags();
         }
 
         // Step 5, minus lastIndex zeroing.
         regexp->initIgnoringLastIndex(sourceAtom, flags);
     } else {
         // Step 4.
         RootedValue P(cx, patternValue);
         RootedValue F(cx, args.get(1));
@@ -430,24 +430,24 @@ js::regexp_construct(JSContext* cx, unsi
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
         // don't reuse the RegExpShared below.
         RootedObject patternObj(cx, &patternValue.toObject());
 
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
             // Step 4.a.
-            RootedRegExpShared g(cx);
-            if (!RegExpToShared(cx, patternObj, &g))
+            RegExpShared* shared = RegExpToShared(cx, patternObj);
+            if (!shared)
                 return false;
-            sourceAtom = g->getSource();
+            sourceAtom = shared->getSource();
 
             // Step 4.b.
             // Get original flags in all cases, to compare with passed flags.
-            flags = g->getFlags();
+            flags = shared->getFlags();
         }
 
         // Step 7.
         RootedObject proto(cx);
         if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
             return false;
 
         Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, GenericObject, proto));
@@ -894,18 +894,18 @@ ExecuteRegExp(JSContext* cx, HandleObjec
      * WARNING: Despite the presence of spec step comment numbers, this
      *          algorithm isn't consistent with any ES6 version, draft or
      *          otherwise.  YOU HAVE BEEN WARNED.
      */
 
     /* Steps 1-2 performed by the caller. */
     Rooted<RegExpObject*> reobj(cx, &regexp->as<RegExpObject>());
 
-    RootedRegExpShared re(cx);
-    if (!RegExpObject::getShared(cx, reobj, &re))
+    RootedRegExpShared re(cx, RegExpObject::getShared(cx, reobj));
+    if (!re)
         return RegExpRunStatus_Error;
 
     RegExpStatics* res;
     if (staticsUpdate == UpdateRegExpStatics) {
         res = GlobalObject::getRegExpStatics(cx, cx->global());
         if (!res)
             return RegExpRunStatus_Error;
     } else {
--- a/js/src/devtools/automation/cgc-jittest-timeouts.txt
+++ b/js/src/devtools/automation/cgc-jittest-timeouts.txt
@@ -1,9 +1,10 @@
 SIMD/nursery-overflow.js
+asm.js/testBug1117235.js
 asm.js/testParallelCompile.js
 auto-regress/bug653395.js
 auto-regress/bug654392.js
 auto-regress/bug675251.js
 auto-regress/bug729797.js
 baseline/bug847446.js
 baseline/bug852175.js
 basic/bug632964-regexp.js
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -228,16 +228,18 @@ var ignoreFunctions = {
     "iJIT_IsProfilingActive" : true,
     "iJIT_NotifyEvent": true,
 
     // The big hammers.
     "PR_GetCurrentThread" : true,
     "calloc" : true,
 
     "uint8 nsContentUtils::IsExpandedPrincipal(nsIPrincipal*)" : true,
+
+    "void mozilla::AutoProfilerLabel::~AutoProfilerLabel(int32)" : true,
 };
 
 function extraGCFunctions() {
     return ["ffi_call"];
 }
 
 function isProtobuf(name)
 {
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -711,17 +711,17 @@ class GCRuntime
 
     void triggerFullGCForAtoms() {
         MOZ_ASSERT(fullGCForAtomsRequested_);
         fullGCForAtomsRequested_ = false;
         MOZ_RELEASE_ASSERT(triggerGC(JS::gcreason::ALLOC_TRIGGER));
     }
 
     void runDebugGC();
-    inline void poke();
+    void notifyRootsRemoved();
 
     enum TraceOrMarkRuntime {
         TraceRuntime,
         MarkRuntime
     };
     void traceRuntime(JSTracer* trc, AutoLockForExclusiveAccess& lock);
     void traceRuntimeForMinorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock);
 
@@ -1298,33 +1298,34 @@ class GCRuntime
      */
     ActiveThreadData<bool> incrementalAllowed;
 
     /*
      * Whether compacting GC can is enabled globally.
      */
     ActiveThreadData<bool> compactingEnabled;
 
-    ActiveThreadData<bool> poked;
+    ActiveThreadData<bool> rootsRemoved;
 
     /*
      * These options control the zealousness of the GC. At every allocation,
      * nextScheduled is decremented. When it reaches zero we do a full GC.
      *
      * At this point, if zeal_ is one of the types that trigger periodic
      * collection, then nextScheduled is reset to the value of zealFrequency.
      * Otherwise, no additional GCs take place.
      *
      * You can control these values in several ways:
      *   - Set the JS_GC_ZEAL environment variable
      *   - Call gczeal() or schedulegc() from inside shell-executed JS code
      *     (see the help for details)
      *
      * If gcZeal_ == 1 then we perform GCs in select places (during MaybeGC and
-     * whenever a GC poke happens). This option is mainly useful to embedders.
+     * whenever we are notified that GC roots have been removed). This option is
+     * mainly useful to embedders.
      *
      * We use zeal_ == 4 to enable write barrier verification. See the comment
      * in jsgc.cpp for more information about this.
      *
      * zeal_ values from 8 to 10 periodically run different types of
      * incremental GC.
      *
      * zeal_ value 14 performs periodic shrinking collections.
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -450,31 +450,20 @@ void
 js::TraceNullableEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
 {
     if (InternalBarrierMethods<T>::isMarkable(thingp->unbarrieredGet()))
         DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
 }
 
 template <typename T>
 JS_PUBLIC_API(void)
-JS::TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
+js::gc::TraceExternalEdge(JSTracer* trc, T* thingp, const char* name)
 {
-    MOZ_ASSERT(thingp);
-    if (InternalBarrierMethods<T>::isMarkable(*thingp->unsafeGet()))
-        DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
-}
-
-JS_PUBLIC_API(void)
-JS::TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* thingp, const char* name)
-{
-    MOZ_ASSERT(thingp);
-    if (JSObject* ptr = thingp->unbarrieredGetPtr()) {
-        DispatchToTracer(trc, &ptr, name);
-        thingp->setPtr(ptr);
-    }
+    MOZ_ASSERT(InternalBarrierMethods<T>::isMarkable(*thingp));
+    DispatchToTracer(trc, ConvertToBase(thingp), name);
 }
 
 template <typename T>
 void
 js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
 {
     DispatchToTracer(trc, ConvertToBase(thingp), name);
 }
@@ -578,20 +567,20 @@ js::TraceRootRange(JSTracer* trc, size_t
     template void js::TraceNullableRoot<type>(JSTracer*, type*, const char*); \
     template void js::TraceNullableRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
     template void js::TraceRange<type>(JSTracer*, size_t, WriteBarrieredBase<type>*, const char*); \
     template void js::TraceRootRange<type>(JSTracer*, size_t, type*, const char*);
 FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
 #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
 
 #define INSTANTIATE_PUBLIC_TRACE_FUNCTIONS(type) \
-    template JS_PUBLIC_API(void) JS::TraceEdge<type>(JSTracer*, JS::Heap<type>*, const char*); \
     template JS_PUBLIC_API(void) JS::UnsafeTraceRoot<type>(JSTracer*, type*, const char*); \
     template JS_PUBLIC_API(void) js::UnsafeTraceManuallyBarrieredEdge<type>(JSTracer*, type*, \
-                                                                            const char*);
+                                                                            const char*); \
+    template JS_PUBLIC_API(void) js::gc::TraceExternalEdge<type>(JSTracer*, type*, const char*);
 FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
 FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
 #undef INSTANTIATE_PUBLIC_TRACE_FUNCTIONS
 
 template <typename T>
 void
 js::TraceManuallyBarrieredCrossCompartmentEdge(JSTracer* trc, JSObject* src, T* dst,
                                                const char* name)
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -437,22 +437,31 @@ js::gc::GCRuntime::finishRoots()
     // Restore the wrapper tracing so that we leak instead of leaving dangling
     // pointers.
     grayRootTracer = prior;
 #endif // DEBUG
 }
 
 // Append traced things to a buffer on the zone for use later in the GC.
 // See the comment in GCRuntime.h above grayBufferState for details.
-class BufferGrayRootsTracer : public JS::CallbackTracer
+class BufferGrayRootsTracer final : public JS::CallbackTracer
 {
     // Set to false if we OOM while buffering gray roots.
     bool bufferingGrayRootsFailed;
 
-    void onChild(const JS::GCCellPtr& thing) override;
+    void onObjectEdge(JSObject** objp) override { bufferRoot(*objp); }
+    void onStringEdge(JSString** stringp) override { bufferRoot(*stringp); }
+    void onScriptEdge(JSScript** scriptp) override { bufferRoot(*scriptp); }
+    void onSymbolEdge(JS::Symbol** symbolp) override { bufferRoot(*symbolp); }
+
+    void onChild(const JS::GCCellPtr& thing) override {
+        MOZ_CRASH("Unexpected gray root kind");
+    }
+
+    template <typename T> inline void bufferRoot(T* thing);
 
   public:
     explicit BufferGrayRootsTracer(JSRuntime* rt)
       : JS::CallbackTracer(rt), bufferingGrayRootsFailed(false)
     {}
 
     bool failed() const { return bufferingGrayRootsFailed; }
 
@@ -489,42 +498,36 @@ js::gc::GCRuntime::bufferGrayRoots()
     if (grayBufferer.failed()) {
       grayBufferState = GrayBufferState::Failed;
       resetBufferedGrayRoots();
     } else {
       grayBufferState = GrayBufferState::Okay;
     }
 }
 
-struct SetMaybeAliveFunctor {
-    template <typename T> void operator()(T* t) { SetMaybeAliveFlag(t); }
-};
-
-void
-BufferGrayRootsTracer::onChild(const JS::GCCellPtr& thing)
+template <typename T>
+inline void
+BufferGrayRootsTracer::bufferRoot(T* thing)
 {
     MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
-    MOZ_RELEASE_ASSERT(thing);
+    MOZ_ASSERT(thing);
     // Check if |thing| is corrupt by calling a method that touches the heap.
-    MOZ_RELEASE_ASSERT(thing.asCell()->getTraceKind() <= JS::TraceKind::Null);
+    MOZ_ASSERT(thing->getTraceKind() <= JS::TraceKind::Null);
 
-    if (bufferingGrayRootsFailed)
-        return;
-
-    gc::TenuredCell* tenured = gc::TenuredCell::fromPointer(thing.asCell());
+    TenuredCell* tenured = &thing->asTenured();
 
     // This is run from a helper thread while the mutator is paused so we have
     // to use *FromAnyThread methods here.
     Zone* zone = tenured->zoneFromAnyThread();
     if (zone->isCollectingFromAnyThread()) {
         // See the comment on SetMaybeAliveFlag to see why we only do this for
         // objects and scripts. We rely on gray root buffering for this to work,
         // but we only need to worry about uncollected dead compartments during
         // incremental GCs (when we do gray root buffering).
-        DispatchTyped(SetMaybeAliveFunctor(), thing);
+        SetMaybeAliveFlag(thing);
 
         if (!zone->gcGrayRoots().append(tenured))
             bufferingGrayRootsFailed = true;
     }
 }
 
 void
 GCRuntime::markBufferedGrayRoots(JS::Zone* zone)
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1911,16 +1911,17 @@ BaselineCacheIRCompiler::init(CacheKind 
     AllocatableGeneralRegisterSet available(ICStubCompiler::availableGeneralRegs(numInputsInRegs));
 
     switch (kind) {
       case CacheKind::GetProp:
       case CacheKind::TypeOf:
         MOZ_ASSERT(numInputs == 1);
         allocator.initInputLocation(0, R0);
         break;
+      case CacheKind::Compare:
       case CacheKind::GetElem:
       case CacheKind::GetPropSuper:
       case CacheKind::SetProp:
       case CacheKind::In:
       case CacheKind::HasOwn:
         MOZ_ASSERT(numInputs == 2);
         allocator.initInputLocation(0, R0);
         allocator.initInputLocation(1, R1);
@@ -1981,16 +1982,17 @@ jit::AttachBaselineCacheIRStub(JSContext
     // unlimited number of stubs.
     MOZ_ASSERT(stub->numOptimizedStubs() < MaxOptimizedCacheIRStubs);
 
     enum class CacheIRStubKind { Regular, Monitored, Updated };
 
     uint32_t stubDataOffset;
     CacheIRStubKind stubKind;
     switch (kind) {
+      case CacheKind::Compare:
       case CacheKind::In:
       case CacheKind::HasOwn:
       case CacheKind::BindName:
       case CacheKind::TypeOf:
         stubDataOffset = sizeof(ICCacheIR_Regular);
         stubKind = CacheIRStubKind::Regular;
         break;
       case CacheKind::GetProp:
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -3691,8 +3691,88 @@ CallIRGenerator::tryAttachStub()
 
     if (strategy == OptStrategy::StringSplit) {
         return tryAttachStringSplit();
     }
 
     MOZ_ASSERT(strategy == OptStrategy::None);
     return false;
 }
+
+CompareIRGenerator::CompareIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
+                                       ICState::Mode mode, JSOp op,
+                                       HandleValue lhsVal, HandleValue rhsVal)
+  : IRGenerator(cx, script, pc, CacheKind::Compare, mode),
+    op_(op), lhsVal_(lhsVal), rhsVal_(rhsVal)
+{ }
+
+bool
+CompareIRGenerator::tryAttachString(ValOperandId lhsId, ValOperandId rhsId)
+{
+    MOZ_ASSERT(IsEqualityOp(op_));
+
+    if (!lhsVal_.isString() || !rhsVal_.isString())
+        return false;
+
+    StringOperandId lhsStrId = writer.guardIsString(lhsId);
+    StringOperandId rhsStrId = writer.guardIsString(rhsId);
+    writer.compareStringResult(op_, lhsStrId, rhsStrId);
+    writer.returnFromIC();
+
+    trackAttached("String");
+    return true;
+}
+
+bool
+CompareIRGenerator::tryAttachStub()
+{
+    MOZ_ASSERT(cacheKind_ == CacheKind::Compare);
+    MOZ_ASSERT(IsEqualityOp(op_) ||
+               op_ == JSOP_LE || op_ == JSOP_LT ||
+               op_ == JSOP_GE || op_ == JSOP_GT);
+
+    AutoAssertNoPendingException aanpe(cx_);
+
+    ValOperandId lhsId(writer.setInputOperandId(0));
+    ValOperandId rhsId(writer.setInputOperandId(1));
+
+    if (IsEqualityOp(op_)) {
+        if (tryAttachString(lhsId, rhsId))
+            return true;
+
+        trackNotAttached();
+        return false;
+    }
+
+    trackNotAttached();
+    return false;
+}
+
+void
+CompareIRGenerator::trackAttached(const char* name)
+{
+#ifdef JS_CACHEIR_SPEW
+    CacheIRSpewer& sp = CacheIRSpewer::singleton();
+    if (sp.enabled()) {
+        LockGuard<Mutex> guard(sp.lock());
+        sp.beginCache(guard, *this);
+        sp.valueProperty(guard, "lhs", lhsVal_);
+        sp.valueProperty(guard, "rhs", rhsVal_);
+        sp.attached(guard, name);
+        sp.endCache(guard);
+    }
+#endif
+}
+
+void
+CompareIRGenerator::trackNotAttached()
+{
+#ifdef JS_CACHEIR_SPEW
+    CacheIRSpewer& sp = CacheIRSpewer::singleton();
+    if (sp.enabled()) {
+        LockGuard<Mutex> guard(sp.lock());
+        sp.beginCache(guard, *this);
+        sp.valueProperty(guard, "lhs", lhsVal_);
+        sp.valueProperty(guard, "rhs", rhsVal_);
+        sp.endCache(guard);
+    }
+#endif
+}
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -140,16 +140,17 @@ class TypedOperandId : public OperandId
     _(GetPropSuper)         \
     _(GetElemSuper)         \
     _(SetProp)              \
     _(SetElem)              \
     _(BindName)             \
     _(In)                   \
     _(HasOwn)               \
     _(TypeOf)               \
+    _(Compare)              \
     _(Call)
 
 enum class CacheKind : uint8_t
 {
 #define DEFINE_KIND(kind) kind,
     CACHE_IR_KINDS(DEFINE_KIND)
 #undef DEFINE_KIND
 };
@@ -251,16 +252,19 @@ extern const char* CacheKindNames[];
     _(CallProxyGetByValueResult)          \
     _(CallProxyHasOwnResult)              \
     _(LoadUndefinedResult)                \
     _(LoadBooleanResult)                  \
     _(LoadStringResult)                   \
     _(LoadTypeOfObjectResult)             \
                                           \
     _(CallStringSplitResult)              \
+                                          \
+    _(CompareStringResult)                \
+                                          \
     _(CallPrintString)                    \
     _(Breakpoint)                         \
                                           \
     _(TypeMonitorResult)                  \
     _(ReturnFromIC)                       \
     _(WrapResult)
 
 enum class CacheOp {
@@ -949,16 +953,22 @@ class MOZ_RAII CacheIRWriter : public JS
 
     void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) {
         writeOp(CacheOp::CallStringSplitResult);
         writeOperandId(str);
         writeOperandId(sep);
         addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
     }
 
+    void compareStringResult(uint32_t op, StringOperandId lhs, StringOperandId rhs) {
+        writeOpWithOperandId(CacheOp::CompareStringResult, lhs);
+        writeOperandId(rhs);
+        buffer_.writeByte(uint32_t(op));
+    }
+
     void callPrintString(const char* str) {
         writeOp(CacheOp::CallPrintString);
         writePointer(const_cast<char*>(str));
     }
     void breakpoint() {
         writeOp(CacheOp::Breakpoint);
     }
 
@@ -1006,16 +1016,17 @@ class MOZ_RAII CacheIRReader
 
     uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
     GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
     JSValueType valueType() { return JSValueType(buffer_.readByte()); }
     TypedThingLayout typedThingLayout() { return TypedThingLayout(buffer_.readByte()); }
     Scalar::Type scalarType() { return Scalar::Type(buffer_.readByte()); }
     uint32_t typeDescrKey() { return buffer_.readByte(); }
     JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); }
+    JSOp jsop() { return JSOp(buffer_.readByte()); }
     int32_t int32Immediate() { return buffer_.readSigned(); }
     uint32_t uint32Immediate() { return buffer_.readUnsigned(); }
     void* pointer() { return buffer_.readRawPointer(); }
 
     ReferenceTypeDescr::Type referenceTypeDescrType() {
         return ReferenceTypeDescr::Type(buffer_.readByte());
     }
 
@@ -1409,12 +1420,30 @@ class MOZ_RAII CallIRGenerator : public 
     CallIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
                     uint32_t argc, HandleValue callee, HandleValue thisval,
                     HandleValueArray args);
 
     OptStrategy getOptStrategy(bool* optimizeAfterCall = nullptr);
     bool tryAttachStub();
 };
 
+class MOZ_RAII CompareIRGenerator : public IRGenerator
+{
+    JSOp op_;
+    HandleValue lhsVal_;
+    HandleValue rhsVal_;
+
+    bool tryAttachString(ValOperandId lhsId, ValOperandId rhsId);
+
+    void trackAttached(const char* name);
+    void trackNotAttached();
+
+  public:
+    CompareIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
+                       JSOp op, HandleValue lhsVal, HandleValue rhsVal);
+
+    bool tryAttachStub();
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_CacheIR_h */
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -2222,16 +2222,36 @@ CacheIRCompiler::emitLoadTypeOfObjectRes
         masm.tagValue(JSVAL_TYPE_STRING, scratch, output.valueReg());
     }
 
     masm.bind(&done);
     return true;
 }
 
 bool
+CacheIRCompiler::emitCompareStringResult()
+{
+    AutoOutputRegister output(*this);
+
+    Register left = allocator.useRegister(masm, reader.stringOperandId());
+    Register right = allocator.useRegister(masm, reader.stringOperandId());
+    JSOp op = reader.jsop();
+
+    AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.compareStrings(op, left, right, scratch, failure->label());
+    masm.tagValue(JSVAL_TYPE_BOOLEAN, scratch, output.valueReg());
+    return true;
+}
+
+bool
 CacheIRCompiler::emitCallPrintString()
 {
     const char* str = reinterpret_cast<char*>(reader.pointer());
     masm.printf(str);
     return true;
 }
 
 bool
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -50,16 +50,17 @@ namespace jit {
     _(LoadDenseElementResult)             \
     _(LoadDenseElementHoleResult)         \
     _(LoadDenseElementExistsResult)       \
     _(LoadDenseElementHoleExistsResult)   \
     _(LoadUnboxedArrayElementResult)      \
     _(LoadTypedElementResult)             \
     _(LoadObjectResult)                   \
     _(LoadTypeOfObjectResult)             \
+    _(CompareStringResult)                \
     _(CallPrintString)                    \
     _(Breakpoint)                         \
     _(MegamorphicLoadSlotByValueResult)   \
     _(MegamorphicHasOwnResult)            \
     _(WrapResult)
 
 // Represents a Value on the Baseline frame's expression stack. Slot 0 is the
 // value on top of the stack (the most recently pushed value), slot 1 is the
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -281,16 +281,17 @@ CodeGenerator::visitOutOfLineICFallback(
 
         StoreRegisterTo(hasOwnIC->output()).generate(this);
         restoreLiveIgnore(lir, StoreRegisterTo(hasOwnIC->output()).clobbered());
 
         masm.jump(ool->rejoin());
         return;
       }
       case CacheKind::Call:
+      case CacheKind::Compare:
       case CacheKind::TypeOf:
       case CacheKind::GetPropSuper:
       case CacheKind::GetElemSuper:
         MOZ_CRASH("Unsupported IC");
     }
     MOZ_CRASH();
 }
 
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -465,16 +465,17 @@ IonCacheIRCompiler::init()
         outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Boolean, AnyRegister(output)));
 
         MOZ_ASSERT(numInputs == 2);
         allocator.initInputLocation(0, ic->id());
         allocator.initInputLocation(1, ic->value());
         break;
       }
       case CacheKind::Call:
+      case CacheKind::Compare:
       case CacheKind::TypeOf:
       case CacheKind::GetPropSuper:
       case CacheKind::GetElemSuper:
         MOZ_CRASH("Unsupported IC");
     }
 
     if (liveRegs_)
         liveFloatRegs_ = LiveFloatRegisterSet(liveRegs_->fpus());
--- a/js/src/jit/IonIC.cpp
+++ b/js/src/jit/IonIC.cpp
@@ -48,16 +48,17 @@ IonIC::scratchRegisterForEntryJump()
         return asGetNameIC()->temp();
       case CacheKind::BindName:
         return asBindNameIC()->temp();
       case CacheKind::In:
         return asInIC()->temp();
       case CacheKind::HasOwn:
         return asHasOwnIC()->output();
       case CacheKind::Call:
+      case CacheKind::Compare:
       case CacheKind::TypeOf:
       case CacheKind::GetPropSuper:
       case CacheKind::GetElemSuper:
         MOZ_CRASH("Unsupported IC");
     }
 
     MOZ_CRASH("Invalid kind");
 }
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -1400,17 +1400,17 @@ DoCompareFallback(JSContext* cx, void* p
 
     // Don't pass lhs/rhs directly, we need the original values when
     // generating stubs.
     RootedValue lhsCopy(cx, lhs);
     RootedValue rhsCopy(cx, rhs);
 
     // Perform the compare operation.
     bool out;
-    switch(op) {
+    switch (op) {
       case JSOP_LT:
         if (!LessThan(cx, &lhsCopy, &rhsCopy, &out))
             return false;
         break;
       case JSOP_LE:
         if (!LessThanOrEqual(cx, &lhsCopy, &rhsCopy, &out))
             return false;
         break;
@@ -1451,16 +1451,29 @@ DoCompareFallback(JSContext* cx, void* p
 
     // Check to see if a new stub should be generated.
     if (stub->numOptimizedStubs() >= ICCompare_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
         // But for now we just bail.
         return true;
     }
 
+    if (engine ==  ICStubEngine::Baseline) {
+        RootedScript script(cx, info.outerScript(cx));
+        CompareIRGenerator gen(cx, script, pc, stub->state().mode(), op, lhs, rhs);
+        bool attached = false;
+        if (gen.tryAttachStub()) {
+            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
+                                                        engine, script, stub, &attached);
+            if (newStub)
+                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
+            return true;
+        }
+    }
+
     // Try to generate new stubs.
     if (lhs.isInt32() && rhs.isInt32()) {
         JitSpew(JitSpew_BaselineIC, "  Generating %s(Int32, Int32) stub", CodeName[op]);
         ICCompare_Int32::Compiler compiler(cx, op, engine);
         ICStub* int32Stub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));
         if (!int32Stub)
             return false;
 
--- a/js/src/jsalloc.h
+++ b/js/src/jsalloc.h
@@ -12,24 +12,25 @@
  */
 
 #ifndef jsalloc_h
 #define jsalloc_h
 
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
+extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx);
+
 namespace js {
 
 enum class AllocFunction {
     Malloc,
     Calloc,
     Realloc
 };
-
 /* Policy for using system memory functions and doing no error reporting. */
 class SystemAllocPolicy
 {
   public:
     template <typename T> T* maybe_pod_malloc(size_t numElems) { return js_pod_malloc<T>(numElems); }
     template <typename T> T* maybe_pod_calloc(size_t numElems) { return js_pod_calloc<T>(numElems); }
     template <typename T> T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
         return js_pod_realloc<T>(p, oldSize, newSize);
--- a/js/src/jsapi-tests/testGCHooks.cpp
+++ b/js/src/jsapi-tests/testGCHooks.cpp
@@ -1,40 +1,99 @@
 /* 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/TimeStamp.h"
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/UniquePtr.h"
 
 #include "js/GCAPI.h"
 
 #include "jsapi-tests/tests.h"
 
 static unsigned gSliceCallbackCount = 0;
 
 static void
 NonIncrementalGCSliceCallback(JSContext* cx, JS::GCProgress progress, const JS::GCDescription& desc)
 {
     using namespace JS;
     static GCProgress expect[] =
         { GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_CYCLE_END };
 
+    MOZ_RELEASE_ASSERT(gSliceCallbackCount < mozilla::ArrayLength(expect));
     MOZ_RELEASE_ASSERT(progress == expect[gSliceCallbackCount++]);
     MOZ_RELEASE_ASSERT(desc.isZone_ == false);
     MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
     MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API);
     if (progress == GC_CYCLE_END) {
         mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
         mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
         mozilla::UniquePtr<char16_t> json(desc.formatJSON(cx, 0));
     }
 }
 
 BEGIN_TEST(testGCSliceCallback)
 {
+    gSliceCallbackCount = 0;
     JS::SetGCSliceCallback(cx, NonIncrementalGCSliceCallback);
     JS_GC(cx);
     JS::SetGCSliceCallback(cx, nullptr);
     CHECK(gSliceCallbackCount == 4);
     return true;
 }
 END_TEST(testGCSliceCallback)
+
+static void
+RootsRemovedGCSliceCallback(JSContext* cx, JS::GCProgress progress, const JS::GCDescription& desc)
+{
+    using namespace JS;
+    using namespace JS::gcreason;
+
+    static GCProgress expectProgress[] = {
+        GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_SLICE_BEGIN, GC_SLICE_END, GC_CYCLE_END,
+        GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_CYCLE_END
+    };
+
+    static Reason expectReasons[] = {
+        DEBUG_GC, DEBUG_GC, DEBUG_GC, DEBUG_GC, DEBUG_GC, DEBUG_GC,
+        ROOTS_REMOVED, ROOTS_REMOVED, ROOTS_REMOVED, ROOTS_REMOVED
+    };
+
+    static_assert(mozilla::ArrayLength(expectProgress) == mozilla::ArrayLength(expectReasons),
+                  "expectProgress and expectReasons arrays should be the same length");
+
+    MOZ_RELEASE_ASSERT(gSliceCallbackCount < mozilla::ArrayLength(expectProgress));
+    MOZ_RELEASE_ASSERT(progress == expectProgress[gSliceCallbackCount]);
+    MOZ_RELEASE_ASSERT(desc.isZone_ == false);
+    MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_SHRINK);
+    MOZ_RELEASE_ASSERT(desc.reason_ == expectReasons[gSliceCallbackCount]);
+    gSliceCallbackCount++;
+}
+
+BEGIN_TEST(testGCRootsRemoved)
+{
+    JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
+
+    gSliceCallbackCount = 0;
+    JS::SetGCSliceCallback(cx, RootsRemovedGCSliceCallback);
+
+    JS::RootedObject obj(cx, JS_NewPlainObject(cx));
+    CHECK(obj);
+
+    JS::PrepareForFullGC(cx);
+    js::SliceBudget budget(js::WorkBudget(1));
+    cx->runtime()->gc.startDebugGC(GC_SHRINK, budget);
+    CHECK(JS::IsIncrementalGCInProgress(cx));
+
+    // Trigger another GC after the current one in shrinking / shutdown GCs.
+    cx->runtime()->gc.notifyRootsRemoved();
+
+    JS::FinishIncrementalGC(cx, JS::gcreason::DEBUG_GC);
+    CHECK(!JS::IsIncrementalGCInProgress(cx));
+
+    JS::SetGCSliceCallback(cx, nullptr);
+
+    JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_GLOBAL);
+
+    return true;
+}
+END_TEST(testGCRootsRemoved)
+
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6267,30 +6267,30 @@ JS_ObjectIsRegExp(JSContext* cx, HandleO
 }
 
 JS_PUBLIC_API(unsigned)
 JS_GetRegExpFlags(JSContext* cx, HandleObject obj)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    RootedRegExpShared shared(cx);
-    if (!RegExpToShared(cx, obj, &shared))
+    RegExpShared* shared = RegExpToShared(cx, obj);
+    if (!shared)
         return false;
     return shared->getFlags();
 }
 
 JS_PUBLIC_API(JSString*)
 JS_GetRegExpSource(JSContext* cx, HandleObject obj)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    RootedRegExpShared shared(cx);
-    if (!RegExpToShared(cx, obj, &shared))
+    RegExpShared* shared = RegExpToShared(cx, obj);
+    if (!shared)
         return nullptr;
     return shared->getSource();
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(bool)
 JS_SetDefaultLocale(JSContext* cx, const char* locale)
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1201,19 +1201,19 @@ js::SetActivityCallback(JSContext* cx, A
 
 JS_FRIEND_API(void)
 JS::NotifyDidPaint(JSContext* cx)
 {
     cx->runtime()->gc.notifyDidPaint();
 }
 
 JS_FRIEND_API(void)
-JS::PokeGC(JSContext* cx)
+JS::NotifyGCRootsRemoved(JSContext* cx)
 {
-    cx->runtime()->gc.poke();
+    cx->runtime()->gc.notifyRootsRemoved();
 }
 
 JS_FRIEND_API(JSCompartment*)
 js::GetAnyCompartmentInZone(JS::Zone* zone)
 {
     CompartmentsInZoneIter comp(zone);
     MOZ_ASSERT(!comp.done());
     return comp.get();
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1176,19 +1176,18 @@ CastToJSFreeOp(FreeOp* fop)
 extern JS_FRIEND_API(JSFlatString*)
 GetErrorTypeName(JSContext* cx, int16_t exnType);
 
 #ifdef JS_DEBUG
 extern JS_FRIEND_API(unsigned)
 GetEnterCompartmentDepth(JSContext* cx);
 #endif
 
-extern JS_FRIEND_API(bool)
-RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp,
-                        JS::MutableHandle<RegExpShared*> shared);
+extern JS_FRIEND_API(RegExpShared*)
+RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp);
 
 /* Implemented in CrossCompartmentWrapper.cpp. */
 typedef enum NukeReferencesToWindow {
     NukeWindowReferences,
     DontNukeWindowReferences
 } NukeReferencesToWindow;
 
 typedef enum NukeReferencesFromTarget {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -923,17 +923,17 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
     relocatedArenasToRelease(nullptr),
 #ifdef JS_GC_ZEAL
     markingValidator(nullptr),
 #endif
     interFrameGC(false),
     defaultTimeBudget_((int64_t) SliceBudget::UnlimitedTimeBudget),
     incrementalAllowed(true),
     compactingEnabled(true),
-    poked(false),
+    rootsRemoved(false),
 #ifdef JS_GC_ZEAL
     zealModeBits(0),
     zealFrequency(0),
     nextScheduled(0),
     deterministicOnly(false),
     incrementalLimit(0),
 #endif
     fullCompartmentChecks(false),
@@ -964,17 +964,17 @@ GCRuntime::getZealBits(uint32_t* zealBit
 
 const char* gc::ZealModeHelpText =
     "  Specifies how zealous the garbage collector should be. Some of these modes can\n"
     "  be set simultaneously, by passing multiple level options, e.g. \"2;4\" will activate\n"
     "  both modes 2 and 4. Modes can be specified by name or number.\n"
     "  \n"
     "  Values:\n"
     "    0: (None) Normal amount of collection (resets all modes)\n"
-    "    1: (Poke) Collect when roots are added or removed\n"
+    "    1: (RootsChange) Collect when roots are added or removed\n"
     "    2: (Alloc) Collect when every N allocations (default: 100)\n"
     "    3: (FrameGC) Collect when the window paints (browser only)\n"
     "    4: (VerifierPre) Verify pre write barriers between instructions\n"
     "    5: (FrameVerifierPre) Verify pre write barriers between paints\n"
     "    6: (StackRooting) Verify stack rooting\n"
     "    7: (GenerationalGC) Collect the nursery every N nursery allocations\n"
     "    8: (IncrementalRootsThenFinish) Incremental GC in two slices: 1) mark roots 2) finish collection\n"
     "    9: (IncrementalMarkAllThenFinish) Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
@@ -1628,17 +1628,17 @@ GCRuntime::addRoot(Value* vp, const char
 
     return rootsHash.ref().put(vp, name);
 }
 
 void
 GCRuntime::removeRoot(Value* vp)
 {
     rootsHash.ref().remove(vp);
-    poke();
+    notifyRootsRemoved();
 }
 
 extern JS_FRIEND_API(bool)
 js::AddRawValueRoot(JSContext* cx, Value* vp, const char* name)
 {
     MOZ_ASSERT(vp);
     MOZ_ASSERT(name);
     bool ok = cx->runtime()->gc.addRoot(vp, name);
@@ -3103,17 +3103,17 @@ GCRuntime::triggerZoneGC(Zone* zone, JS:
 }
 
 void
 GCRuntime::maybeGC(Zone* zone)
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
 #ifdef JS_GC_ZEAL
-    if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::Poke)) {
+    if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::RootsChange)) {
         JS::PrepareForFullGC(rt->activeContextFromOwnThread());
         gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
         return;
     }
 #endif
 
     if (gcIfRequested())
         return;
@@ -6456,16 +6456,17 @@ GCRuntime::incrementalCollectSlice(Slice
     }
 
     switch (incrementalState) {
       case State::NotActive:
         initialReason = reason;
         cleanUpEverything = ShouldCleanUpEverything(reason, invocationKind);
         isCompacting = shouldCompact();
         lastMarkSlice = false;
+        rootsRemoved = false;
 
         incrementalState = State::MarkRoots;
 
         MOZ_FALLTHROUGH;
 
       case State::MarkRoots:
         if (!beginMarkPhase(reason, lock)) {
             incrementalState = State::NotActive;
@@ -6941,18 +6942,19 @@ GCRuntime::checkIfGCAllowedInCurrentStat
 
     return true;
 }
 
 bool
 GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason)
 {
     MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
-
-    if (!isIncremental || isIncrementalGCInProgress())
+    MOZ_ASSERT(!isIncrementalGCInProgress());
+
+    if (!isIncremental)
         return false;
 
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         if (c->scheduledForDestruction)
             return true;
     }
 
     return false;
@@ -6968,47 +6970,48 @@ GCRuntime::collect(bool nonincrementalBy
     if (!checkIfGCAllowedInCurrentState(reason))
         return;
 
     AutoTraceLog logGC(TraceLoggerForCurrentThread(), TraceLogger_GC);
     AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason));
     AutoEnqueuePendingParseTasksAfterGC aept(*this);
     AutoScheduleZonesForGC asz(rt);
 
-    bool repeat = false;
+    bool repeat;
     do {
-        poked = false;
         bool wasReset = gcCycle(nonincrementalByAPI, budget, reason) == IncrementalResult::Reset;
 
         if (reason == JS::gcreason::ABORT_GC) {
             MOZ_ASSERT(!isIncrementalGCInProgress());
             break;
         }
 
-        bool repeatForDeadZone = false;
-        if (poked && cleanUpEverything) {
-            /* Need to re-schedule all zones for GC. */
-            JS::PrepareForFullGC(rt->activeContextFromOwnThread());
-        } else if (shouldRepeatForDeadZone(reason) && !wasReset) {
-            /*
-             * This code makes an extra effort to collect compartments that we
-             * thought were dead at the start of the GC. See the large comment
-             * in beginMarkPhase.
-             */
-            repeatForDeadZone = true;
-            reason = JS::gcreason::COMPARTMENT_REVIVED;
-        }
-
         /*
-         * If we reset an existing GC, we need to start a new one. Also, we
-         * repeat GCs that happen during shutdown (the gcShouldCleanUpEverything
-         * case) until we can be sure that no additional garbage is created
-         * (which typically happens if roots are dropped during finalizers).
+         * Sometimes when we finish a GC we need to immediately start a new one.
+         * This happens in the following cases:
+         *  - when we reset the current GC
+         *  - when finalizers drop roots during shutdown (the cleanUpEverything
+         *    case)
+         *  - when zones that we thought were dead at the start of GC are
+         *    not collected (see the large comment in beginMarkPhase)
          */
-        repeat = (poked && cleanUpEverything) || wasReset || repeatForDeadZone;
+        repeat = false;
+        if (!isIncrementalGCInProgress()) {
+            if (wasReset) {
+                repeat = true;
+            } else if (rootsRemoved && cleanUpEverything) {
+                /* Need to re-schedule all zones for GC. */
+                JS::PrepareForFullGC(rt->activeContextFromOwnThread());
+                repeat = true;
+                reason = JS::gcreason::ROOTS_REMOVED;
+            } else if (shouldRepeatForDeadZone(reason)) {
+                repeat = true;
+                reason = JS::gcreason::COMPARTMENT_REVIVED;
+            }
+         }
     } while (repeat);
 
     if (reason == JS::gcreason::COMPARTMENT_REVIVED)
         maybeDoCycleCollection();
 
 #ifdef JS_GC_ZEAL
     if (rt->hasZealMode(ZealMode::CheckHeapAfterGC)) {
         gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
@@ -7565,16 +7568,28 @@ GCRuntime::runDebugGC()
 
 void
 GCRuntime::setFullCompartmentChecks(bool enabled)
 {
     MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
     fullCompartmentChecks = enabled;
 }
 
+void
+GCRuntime::notifyRootsRemoved()
+{
+    rootsRemoved = true;
+
+#ifdef JS_GC_ZEAL
+    /* Schedule a GC to happen "soon". */
+    if (hasZealMode(ZealMode::RootsChange))
+        nextScheduled = 1;
+#endif
+}
+
 #ifdef JS_GC_ZEAL
 bool
 GCRuntime::selectForMarking(JSObject* object)
 {
     MOZ_ASSERT(!JS::CurrentThreadIsHeapMajorCollecting());
     return selectedForMarking.ref().append(object);
 }
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1161,17 +1161,17 @@ inline void CheckGCThingAfterMovingGC(T*
 template <typename T>
 inline void CheckGCThingAfterMovingGC(const ReadBarriered<T*>& t);
 
 inline void CheckValueAfterMovingGC(const JS::Value& value);
 
 #endif // JSGC_HASH_TABLE_CHECKS
 
 #define JS_FOR_EACH_ZEAL_MODE(D)               \
-            D(Poke, 1)                         \
+            D(RootsChange, 1)                  \
             D(Alloc, 2)                        \
             D(FrameGC, 3)                      \
             D(VerifierPre, 4)                  \
             D(FrameVerifierPre, 5)             \
             D(StackRooting, 6)                 \
             D(GenerationalGC, 7)               \
             D(IncrementalRootsThenFinish, 8)   \
             D(IncrementalMarkAllThenFinish, 9) \
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -36,28 +36,16 @@ GetGCObjectKind(const Class* clasp)
     MOZ_ASSERT(!clasp->isProxy(), "Proxies should use GetProxyGCObjectKind");
 
     uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
     if (clasp->flags & JSCLASS_HAS_PRIVATE)
         nslots++;
     return GetGCObjectKind(nslots);
 }
 
-inline void
-GCRuntime::poke()
-{
-    poked = true;
-
-#ifdef JS_GC_ZEAL
-    /* Schedule a GC to happen "soon" after a GC poke. */
-    if (hasZealMode(ZealMode::Poke))
-        nextScheduled = 1;
-#endif
-}
-
 class ArenaIter
 {
     Arena* arena;
     Arena* unsweptArena;
     Arena* sweptArena;
     mozilla::DebugOnly<bool> initialized;
 
   public:
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -111,18 +111,17 @@ class JS_FRIEND_API(Wrapper) : public Ba
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
                                    unsigned indent) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<RegExpShared*> shared) const override;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                   MutableHandleValue vp) const override;
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
     virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
 
   public:
     using BaseProxyHandler::Action;
@@ -206,18 +205,17 @@ class JS_FRIEND_API(CrossCompartmentWrap
                                               AutoIdVector& props) const override;
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
                              bool* bp) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
                                    unsigned indent) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<RegExpShared*> shared) const override;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
 
     // Allocate CrossCompartmentWrappers in the nursery.
     virtual bool canNurseryAllocate() const override { return true; }
 
     static const CrossCompartmentWrapper singleton;
     static const CrossCompartmentWrapper singletonWithPrototype;
 };
@@ -304,18 +302,17 @@ class JS_FRIEND_API(SecurityWrapper) : p
     virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
                               ObjectOpResult& result) const override;
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override;
 
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<RegExpShared*> shared) const override;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
 
     // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
     // against.
 
     virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
                        JS::HandleObject callable) const override;
     virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override;
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -320,19 +320,18 @@ BaseProxyHandler::fun_toString(JSContext
 {
     if (proxy->isCallable())
         return JS_NewStringCopyZ(cx, "function () {\n    [native code]\n}");
     RootedValue v(cx, ObjectValue(*proxy));
     ReportIsNotFunction(cx, v);
     return nullptr;
 }
 
-bool
-BaseProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
-                                  MutableHandleRegExpShared shared) const
+RegExpShared*
+BaseProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
 {
     MOZ_CRASH("This should have been a wrapped regexp");
 }
 
 bool
 BaseProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
 {
     vp.setUndefined();
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -458,31 +458,31 @@ CrossCompartmentWrapper::fun_toString(JS
         if (!str)
             return nullptr;
     }
     if (!cx->compartment()->wrap(cx, &str))
         return nullptr;
     return str;
 }
 
-bool
-CrossCompartmentWrapper::regexp_toShared(JSContext* cx, HandleObject wrapper,
-                                         MutableHandleRegExpShared shared) const
+RegExpShared*
+CrossCompartmentWrapper::regexp_toShared(JSContext* cx, HandleObject wrapper) const
 {
     RootedRegExpShared re(cx);
     {
         AutoCompartment call(cx, wrappedObject(wrapper));
-        if (!Wrapper::regexp_toShared(cx, wrapper, &re))
-            return false;
+        re = Wrapper::regexp_toShared(cx, wrapper);
+        if (!re)
+            return nullptr;
     }
 
     // Get an equivalent RegExpShared associated with the current compartment.
     RootedAtom source(cx, re->getSource());
     cx->markAtom(source);
-    return cx->zone()->regExps.get(cx, source, re->getFlags(), shared);
+    return cx->zone()->regExps.get(cx, source, re->getFlags());
 }
 
 bool
 CrossCompartmentWrapper::boxedValue_unbox(JSContext* cx, HandleObject wrapper, MutableHandleValue vp) const
 {
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::boxedValue_unbox(cx, wrapper, vp),
--- a/js/src/proxy/DeadObjectProxy.cpp
+++ b/js/src/proxy/DeadObjectProxy.cpp
@@ -155,22 +155,21 @@ template <DeadProxyIsCallableIsConstruct
 JSString*
 DeadObjectProxy<CC>::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
 {
     ReportDead(cx);
     return nullptr;
 }
 
 template <DeadProxyIsCallableIsConstructorOption CC>
-bool
-DeadObjectProxy<CC>::regexp_toShared(JSContext* cx, HandleObject proxy,
-                                     MutableHandle<RegExpShared*> shared) const
+RegExpShared*
+DeadObjectProxy<CC>::regexp_toShared(JSContext* cx, HandleObject proxy) const
 {
     ReportDead(cx);
-    return false;
+    return nullptr;
 }
 
 template <>
 const char DeadObjectProxy<DeadProxyNotCallableNotConstructor>::family = 0;
 template <>
 const char DeadObjectProxy<DeadProxyNotCallableIsConstructor>::family = 0;
 template <>
 const char DeadObjectProxy<DeadProxyIsCallableNotConstructor>::family = 0;
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -55,18 +55,17 @@ class DeadObjectProxy : public BaseProxy
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<RegExpShared*> shared) const override;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
 
     virtual bool isCallable(JSObject* obj) const override {
         return CC == DeadProxyIsCallableIsConstructor || CC == DeadProxyIsCallableNotConstructor;
     }
     virtual bool isConstructor(JSObject* obj) const override {
         return CC == DeadProxyIsCallableIsConstructor || CC == DeadProxyNotCallableIsConstructor;
     }
 
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -570,22 +570,22 @@ Proxy::fun_toString(JSContext* cx, Handl
     AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                            BaseProxyHandler::GET, /* mayThrow = */ false);
     // Do the safe thing if the policy rejects.
     if (!policy.allowed())
         return handler->BaseProxyHandler::fun_toString(cx, proxy, indent);
     return handler->fun_toString(cx, proxy, indent);
 }
 
-bool
-Proxy::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandleRegExpShared shared)
+RegExpShared*
+Proxy::regexp_toShared(JSContext* cx, HandleObject proxy)
 {
     if (!CheckRecursionLimit(cx))
-        return false;
-    return proxy->as<ProxyObject>().handler()->regexp_toShared(cx, proxy, shared);
+        return nullptr;
+    return proxy->as<ProxyObject>().handler()->regexp_toShared(cx, proxy);
 }
 
 bool
 Proxy::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp)
 {
     if (!CheckRecursionLimit(cx))
         return false;
     return proxy->as<ProxyObject>().handler()->boxedValue_unbox(cx, proxy, vp);
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -55,18 +55,17 @@ class Proxy
                                              AutoIdVector& props);
     static bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                            const CallArgs& args);
     static bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp);
     static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls);
     static bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer);
     static const char* className(JSContext* cx, HandleObject proxy);
     static JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent);
-    static bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                MutableHandle<RegExpShared*> shared);
+    static RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy);
     static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp);
 
     static bool watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable);
     static bool unwatch(JSContext* cx, HandleObject proxy, HandleId id);
 
     static bool getElements(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end,
                             ElementAdder* adder);
 
--- a/js/src/proxy/ScriptedProxyHandler.cpp
+++ b/js/src/proxy/ScriptedProxyHandler.cpp
@@ -1262,22 +1262,20 @@ ScriptedProxyHandler::className(JSContex
 JSString*
 ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
 {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                               js_Function_str, js_toString_str, "object");
     return nullptr;
 }
 
-bool
-ScriptedProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
-                                      MutableHandleRegExpShared shared) const
+RegExpShared*
+ScriptedProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
 {
     MOZ_CRASH("Should not end up in ScriptedProxyHandler::regexp_toShared");
-    return false;
 }
 
 bool
 ScriptedProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                        MutableHandleValue vp) const
 {
     MOZ_CRASH("Should not end up in ScriptedProxyHandler::boxedValue_unbox");
     return false;
--- a/js/src/proxy/ScriptedProxyHandler.h
+++ b/js/src/proxy/ScriptedProxyHandler.h
@@ -64,18 +64,17 @@ class ScriptedProxyHandler : public Base
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
                                    unsigned indent) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 MutableHandle<RegExpShared*> shared) const override;
+    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                   MutableHandleValue vp) const override;
 
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
 
     virtual bool isScripted() const override { return true; }
 
--- a/js/src/proxy/SecurityWrapper.cpp
+++ b/js/src/proxy/SecurityWrapper.cpp
@@ -82,21 +82,20 @@ bool
 SecurityWrapper<Base>::isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const
 {
     // This should ReportAccessDenied(cx), but bug 849730 disagrees.  :-(
     *answer = JS::IsArrayAnswer::NotArray;
     return true;
 }
 
 template <class Base>
-bool
-SecurityWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject obj,
-                                       MutableHandle<RegExpShared*> shared) const
+RegExpShared*
+SecurityWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject obj) const
 {
-    return Base::regexp_toShared(cx, obj, shared);
+    return Base::regexp_toShared(cx, obj);
 }
 
 template <class Base>
 bool
 SecurityWrapper<Base>::boxedValue_unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp) const
 {
     vp.setUndefined();
     return true;
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -266,21 +266,21 @@ Wrapper::className(JSContext* cx, Handle
 JSString*
 Wrapper::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return fun_toStringHelper(cx, target, indent);
 }
 
-bool
-Wrapper::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandleRegExpShared shared) const
+RegExpShared*
+Wrapper::regexp_toShared(JSContext* cx, HandleObject proxy) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return RegExpToShared(cx, target, shared);
+    return RegExpToShared(cx, target);
 }
 
 bool
 Wrapper::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return Unbox(cx, target, vp);
 }
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2860,18 +2860,16 @@ js::NativeDeleteProperty(JSContext* cx, 
 
     // Step 4.
     if (!prop) {
         // If no property call the class's delProperty hook, passing succeeded
         // as the result parameter. This always succeeds when there is no hook.
         return CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result);
     }
 
-    cx->runtime()->gc.poke();
-
     // Step 6. Non-configurable property.
     if (GetPropertyAttributes(obj, prop) & JSPROP_PERMANENT)
         return result.failCantDelete();
 
     if (!CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result))
         return false;
     if (!result)
         return true;
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -111,26 +111,23 @@ VectorMatchPairs::allocOrExpandArray(siz
 
     pairs_ = &vec_[0];
     pairCount_ = pairCount;
     return true;
 }
 
 /* RegExpObject */
 
-/* static */ bool
-RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp,
-                        MutableHandleRegExpShared shared)
+/* static */ RegExpShared*
+RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp)
 {
-    if (regexp->hasShared()) {
-        shared.set(regexp->sharedRef());
-        return true;
-    }
+    if (regexp->hasShared())
+        return regexp->sharedRef();
 
-    return createShared(cx, regexp, shared);
+    return createShared(cx, regexp);
 }
 
 /* static */ bool
 RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
 {
   if (native == regexp_global) {
       *mask = GlobalFlag;
       return true;
@@ -265,27 +262,27 @@ RegExpObject::create(JSContext* cx, Hand
     if (!regexp)
         return nullptr;
 
     regexp->initAndZeroLastIndex(source, flags, cx);
 
     return regexp;
 }
 
-/* static */ bool
-RegExpObject::createShared(JSContext* cx, Handle<RegExpObject*> regexp,
-                           MutableHandleRegExpShared shared)
+/* static */ RegExpShared*
+RegExpObject::createShared(JSContext* cx, Handle<RegExpObject*> regexp)
 {
     MOZ_ASSERT(!regexp->hasShared());
     RootedAtom source(cx, regexp->getSource());
-    if (!cx->zone()->regExps.get(cx, source, regexp->getFlags(), shared))
-        return false;
+    RegExpShared* shared = cx->zone()->regExps.get(cx, source, regexp->getFlags());
+    if (!shared)
+        return nullptr;
 
     regexp->setShared(*shared);
-    return true;
+    return shared;
 }
 
 Shape*
 RegExpObject::assignInitialShape(JSContext* cx, Handle<RegExpObject*> self)
 {
     MOZ_ASSERT(self->empty());
 
     JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
@@ -883,18 +880,18 @@ RegExpShared::dumpBytecode(JSContext* cx
 
     return true;
 }
 
 /* static */ bool
 RegExpObject::dumpBytecode(JSContext* cx, Handle<RegExpObject*> regexp,
                            bool match_only, HandleLinearString input)
 {
-    RootedRegExpShared shared(cx);
-    if (!getShared(cx, regexp, &shared))
+    RootedRegExpShared shared(cx, getShared(cx, regexp));
+    if (!shared)
         return false;
 
     return RegExpShared::dumpBytecode(cx, &shared, match_only, input);
 }
 #endif
 
 template <typename CharT>
 static MOZ_ALWAYS_INLINE bool
@@ -1284,49 +1281,45 @@ RegExpCompartment::sweep(JSRuntime* rt)
 
     if (optimizableRegExpInstanceShape_ &&
         IsAboutToBeFinalized(&optimizableRegExpInstanceShape_))
     {
         optimizableRegExpInstanceShape_.set(nullptr);
     }
 }
 
-bool
-RegExpZone::get(JSContext* cx, HandleAtom source, RegExpFlag flags,
-                MutableHandleRegExpShared result)
+RegExpShared*
+RegExpZone::get(JSContext* cx, HandleAtom source, RegExpFlag flags)
 {
     DependentAddPtr<Set> p(cx, set_, Key(source, flags));
-    if (p) {
-        result.set(*p);
-        return true;
-    }
+    if (p)
+        return *p;
 
     auto shared = Allocate<RegExpShared>(cx);
     if (!shared)
-        return false;
+        return nullptr;
 
     new (shared) RegExpShared(source, flags);
 
     if (!p.add(cx, set_, Key(source, flags), shared)) {
         ReportOutOfMemory(cx);
-        return false;
+        return nullptr;
     }
 
-    result.set(shared);
-    return true;
+    return shared;
 }
 
-bool
-RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt, MutableHandleRegExpShared shared)
+RegExpShared*
+RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt)
 {
     RegExpFlag flags = RegExpFlag(0);
     if (opt && !ParseRegExpFlags(cx, opt, &flags))
-        return false;
+        return nullptr;
 
-    return get(cx, atom, flags, shared);
+    return get(cx, atom, flags);
 }
 
 size_t
 RegExpZone::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return set_.sizeOfExcludingThis(mallocSizeOf);
 }
 
@@ -1348,18 +1341,18 @@ js::CloneRegExpObject(JSContext* cx, JSO
         return nullptr;
     clone->initPrivate(nullptr);
 
     if (!EmptyShape::ensureInitialCustomShape<RegExpObject>(cx, clone))
         return nullptr;
 
     Rooted<JSAtom*> source(cx, regex->getSource());
 
-    RootedRegExpShared shared(cx);
-    if (!RegExpObject::getShared(cx, regex, &shared))
+    RegExpShared* shared = RegExpObject::getShared(cx, regex);
+    if (!shared)
         return nullptr;
 
     clone->initAndZeroLastIndex(source, shared->getFlags(), cx);
     clone->setShared(*shared);
 
     return clone;
 }
 
@@ -1488,20 +1481,20 @@ js::CloneScriptRegExpObject(JSContext* c
     RootedAtom source(cx, reobj.getSource());
     cx->markAtom(source);
 
     return RegExpObject::create(cx, source, reobj.getFlags(),
                                 nullptr, nullptr, cx->tempLifoAlloc(),
                                 TenuredObject);
 }
 
-JS_FRIEND_API(bool)
-js::RegExpToSharedNonInline(JSContext* cx, HandleObject obj, MutableHandleRegExpShared shared)
+JS_FRIEND_API(RegExpShared*)
+js::RegExpToSharedNonInline(JSContext* cx, HandleObject obj)
 {
-    return RegExpToShared(cx, obj, shared);
+    return RegExpToShared(cx, obj);
 }
 
 JS::ubi::Node::Size
 JS::ubi::Concrete<RegExpShared>::size(mozilla::MallocSizeOf mallocSizeOf) const
 {
     return js::gc::Arena::thingSize(gc::AllocKind::REGEXP_SHARED) +
         get().sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -138,18 +138,17 @@ class RegExpObject : public NativeObject
     bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
     bool global() const     { return getFlags() & GlobalFlag; }
     bool multiline() const  { return getFlags() & MultilineFlag; }
     bool sticky() const     { return getFlags() & StickyFlag; }
     bool unicode() const    { return getFlags() & UnicodeFlag; }
 
     static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
 
-    static MOZ_MUST_USE bool getShared(JSContext* cx, Handle<RegExpObject*> regexp,
-                                       MutableHandleRegExpShared shared);
+    static RegExpShared* getShared(JSContext* cx, Handle<RegExpObject*> regexp);
 
     bool hasShared() {
         return !!sharedRef();
     }
 
     void setShared(RegExpShared& shared) {
         MOZ_ASSERT(!hasShared());
         sharedRef().init(&shared);
@@ -175,40 +174,39 @@ class RegExpObject : public NativeObject
                                           bool match_only, HandleLinearString input);
 #endif
 
   private:
     /*
      * Precondition: the syntax for |source| has already been validated.
      * Side effect: sets the private field.
      */
-    static MOZ_MUST_USE bool createShared(JSContext* cx, Handle<RegExpObject*> regexp,
-                                          MutableHandleRegExpShared shared);
+    static RegExpShared* createShared(JSContext* cx, Handle<RegExpObject*> regexp);
 
     /* Call setShared in preference to setPrivate. */
     void setPrivate(void* priv) = delete;
 };
 
 /*
  * Parse regexp flags. Report an error and return false if an invalid
  * sequence of flags is encountered (repeat/invalid flag).
  *
  * N.B. flagStr must be rooted.
  */
 bool
 ParseRegExpFlags(JSContext* cx, JSString* flagStr, RegExpFlag* flagsOut);
 
 /* Assuming GetBuiltinClass(obj) is ESClass::RegExp, return a RegExpShared for obj. */
-inline bool
-RegExpToShared(JSContext* cx, HandleObject obj, MutableHandleRegExpShared shared)
+inline RegExpShared*
+RegExpToShared(JSContext* cx, HandleObject obj)
 {
     if (obj->is<RegExpObject>())
-        return RegExpObject::getShared(cx, obj.as<RegExpObject>(), shared);
+        return RegExpObject::getShared(cx, obj.as<RegExpObject>());
 
-    return Proxy::regexp_toShared(cx, obj, shared);
+    return Proxy::regexp_toShared(cx, obj);
 }
 
 template<XDRMode mode>
 bool
 XDRScriptRegExpObject(XDRState<mode>* xdr, MutableHandle<RegExpObject*> objp);
 
 extern JSObject*
 CloneScriptRegExpObject(JSContext* cx, RegExpObject& re);
--- a/js/src/vm/RegExpShared.h
+++ b/js/src/vm/RegExpShared.h
@@ -268,21 +268,20 @@ class RegExpZone
     ~RegExpZone() {
         MOZ_ASSERT_IF(set_.initialized(), set_.empty());
     }
 
     bool init();
 
     bool empty() const { return set_.empty(); }
 
-    bool get(JSContext* cx, HandleAtom source, RegExpFlag flags, MutableHandleRegExpShared shared);
+    RegExpShared* get(JSContext* cx, HandleAtom source, RegExpFlag flags);
 
     /* Like 'get', but compile 'maybeOpt' (if non-null). */
-    bool get(JSContext* cx, HandleAtom source, JSString* maybeOpt,
-             MutableHandleRegExpShared shared);
+    RegExpShared* get(JSContext* cx, HandleAtom source, JSString* maybeOpt);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 class RegExpCompartment
 {
     /*
      * This is the template object where the result of re.exec() is based on,
--- a/js/src/vm/RegExpStatics.cpp
+++ b/js/src/vm/RegExpStatics.cpp
@@ -77,19 +77,19 @@ RegExpStatics::executeLazy(JSContext* cx
     if (!pendingLazyEvaluation)
         return true;
 
     MOZ_ASSERT(lazySource);
     MOZ_ASSERT(matchesInput);
     MOZ_ASSERT(lazyIndex != size_t(-1));
 
     /* Retrieve or create the RegExpShared in this zone. */
-    RootedRegExpShared shared(cx);
     RootedAtom source(cx, lazySource);
-    if (!cx->zone()->regExps.get(cx, source, lazyFlags, &shared))
+    RootedRegExpShared shared(cx, cx->zone()->regExps.get(cx, source, lazyFlags));
+    if (!shared)
         return false;
 
     /*
      * It is not necessary to call aboutToWrite(): evaluation of
      * implicit copies is safe.
      */
 
     /* Execute the full regular expression. */
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1484,18 +1484,18 @@ JSStructuredCloneWriter::startWrite(Hand
         if (backref)
             return true;
 
         ESClass cls;
         if (!GetBuiltinClass(context(), obj, &cls))
             return false;
 
         if (cls == ESClass::RegExp) {
-            RootedRegExpShared re(context());
-            if (!RegExpToShared(context(), obj, &re))
+            RegExpShared* re = RegExpToShared(context(), obj);
+            if (!re)
                 return false;
             return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
                    writeString(SCTAG_STRING, re->getSource());
         } else if (cls == ESClass::Date) {
             RootedValue unboxed(context());
             if (!Unbox(context(), obj, &unboxed))
                 return false;
             return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(unboxed.toNumber());
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3020,17 +3020,17 @@ XPCRootSetElem::AddToRootSet(XPCRootSetE
         mNext->mSelfp = &mNext;
     }
     *listHead = this;
 }
 
 void
 XPCRootSetElem::RemoveFromRootSet()
 {
-    JS::PokeGC(XPCJSContext::Get()->Context());
+    JS::NotifyGCRootsRemoved(XPCJSContext::Get()->Context());
 
     MOZ_ASSERT(mSelfp, "Must be linked");
 
     MOZ_ASSERT(*mSelfp == this, "Link invariant");
     *mSelfp = mNext;
     if (mNext)
         mNext->mSelfp = mSelfp;
 #ifdef DEBUG
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1890,16 +1890,19 @@ nsPresContext::SysColorChangedInternal()
   mPendingSysColorChanged = false;
 
   if (sLookAndFeelChanged) {
      // Don't use the cached values for the system colors
     LookAndFeel::Refresh();
     sLookAndFeelChanged = false;
   }
 
+  // Invalidate cached '-moz-windows-accent-color-applies' media query:
+  nsCSSRuleProcessor::FreeSystemMetrics();
+
   // Reset default background and foreground colors for the document since
   // they may be using system colors
   GetDocumentColorPreferences();
 
   // The system color values are computed to colors in the style data,
   // so normal style data comparison is sufficient here.
   RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
 }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3363,28 +3363,30 @@ ScrollFrameHelper::BuildDisplayList(nsDi
     !(mIsRoot && mOuter->PresContext()->PresShell()->GetIsViewportOverridden());
 
   // Whether we might want to build a scrollable layer for this scroll frame
   // at some point in the future. This controls whether we add the information
   // to the layer tree (a scroll info layer if necessary, and add the right
   // area to the dispatch to content layer event regions) necessary to activate
   // a scroll frame so it creates a scrollable layer.
   bool couldBuildLayer = false;
-  if (mWillBuildScrollableLayer) {
-    couldBuildLayer = true;
-  } else {
-    couldBuildLayer =
-      nsLayoutUtils::AsyncPanZoomEnabled(mOuter) &&
-      WantAsyncScroll() &&
-      // If we are using containers for root frames, and we are the root
-      // scroll frame for the display root, then we don't need a scroll
-      // info layer. nsDisplayList::PaintForFrame already calls
-      // ComputeFrameMetrics for us.
-      (!(gfxPrefs::LayoutUseContainersForRootFrames() && mIsRoot) ||
-       (aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext()));
+  if (aBuilder->IsPaintingToWindow()) {
+    if (mWillBuildScrollableLayer) {
+      couldBuildLayer = true;
+    } else {
+      couldBuildLayer =
+        nsLayoutUtils::AsyncPanZoomEnabled(mOuter) &&
+        WantAsyncScroll() &&
+        // If we are using containers for root frames, and we are the root
+        // scroll frame for the display root, then we don't need a scroll
+        // info layer. nsDisplayList::PaintForFrame already calls
+        // ComputeFrameMetrics for us.
+        (!(gfxPrefs::LayoutUseContainersForRootFrames() && mIsRoot) ||
+         (aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext()));
+    }
   }
 
   // Now display the scrollbars and scrollcorner. These parts are drawn
   // in the border-background layer, on top of our own background and
   // borders and underneath borders and backgrounds of later elements
   // in the tree.
   // Note that this does not apply for overlay scrollbars; those are drawn
   // in the positioned-elements layer on top of everything else by the call
@@ -3596,22 +3598,21 @@ ScrollFrameHelper::BuildDisplayList(nsDi
 bool
 ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                                          nsRect* aDirtyRect,
                                          bool aAllowCreateDisplayPort)
 {
   // Save and check if this changes so we can recompute the current agr.
   bool oldWillBuildScrollableLayer = mWillBuildScrollableLayer;
 
-  bool wasUsingDisplayPort = false;
-  bool usingDisplayPort = false;
   nsIContent* content = mOuter->GetContent();
+  bool wasUsingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
+  bool usingDisplayPort = wasUsingDisplayPort;
+
   if (aBuilder->IsPaintingToWindow()) {
-    wasUsingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
-
     if (aAllowCreateDisplayPort) {
       nsLayoutUtils::MaybeCreateDisplayPort(*aBuilder, mOuter);
 
       nsRect displayportBase = *aDirtyRect;
       nsPresContext* pc = mOuter->PresContext();
       if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
         displayportBase =
           nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -400,17 +400,19 @@ nsSubDocumentFrame::BuildDisplayList(nsD
 
     if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
       nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
       MOZ_ASSERT(rootScrollableFrame);
       // Use a copy, so the dirty rect doesn't get modified to the display port.
       nsRect copy = dirty;
       haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
                           &copy, /* aAllowCreateDisplayPort = */ true);
-      if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
+
+      if (!gfxPrefs::LayoutUseContainersForRootFrames() ||
+          !aBuilder->IsPaintingToWindow()) {
         haveDisplayPort = false;
       }
 
       ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
       if (ignoreViewportScrolling) {
         savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
         aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
       }
--- a/media/webrtc/trunk/webrtc/base/task_queue_libevent.cc
+++ b/media/webrtc/trunk/webrtc/base/task_queue_libevent.cc
@@ -229,17 +229,17 @@ void TaskQueue::PostTask(std::unique_ptr
 void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task,
                                 uint32_t milliseconds) {
   if (IsCurrent()) {
     TimerEvent* timer = new TimerEvent(std::move(task));
     EventAssign(&timer->ev, event_base_, -1, 0, &TaskQueue::RunTimer, timer);
     QueueContext* ctx =
         static_cast<QueueContext*>(pthread_getspecific(GetQueuePtrTls()));
     ctx->pending_timers_.push_back(timer);
-    timeval tv = {milliseconds / 1000,
+    timeval tv = {static_cast<time_t>(milliseconds) / 1000,
 		  static_cast<suseconds_t>((milliseconds % 1000) * 1000)};
     event_add(&timer->ev, &tv);
   } else {
     PostTask(std::unique_ptr<QueuedTask>(
         new SetTimerTask(std::move(task), milliseconds)));
   }
 }
 
--- a/modules/pdfium/moz.build
+++ b/modules/pdfium/moz.build
@@ -22,17 +22,17 @@ if CONFIG['OS_TARGET'] == 'WINNT':
 DEFINES['V8_DEPRECATION_WARNINGS'] = True
 if CONFIG['OS_ARCH'] == 'Linux':
     if CONFIG['CPU_ARCH'] == 'x86_64':
         DEFINES['_FX_CPU_'] = '_FX_X64_'
     elif CONFIG['CPU_ARCH'] == 'x86':
         DEFINES['_FX_CPU_'] = '_FX_X86_'
 
 # pdfium
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/fpdfsdk/cba_annotiterator.cpp',
     'pdfium/fpdfsdk/cfx_systemhandler.cpp',
     'pdfium/fpdfsdk/cpdfsdk_annot.cpp',
     'pdfium/fpdfsdk/cpdfsdk_annothandlermgr.cpp',
     'pdfium/fpdfsdk/cpdfsdk_annotiteration.cpp',
     'pdfium/fpdfsdk/cpdfsdk_baannot.cpp',
     'pdfium/fpdfsdk/cpdfsdk_baannothandler.cpp',
     'pdfium/fpdfsdk/cpdfsdk_datetime.cpp',
@@ -66,37 +66,43 @@ SOURCES += [
 if CONFIG['OS_TARGET'] == 'WINNT':
     OS_LIBS += [
         'advapi32',
         'gdi32',
         'user32',
     ]
 
 # fdrm
+UNIFIED_SOURCES += [
+    'pdfium/core/fdrm/crypto/fx_crypt_aes.cpp',
+]
 SOURCES += [
+    # not able to be unified because of the error:
+    # - 'GET_UINT32': macro redefinition
+    # - 'PUT_UINT32': macro redefinition
+    # - 'P': macro redefinition
     'pdfium/core/fdrm/crypto/fx_crypt.cpp',
-    'pdfium/core/fdrm/crypto/fx_crypt_aes.cpp',
     'pdfium/core/fdrm/crypto/fx_crypt_sha.cpp',
 ]
 
 # formfiller
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/fpdfsdk/formfiller/cba_fontmap.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_checkbox.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_combobox.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_formfiller.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_listbox.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_pushbutton.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_radiobutton.cpp',
     'pdfium/fpdfsdk/formfiller/cffl_textfield.cpp',
 ]
 
 # fpdfapi
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/core/fpdfapi/cmaps/CNS1/Adobe-CNS1-UCS2_5.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/B5pc-H_0.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/B5pc-V_0.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/cmaps_cns1.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/CNS-EUC-H_0.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/CNS-EUC-V_0.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/ETen-B5-H_0.cpp',
     'pdfium/core/fpdfapi/cmaps/CNS1/ETen-B5-V_0.cpp',
@@ -223,36 +229,40 @@ SOURCES += [
     'pdfium/core/fpdfapi/parser/cpdf_stream.cpp',
     'pdfium/core/fpdfapi/parser/cpdf_stream_acc.cpp',
     'pdfium/core/fpdfapi/parser/cpdf_string.cpp',
     'pdfium/core/fpdfapi/parser/cpdf_syntax_parser.cpp',
     'pdfium/core/fpdfapi/parser/fpdf_parser_decode.cpp',
     'pdfium/core/fpdfapi/parser/fpdf_parser_utility.cpp',
     'pdfium/core/fpdfapi/render/cpdf_charposlist.cpp',
     'pdfium/core/fpdfapi/render/cpdf_devicebuffer.cpp',
-    'pdfium/core/fpdfapi/render/cpdf_dibsource.cpp',
     'pdfium/core/fpdfapi/render/cpdf_dibtransferfunc.cpp',
     'pdfium/core/fpdfapi/render/cpdf_docrenderdata.cpp',
     'pdfium/core/fpdfapi/render/cpdf_imagecacheentry.cpp',
     'pdfium/core/fpdfapi/render/cpdf_imageloader.cpp',
     'pdfium/core/fpdfapi/render/cpdf_imagerenderer.cpp',
     'pdfium/core/fpdfapi/render/cpdf_pagerendercache.cpp',
     'pdfium/core/fpdfapi/render/cpdf_progressiverenderer.cpp',
     'pdfium/core/fpdfapi/render/cpdf_rendercontext.cpp',
     'pdfium/core/fpdfapi/render/cpdf_renderoptions.cpp',
     'pdfium/core/fpdfapi/render/cpdf_renderstatus.cpp',
     'pdfium/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp',
     'pdfium/core/fpdfapi/render/cpdf_textrenderer.cpp',
     'pdfium/core/fpdfapi/render/cpdf_transferfunc.cpp',
     'pdfium/core/fpdfapi/render/cpdf_type3cache.cpp',
     'pdfium/core/fpdfapi/render/cpdf_type3glyphs.cpp',
 ]
+SOURCES += [
+    # not able to be unified because of the error:
+    # - '`anonymous-namespace'::kMaxImageDimension': redefinition; different storage class
+    'pdfium/core/fpdfapi/render/cpdf_dibsource.cpp',
+]
 
 # fpdfdoc
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/core/fpdfdoc/cline.cpp',
     'pdfium/core/fpdfdoc/clines.cpp',
     'pdfium/core/fpdfdoc/cpdf_aaction.cpp',
     'pdfium/core/fpdfdoc/cpdf_action.cpp',
     'pdfium/core/fpdfdoc/cpdf_actionfields.cpp',
     'pdfium/core/fpdfdoc/cpdf_annot.cpp',
     'pdfium/core/fpdfdoc/cpdf_annotlist.cpp',
     'pdfium/core/fpdfdoc/cpdf_apsettings.cpp',
@@ -260,48 +270,51 @@ SOURCES += [
     'pdfium/core/fpdfdoc/cpdf_bookmarktree.cpp',
     'pdfium/core/fpdfdoc/cpdf_defaultappearance.cpp',
     'pdfium/core/fpdfdoc/cpdf_dest.cpp',
     'pdfium/core/fpdfdoc/cpdf_docjsactions.cpp',
     'pdfium/core/fpdfdoc/cpdf_filespec.cpp',
     'pdfium/core/fpdfdoc/cpdf_formcontrol.cpp',
     'pdfium/core/fpdfdoc/cpdf_formfield.cpp',
     'pdfium/core/fpdfdoc/cpdf_iconfit.cpp',
-    'pdfium/core/fpdfdoc/cpdf_interform.cpp',
     'pdfium/core/fpdfdoc/cpdf_link.cpp',
     'pdfium/core/fpdfdoc/cpdf_linklist.cpp',
     'pdfium/core/fpdfdoc/cpdf_metadata.cpp',
-    'pdfium/core/fpdfdoc/cpdf_nametree.cpp',
     'pdfium/core/fpdfdoc/cpdf_numbertree.cpp',
     'pdfium/core/fpdfdoc/cpdf_occontext.cpp',
     'pdfium/core/fpdfdoc/cpdf_pagelabel.cpp',
     'pdfium/core/fpdfdoc/cpdf_variabletext.cpp',
     'pdfium/core/fpdfdoc/cpdf_viewerpreferences.cpp',
     'pdfium/core/fpdfdoc/cpvt_color.cpp',
     'pdfium/core/fpdfdoc/cpvt_fontmap.cpp',
     'pdfium/core/fpdfdoc/cpvt_generateap.cpp',
     'pdfium/core/fpdfdoc/cpvt_sectioninfo.cpp',
     'pdfium/core/fpdfdoc/cpvt_wordinfo.cpp',
     'pdfium/core/fpdfdoc/csection.cpp',
     'pdfium/core/fpdfdoc/ctypeset.cpp',
+]
+SOURCES += [
+    # not able to be unified because of the error:
+    # - '`anonymous-namespace'::nMaxRecursion': redefinition; different storage class
+    'pdfium/core/fpdfdoc/cpdf_interform.cpp',
+    'pdfium/core/fpdfdoc/cpdf_nametree.cpp',
     'pdfium/core/fpdfdoc/doc_tagged.cpp',
 ]
 
 # fpdftext
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/core/fpdftext/cpdf_linkextract.cpp',
     'pdfium/core/fpdftext/cpdf_textpage.cpp',
     'pdfium/core/fpdftext/cpdf_textpagefind.cpp',
     'pdfium/core/fpdftext/unicodenormalizationdata.cpp',
 ]
 
 # fxcodec
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/core/fxcodec/codec/fx_codec.cpp',
-    'pdfium/core/fxcodec/codec/fx_codec_fax.cpp',
     'pdfium/core/fxcodec/codec/fx_codec_flate.cpp',
     'pdfium/core/fxcodec/codec/fx_codec_icc.cpp',
     'pdfium/core/fxcodec/codec/fx_codec_jbig.cpp',
     'pdfium/core/fxcodec/codec/fx_codec_jpeg.cpp',
 #    'pdfium/core/fxcodec/codec/fx_codec_jpx_opj.cpp',  # SkiaPDF doesn't use JPEG 2000 format
     'pdfium/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_ArithIntDecoder.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_BitStream.cpp',
@@ -316,19 +329,24 @@ SOURCES += [
     'pdfium/core/fxcodec/jbig2/JBig2_Image.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_PatternDict.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_PddProc.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_SddProc.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_Segment.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_SymbolDict.cpp',
     'pdfium/core/fxcodec/jbig2/JBig2_TrdProc.cpp',
 ]
+SOURCES += [
+    # not able to be unified because of the error:
+    # - '`anonymous-namespace'::kMaxImageDimension': redefinition; different storage class
+    'pdfium/core/fxcodec/codec/fx_codec_fax.cpp',
+]
 
 # fxcrt
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/core/fxcrt/fx_basic_array.cpp',
     'pdfium/core/fxcrt/fx_basic_bstring.cpp',
     'pdfium/core/fxcrt/fx_basic_buffer.cpp',
     'pdfium/core/fxcrt/fx_basic_coords.cpp',
     'pdfium/core/fxcrt/fx_basic_gcc.cpp',
     'pdfium/core/fxcrt/fx_basic_memmgr.cpp',
     'pdfium/core/fxcrt/fx_basic_utf.cpp',
     'pdfium/core/fxcrt/fx_basic_util.cpp',
@@ -340,24 +358,24 @@ SOURCES += [
     'pdfium/core/fxcrt/fx_xml_composer.cpp',
     'pdfium/core/fxcrt/fx_xml_parser.cpp',
     'pdfium/core/fxcrt/fxcrt_posix.cpp',
     'pdfium/core/fxcrt/fxcrt_stream.cpp',
     'pdfium/core/fxcrt/fxcrt_windows.cpp',
 ]
 
 # fxedit
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/fpdfsdk/fxedit/fxet_ap.cpp',
     'pdfium/fpdfsdk/fxedit/fxet_edit.cpp',
     'pdfium/fpdfsdk/fxedit/fxet_list.cpp',
 ]
 
 # fxge
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/core/fxge/agg/fx_agg_driver.cpp',
     'pdfium/core/fxge/dib/fx_dib_composite.cpp',
     'pdfium/core/fxge/dib/fx_dib_convert.cpp',
     'pdfium/core/fxge/dib/fx_dib_engine.cpp',
     'pdfium/core/fxge/dib/fx_dib_main.cpp',
     'pdfium/core/fxge/dib/fx_dib_transform.cpp',
     'pdfium/core/fxge/fontdata/chromefontdata/FoxitDingbats.cpp',
     'pdfium/core/fxge/fontdata/chromefontdata/FoxitFixed.cpp',
@@ -392,116 +410,139 @@ SOURCES += [
     'pdfium/core/fxge/ge/cfx_unicodeencoding.cpp',
     'pdfium/core/fxge/ge/cttfontdesc.cpp',
     'pdfium/core/fxge/ge/fx_ge_fontmap.cpp',
     'pdfium/core/fxge/ge/fx_ge_linux.cpp',
     'pdfium/core/fxge/ge/fx_ge_text.cpp',
     'pdfium/core/fxge/ifx_renderdevicedriver.cpp',
 ]
 if CONFIG['OS_TARGET'] == 'WINNT':
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'pdfium/core/fxge/win32/cfx_psrenderer.cpp',
         'pdfium/core/fxge/win32/cpsoutput.cpp',
         'pdfium/core/fxge/win32/fx_win32_device.cpp',
         'pdfium/core/fxge/win32/fx_win32_dib.cpp',
-        'pdfium/core/fxge/win32/fx_win32_dwrite.cpp',
-        'pdfium/core/fxge/win32/fx_win32_gdipext.cpp',
         'pdfium/core/fxge/win32/fx_win32_print.cpp',
     ]
+    SOURCES += [
+        # not able to be unified because of the error:
+        # - 'boolean': redefinition; different basic types
+        # - 'BOOLEAN': redefinition; different basic types
+        'pdfium/core/fxge/win32/fx_win32_dwrite.cpp',
+    ]
+    SOURCES += [
+        # avoid other files being polluted by WIN32_LEAN_AND_MEAN macro
+        'pdfium/core/fxge/win32/fx_win32_gdipext.cpp',
+    ]
 if CONFIG['OS_TARGET'] == 'Darwin':
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'pdfium/core/fxge/apple/fx_apple_platform.cpp',
         'pdfium/core/fxge/apple/fx_mac_imp.cpp',
         'pdfium/core/fxge/apple/fx_quartz_device.cpp',
     ]
 if CONFIG['OS_TARGET'] == 'Android':
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'pdfium/core/fxge/android/cfpf_skiadevicemodule.cpp',
         'pdfium/core/fxge/android/cfpf_skiafont.cpp',
         'pdfium/core/fxge/android/cfpf_skiafontmgr.cpp',
         'pdfium/core/fxge/android/cfx_androidfontinfo.cpp',
         'pdfium/core/fxge/android/fx_android_imp.cpp',
     ]
 
 # javascript
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/fpdfsdk/javascript/JS_Runtime_Stub.cpp',
 ]
 
 # pdfwindow
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/fpdfsdk/pdfwindow/cpwl_color.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_Button.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_Caret.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_ComboBox.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_Edit.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_EditCtrl.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_FontMap.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_Icon.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_ListBox.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_ScrollBar.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_SpecialButton.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_Utils.cpp',
     'pdfium/fpdfsdk/pdfwindow/PWL_Wnd.cpp',
 ]
 
 # third_party:fx_agg
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/third_party/agg23/agg_curves.cpp',
     'pdfium/third_party/agg23/agg_path_storage.cpp',
     'pdfium/third_party/agg23/agg_rasterizer_scanline_aa.cpp',
     'pdfium/third_party/agg23/agg_vcgen_dash.cpp',
     'pdfium/third_party/agg23/agg_vcgen_stroke.cpp',
 ]
 
 # third_party:bigint
-SOURCES += [
-    'pdfium/third_party/bigint/BigInteger.cc',
+UNIFIED_SOURCES += [
     'pdfium/third_party/bigint/BigIntegerUtils.cc',
+    'pdfium/third_party/bigint/BigUnsignedInABase.cc',
+]
+SOURCES += [
+    # not able to be unified because of the error:
+    # - 'DTRT_ALIASED': macro redefinition
+    'pdfium/third_party/bigint/BigInteger.cc',
     'pdfium/third_party/bigint/BigUnsigned.cc',
-    'pdfium/third_party/bigint/BigUnsignedInABase.cc',
 ]
 
 # third_party:fx_freetype
 LOCAL_INCLUDES += [
     '/modules/freetype2/include',
     '/modules/freetype2/src',
 ]
 USE_LIBS += [
     'freetype',
 ]
 
 # third_party:fx_lcms2
-SOURCES += [
+UNIFIED_SOURCES += [
     'pdfium/third_party/lcms2-2.6/src/cmscam02.c',
     'pdfium/third_party/lcms2-2.6/src/cmscgats.c',
     'pdfium/third_party/lcms2-2.6/src/cmscnvrt.c',
     'pdfium/third_party/lcms2-2.6/src/cmserr.c',
     'pdfium/third_party/lcms2-2.6/src/cmsgamma.c',
     'pdfium/third_party/lcms2-2.6/src/cmsgmt.c',
     'pdfium/third_party/lcms2-2.6/src/cmshalf.c',
     'pdfium/third_party/lcms2-2.6/src/cmsintrp.c',
     'pdfium/third_party/lcms2-2.6/src/cmsio0.c',
     'pdfium/third_party/lcms2-2.6/src/cmsio1.c',
     'pdfium/third_party/lcms2-2.6/src/cmslut.c',
     'pdfium/third_party/lcms2-2.6/src/cmsmd5.c',
     'pdfium/third_party/lcms2-2.6/src/cmsmtrx.c',
-    'pdfium/third_party/lcms2-2.6/src/cmsnamed.c',
     'pdfium/third_party/lcms2-2.6/src/cmsopt.c',
     'pdfium/third_party/lcms2-2.6/src/cmspack.c',
     'pdfium/third_party/lcms2-2.6/src/cmspcs.c',
     'pdfium/third_party/lcms2-2.6/src/cmsplugin.c',
-    'pdfium/third_party/lcms2-2.6/src/cmsps2.c',
     'pdfium/third_party/lcms2-2.6/src/cmssamp.c',
     'pdfium/third_party/lcms2-2.6/src/cmssm.c',
-    'pdfium/third_party/lcms2-2.6/src/cmstypes.c',
     'pdfium/third_party/lcms2-2.6/src/cmsvirt.c',
     'pdfium/third_party/lcms2-2.6/src/cmswtpnt.c',
     'pdfium/third_party/lcms2-2.6/src/cmsxform.c',
 ]
+SOURCES += [
+    # not able to be unified because of the error:
+    # - function 'cmsUInt32Number mywcslen(const wchar_t *)' already has a body
+    'pdfium/third_party/lcms2-2.6/src/cmsnamed.c',
+
+    # not able to be unified because of the error:
+    # - 'WriteCLUT': redefinition; different basic types
+    'pdfium/third_party/lcms2-2.6/src/cmsps2.c',
+
+    # not able to be unified because of the error:
+    # - function 'cmsUInt32Number mywcslen(const wchar_t *)' already has a body
+    # - 'WriteCLUT': redefinition; different basic types
+    'pdfium/third_party/lcms2-2.6/src/cmstypes.c',
+]
 
 # third_party:fx_zlib
 LOCAL_INCLUDES += [
     '/modules/zlib/src',
 ]
 USE_LIBS += [
     'zlib',
 ]
--- a/netwerk/base/NetUtil.jsm
+++ b/netwerk/base/NetUtil.jsm
@@ -20,16 +20,19 @@ const Cc = Components.classes;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 const PR_UINT32_MAX = 0xffffffff;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
+const BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
+                                                 "nsIBinaryInputStream", "setInputStream");
+
 ////////////////////////////////////////////////////////////////////////////////
 //// NetUtil Object
 
 this.NetUtil = {
     /**
      * Function to perform simple async copying from aSource (an input stream)
      * to aSink (an output stream).  The copy will happen on some background
      * thread.  Both streams will be closed when the copy completes.
@@ -443,16 +446,53 @@ this.NetUtil = {
         catch (e) {
             // Adjust the stack so it throws at the caller's location.
             throw new Components.Exception(e.message, e.result,
                                            Components.stack.caller, e.data);
         }
     },
 
     /**
+     * Reads aCount bytes from aInputStream into a string.
+     *
+     * @param {nsIInputStream} aInputStream
+     *        The input stream to read from.
+     * @param {integer} [aCount = aInputStream.available()]
+     *        The number of bytes to read from the stream.
+     *
+     * @return the bytes from the input stream in string form.
+     *
+     * @throws NS_ERROR_INVALID_ARG if aInputStream is not an nsIInputStream.
+     * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from aInputStream would
+     *         block the calling thread (non-blocking mode only).
+     * @throws NS_ERROR_FAILURE if there are not enough bytes available to read
+     *         aCount amount of data.
+     */
+    readInputStream(aInputStream, aCount)
+    {
+        if (!(aInputStream instanceof Ci.nsIInputStream)) {
+            let exception = new Components.Exception(
+                "First argument should be an nsIInputStream",
+                Cr.NS_ERROR_INVALID_ARG,
+                Components.stack.caller
+            );
+            throw exception;
+        }
+
+        if (!aCount) {
+            aCount = aInputStream.available();
+        }
+
+        let stream = new BinaryInputStream(aInputStream);
+        let result = new ArrayBuffer(aCount);
+        stream.readArrayBuffer(result.byteLength, result);
+        return result;
+    },
+
+    /**
      * Returns a reference to nsIIOService.
      *
      * @return a reference to nsIIOService.
      */
     get ioService()
     {
         delete this.ioService;
         return this.ioService = Cc["@mozilla.org/network/io-service;1"].
--- a/netwerk/protocol/data/nsDataHandler.cpp
+++ b/netwerk/protocol/data/nsDataHandler.cpp
@@ -47,25 +47,19 @@ NS_IMETHODIMP
 nsDataHandler::GetDefaultPort(int32_t *result) {
     // no ports for data protocol
     *result = -1;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDataHandler::GetProtocolFlags(uint32_t *result) {
-    *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
-              URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE |
+    *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
+              URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE |
               URI_SYNC_LOAD_IS_OK;
-
-    // Until Bug 1324406 and all it's dependencies are fixed
-    // data: URIs inherit the security context.
-    if (!nsIOService::IsDataURIUniqueOpaqueOrigin()) {
-        *result |= URI_INHERITS_SECURITY_CONTEXT;
-    }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDataHandler::NewURI(const nsACString &aSpec,
                       const char *aCharset, // ignore charset info
                       nsIURI *aBaseURI,
                       nsIURI **result) {
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -480,16 +480,24 @@ nsHttpChannel::Connect()
             if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
                 return AsyncCall(&nsHttpChannel::HandleAsyncFallback);
             }
             return NS_ERROR_DOCUMENT_NOT_CACHED;
         }
         // otherwise, let's just proceed without using the cache.
     }
 
+    // When racing, if OnCacheEntryAvailable is called before AsyncOpenURI
+    // returns, then we may not have started reading from the cache.
+    // If the content is valid, we should attempt to do so, as technically the
+    // cache has won the race.
+    if (sRCWNEnabled && mCachedContentIsValid && mNetworkTriggered) {
+        Unused << ReadFromCache(true);
+    }
+
     return TriggerNetwork(0);
 }
 
 nsresult
 nsHttpChannel::TryHSTSPriming()
 {
     bool isHttpScheme;
     nsresult rv = mURI->SchemeIs("http", &isHttpScheme);
--- a/netwerk/streamconv/converters/nsFTPDirListingConv.cpp
+++ b/netwerk/streamconv/converters/nsFTPDirListingConv.cpp
@@ -284,16 +284,23 @@ nsFTPDirListingConv::DigestBufferLines(c
             aString.Append(' ');
         }
         else
             aString.AppendLiteral("0 ");
 
 
         // MODIFIED DATE
         char buffer[256] = "";
+
+        // ParseFTPList can return time structure with invalid values.
+        // PR_NormalizeTime will set all values into valid limits.
+        result.fe_time.tm_params.tp_gmt_offset = 0;
+        result.fe_time.tm_params.tp_dst_offset = 0;
+        PR_NormalizeTime(&result.fe_time, PR_GMTParameters);
+
         // Note: The below is the RFC822/1123 format, as required by
         // the application/http-index-format specs
         // viewers of such a format can then reformat this into the
         // current locale (or anything else they choose)
         PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
                                "%a, %d %b %Y %H:%M:%S", &result.fe_time );
 
         nsAutoCString escaped;
--- a/netwerk/test/unit/test_bug365133.js
+++ b/netwerk/test/unit/test_bug365133.js
@@ -1,66 +1,66 @@
 const URL = "ftp://localhost/bug365133/";
 
 const tests = [
   [ /* Unix style listing, space at the end of filename */
     "drwxrwxr-x    2 500      500          4096 Jan 01  2000 a \r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"a%20\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n"
+    "201: \"a%20\" 0 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n"
   ],
   [ /* Unix style listing, space at the end of link name */
     "lrwxrwxrwx    1 500      500             2 Jan 01  2000 l  -> a \r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"l%20\" 2 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
+    "201: \"l%20\" 2 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
   ],
   [ /* Unix style listing, regular file with " -> " in name */
     "-rw-rw-r--    1 500      500             0 Jan 01  2000 arrow -> in name \r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"arrow%20-%3E%20in%20name%20\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"
+    "201: \"arrow%20-%3E%20in%20name%20\" 0 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"
   ],
   [ /* Unix style listing, tab at the end of filename */
     "drwxrwxrwx    2 500      500          4096 Jan 01  2000 t	\r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"t%09\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n"
+    "201: \"t%09\" 0 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n"
   ],
   [ /* Unix style listing, multiple " -> " in filename */
     "lrwxrwxrwx    1 500      500            26 Jan 01  2000 symlink with arrow -> in name -> file with arrow -> in name\r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"symlink%20with%20arrow%20-%3E%20in%20name\" 26 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
+    "201: \"symlink%20with%20arrow%20-%3E%20in%20name\" 26 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
   ],
   [ /* Unix style listing, multiple " -> " in filename, incorrect filesize */
     "lrwxrwxrwx    1 500      500             0 Jan 01  2000 symlink with arrow -> in name -> file with arrow -> in name\r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"symlink%20with%20arrow%20-%3E%20in%20name%20-%3E%20file%20with%20arrow\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
+    "201: \"symlink%20with%20arrow%20-%3E%20in%20name%20-%3E%20file%20with%20arrow\" 0 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
   ],
   [ /* DOS style listing, space at the end of filename, year 1999 */
     "01-01-99  01:00AM                 1024 file \r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"file%20\" 1024 Sun%2C%2001%20Jan%201999%2001%3A00%3A00 FILE \n"
+    "201: \"file%20\" 1024 Fri%2C%2001%20Jan%201999%2001%3A00%3A00 FILE \n"
   ],
   [ /* DOS style listing, tab at the end of filename, year 2000 */
     "01-01-00  01:00AM                 1024 file	\r\n"
   ,
     "300: " + URL + "\n" +
     "200: filename content-length last-modified file-type\n" +
-    "201: \"file%09\" 1024 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"
+    "201: \"file%09\" 1024 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"
   ]
 ]
 
 function checkData(request, data, ctx) {
   do_check_eq(tests[0][1], data);
   tests.shift();
   do_execute_soon(next_test);
 }
--- a/netwerk/test/unit/test_bug484684.js
+++ b/netwerk/test/unit/test_bug484684.js
@@ -2,70 +2,70 @@ const URL = "ftp://localhost/bug464884/"
 
 const tests = [
   // standard ls unix format
   ["-rw-rw-r--    1 500      500             0 Jan 01  2000 file1\r\n" +
    "-rw-rw-r--    1 500      500             0 Jan 01  2000  file2\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"file1\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n" +
-   "201: \"%20file2\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"],
+   "201: \"file1\" 0 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n" +
+   "201: \"%20file2\" 0 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"],
   // old Hellsoft unix format
   ["-[RWCEMFA] supervisor         214059       Jan 01  2000    file1\r\n" +
    "-[RWCEMFA] supervisor         214059       Jan 01  2000     file2\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"file1\" 214059 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n" +
-   "201: \"file2\" 214059 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"],
+   "201: \"file1\" 214059 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n" +
+   "201: \"file2\" 214059 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"],
   // new Hellsoft unix format
   ["- [RWCEAFMS] jrd                    192 Jan 01  2000 file1\r\n"+
    "- [RWCEAFMS] jrd                    192 Jan 01  2000  file2\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"file1\" 192 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n" +
-   "201: \"%20file2\" 192 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"],
+   "201: \"file1\" 192 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n" +
+   "201: \"%20file2\" 192 Sat%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"],
   // DOS format with correct offsets
   ["01-01-00  01:00AM       <DIR>          dir1\r\n" +
    "01-01-00  01:00AM       <JUNCTION>     junction1 -> foo1\r\n" +
    "01-01-00  01:00AM                95077 file1\r\n" +
    "01-01-00  01:00AM       <DIR>           dir2\r\n" +
    "01-01-00  01:00AM       <JUNCTION>      junction2 ->  foo2\r\n" +
    "01-01-00  01:00AM                95077  file2\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"dir1\" 0 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
-   "201: \"junction1\"  Sun%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
-   "201: \"file1\" 95077 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n" +
-   "201: \"%20dir2\" 0 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
-   "201: \"%20junction2\"  Sun%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
-   "201: \"%20file2\" 95077 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"],
+   "201: \"dir1\" 0 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
+   "201: \"junction1\"  Sat%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
+   "201: \"file1\" 95077 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n" +
+   "201: \"%20dir2\" 0 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
+   "201: \"%20junction2\"  Sat%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
+   "201: \"%20file2\" 95077 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"],
   // DOS format with wrong offsets
   ["01-01-00  01:00AM       <DIR>       dir1\r\n" +
    "01-01-00  01:00AM     <DIR>             dir2\r\n" +
    "01-01-00  01:00AM   <DIR>                  dir3\r\n" +
    "01-01-00  01:00AM       <JUNCTION>  junction1 -> foo1\r\n" +
    "01-01-00  01:00AM     <JUNCTION>        junction2 ->  foo2\r\n" +
    "01-01-00  01:00AM   <JUNCTION>             junction3 ->  foo3\r\n" +
    "01-01-00  01:00AM               95077  file1\r\n" +
    "01-01-00  01:00AM        95077 file2\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"dir1\" 0 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
-   "201: \"dir2\" 0 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
-   "201: \"dir3\" 0 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
-   "201: \"junction1\"  Sun%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
-   "201: \"junction2\"  Sun%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
-   "201: \"junction3\"  Sun%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
-   "201: \"file1\" 95077 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n" +
-   "201: \"file2\" 95077 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"]
+   "201: \"dir1\" 0 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
+   "201: \"dir2\" 0 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
+   "201: \"dir3\" 0 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 DIRECTORY \n" +
+   "201: \"junction1\"  Sat%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
+   "201: \"junction2\"  Sat%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
+   "201: \"junction3\"  Sat%2C%2001%20Jan%202000%2001%3A00%3A00 SYMBOLIC-LINK \n" +
+   "201: \"file1\" 95077 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n" +
+   "201: \"file2\" 95077 Sat%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"]
 ]
 
 function checkData(request, data, ctx) {
   do_check_eq(tests[0][1], data);
   tests.shift();
   do_execute_soon(next_test);
 }
 
--- a/netwerk/test/unit/test_bug515583.js
+++ b/netwerk/test/unit/test_bug515583.js
@@ -7,18 +7,18 @@ const tests = [
    "[RWCEM1]B; 4 4-MAR-1993 18:09:01.12\r\n" +
    "[RWCEM1];1 4 5-MAR-1993 18:09:01.12\r\n" +
    "[RWCEM1]; 4 6-MAR-1993 18:09:01.12\r\n" +
    "[RWCEM1]C;1D 4 7-MAR-1993 18:09:01.12\r\n" +
    "[RWCEM1]E;1 4 8-MAR-1993 18:09:01.12\r\n"
   ,
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"A\" 2048 Sun%2C%2003%20Mar%201993%2018%3A09%3A01 FILE \n" +
-   "201: \"E\" 2048 Sun%2C%2008%20Mar%201993%2018%3A09%3A01 FILE \n"]
+   "201: \"A\" 2048 Wed%2C%2003%20Mar%201993%2018%3A09%3A01 FILE \n" +
+   "201: \"E\" 2048 Mon%2C%2008%20Mar%201993%2018%3A09%3A01 FILE \n"]
    ,
    ["\r\r\r\n"
    ,
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n"]
 ]
 
 function checkData(request, data, ctx) {
--- a/netwerk/test/unit/test_bug543805.js
+++ b/netwerk/test/unit/test_bug543805.js
@@ -1,47 +1,49 @@
 const URL = "ftp://localhost/bug543805/";
 
+var dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
 var year = new Date().getFullYear().toString();
+var day = dayNames[new Date(year, 0, 1).getDay()];
 
 const tests = [
   // AIX ls format
   ["-rw-r--r--   1 0                11 Jan  1 20:19  nodup.file\r\n" +
    "-rw-r--r--   1 0                22 Jan  1 20:19  test.blankfile\r\n" +
    "-rw-r--r--   1 0                33 Apr  1 2008   test2.blankfile\r\n" +
    "-rw-r--r--   1 0                44 Jan  1 20:19 nodup.file\r\n" +
    "-rw-r--r--   1 0                55 Jan  1 20:19 test.file\r\n" +
    "-rw-r--r--   1 0                66 Apr  1 2008  test2.file\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"%20nodup.file\" 11 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"%20test.blankfile\" 22 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"%20test2.blankfile\" 33 Sun%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n" +
-   "201: \"nodup.file\" 44 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"test.file\" 55 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"test2.file\" 66 Sun%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n"],
+   "201: \"%20nodup.file\" 11 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"%20test.blankfile\" 22 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"%20test2.blankfile\" 33 Tue%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n" +
+   "201: \"nodup.file\" 44 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"test.file\" 55 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"test2.file\" 66 Tue%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n"],
 
   // standard ls format
   [
    "-rw-r--r--    1 500      500            11 Jan  1 20:19  nodup.file\r\n" +
    "-rw-r--r--    1 500      500            22 Jan  1 20:19  test.blankfile\r\n" +
    "-rw-r--r--    1 500      500            33 Apr  1  2008  test2.blankfile\r\n" +
    "-rw-r--r--    1 500      500            44 Jan  1 20:19 nodup.file\r\n" +
    "-rw-r--r--    1 500      500            55 Jan  1 20:19 test.file\r\n" +
    "-rw-r--r--    1 500      500            66 Apr  1  2008 test2.file\r\n",
 
    "300: " + URL + "\n" +
    "200: filename content-length last-modified file-type\n" +
-   "201: \"%20nodup.file\" 11 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"%20test.blankfile\" 22 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"%20test2.blankfile\" 33 Sun%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n" +
-   "201: \"nodup.file\" 44 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"test.file\" 55 Sun%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
-   "201: \"test2.file\" 66 Sun%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n"]
+   "201: \"%20nodup.file\" 11 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"%20test.blankfile\" 22 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"%20test2.blankfile\" 33 Tue%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n" +
+   "201: \"nodup.file\" 44 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"test.file\" 55 " + day + "%2C%2001%20Jan%20" + year + "%2020%3A19%3A00 FILE \n" +
+   "201: \"test2.file\" 66 Tue%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n"]
 ]
 
 function checkData(request, data, ctx) {
   do_check_eq(tests[0][1], data);
   tests.shift();
   do_execute_soon(next_test);
 }
 
--- a/python/mozbuild/mozbuild/codecoverage/lcov_rewriter.py
+++ b/python/mozbuild/mozbuild/codecoverage/lcov_rewriter.py
@@ -502,16 +502,17 @@ class UrlFinder(object):
         for leaf in reversed(mozpath.split(objdir_path)):
             offset += len(leaf)
             if objdir_path[:-offset] in self._install_mapping:
                 pattern_prefix, is_pp = self._install_mapping[objdir_path[:-offset]]
                 full_leaf = objdir_path[len(objdir_path) - offset:]
                 src_prefix = ''.join(_prefix(pattern_prefix))
                 self._install_mapping[objdir_path] = (mozpath.join(src_prefix, full_leaf),
                                                       is_pp)
+                break
             offset += 1
 
     def _install_info(self, objdir_path):
         if objdir_path not in self._install_mapping:
             # If our path is missing, some prefix of it may be in the install
             # mapping mapped to a wildcard.
             self._find_install_prefix(objdir_path)
         if objdir_path not in self._install_mapping:
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
@@ -38,19 +38,16 @@ std::unique_ptr<BYTE[]> GetTokenInfo(con
   *error = ERROR_SUCCESS;
   return buffer;
 }
 
 }  // namespace
 
 namespace sandbox {
 
-// We want to use restricting SIDs in the tokens by default.
-bool gUseRestricting = true;
-
 RestrictedToken::RestrictedToken()
     : integrity_level_(INTEGRITY_LEVEL_LAST),
       init_(false),
       lockdown_default_dacl_(false) {}
 
 RestrictedToken::~RestrictedToken() {
 }
 
@@ -81,17 +78,17 @@ DWORD RestrictedToken::Init(const HANDLE
 
 DWORD RestrictedToken::GetRestrictedToken(
     base::win::ScopedHandle* token) const {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
   size_t deny_size = sids_for_deny_only_.size();
-  size_t restrict_size = gUseRestricting ? sids_to_restrict_.size() : 0;
+  size_t restrict_size = sids_to_restrict_.size();
   size_t privileges_size = privileges_to_disable_.size();
 
   SID_AND_ATTRIBUTES *deny_only_array = NULL;
   if (deny_size) {
     deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
 
     for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
       deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
@@ -224,41 +221,33 @@ DWORD RestrictedToken::GetRestrictedToke
   return ERROR_SUCCESS;
 }
 
 DWORD RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
-  // If this is normally a token with restricting SIDs, but we're not allowing
-  // them, then use the sids_to_restrict_ as an exceptions list to give a
-  // similar effect.
-  std::vector<Sid>* localExpections =
-    gUseRestricting || !sids_to_restrict_.size() ? exceptions : &sids_to_restrict_;
-
   DWORD error;
   std::unique_ptr<BYTE[]> buffer =
       GetTokenInfo(effective_token_, TokenGroups, &error);
 
   if (!buffer)
     return error;
 
   TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
 
-  // Build the list of the deny only group SIDs.  We want to be able to have
-  // logon SID as deny only, if we're not allowing restricting SIDs.
+  // Build the list of the deny only group SIDs
   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
-        (!gUseRestricting ||
-         (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0)) {
+        (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
       bool should_ignore = false;
-      if (localExpections) {
-        for (unsigned int j = 0; j < localExpections->size(); ++j) {
-          if (::EqualSid(const_cast<SID*>((*localExpections)[j].GetPSID()),
+      if (exceptions) {
+        for (unsigned int j = 0; j < exceptions->size(); ++j) {
+          if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
                           token_groups->Groups[i].Sid)) {
             should_ignore = true;
             break;
           }
         }
       }
       if (!should_ignore) {
         sids_for_deny_only_.push_back(
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token.h
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.h
@@ -20,19 +20,16 @@
 #define SE_GROUP_INTEGRITY (0x00000020L)
 #endif
 #ifndef SE_GROUP_INTEGRITY_ENABLED
 #define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
 #endif
 
 namespace sandbox {
 
-// Whether we are allowing restricting SIDs in the access tokens or not.
-extern bool gUseRestricting;
-
 // Handles the creation of a restricted token using the effective token or
 // any token handle.
 // Sample usage:
 //    RestrictedToken restricted_token;
 //    DWORD err_code = restricted_token.Init(NULL);  // Use the current
 //                                                   // effective token
 //    if (ERROR_SUCCESS != err_code) {
 //      // handle error.
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
@@ -17,16 +17,17 @@
 #include "sandbox/win/src/sid.h"
 
 namespace sandbox {
 
 DWORD CreateRestrictedToken(TokenLevel security_level,
                             IntegrityLevel integrity_level,
                             TokenType token_type,
                             bool lockdown_default_dacl,
+                            bool use_restricting_sids,
                             base::win::ScopedHandle* token) {
   RestrictedToken restricted_token;
   restricted_token.Init(NULL);  // Initialized with the current process token
   if (lockdown_default_dacl)
     restricted_token.SetLockdownDefaultDacl();
 
   std::vector<base::string16> privilege_exceptions;
   std::vector<Sid> sid_exceptions;
@@ -40,19 +41,22 @@ DWORD CreateRestrictedToken(TokenLevel s
       deny_sids = false;
       remove_privileges = false;
       break;
     }
     case USER_RESTRICTED_SAME_ACCESS: {
       deny_sids = false;
       remove_privileges = false;
 
-      unsigned err_code = restricted_token.AddRestrictingSidAllSids();
-      if (ERROR_SUCCESS != err_code)
-        return err_code;
+      if (use_restricting_sids) {
+        unsigned err_code = restricted_token.AddRestrictingSidAllSids();
+        if (ERROR_SUCCESS != err_code) {
+          return err_code;
+        }
+      }
 
       break;
     }
     case USER_NON_ADMIN: {
       deny_sids = false;
       deny_only_sids.push_back(WinBuiltinAdministratorsSid);
       deny_only_sids.push_back(WinAccountAdministratorSid);
       deny_only_sids.push_back(WinAccountDomainAdminsSid);
@@ -66,54 +70,57 @@ DWORD CreateRestrictedToken(TokenLevel s
       break;
     }
     case USER_INTERACTIVE: {
       sid_exceptions.push_back(WinBuiltinUsersSid);
       sid_exceptions.push_back(WinWorldSid);
       sid_exceptions.push_back(WinInteractiveSid);
       sid_exceptions.push_back(WinAuthenticatedUserSid);
       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
-      restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
-      restricted_token.AddRestrictingSid(WinWorldSid);
-      restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
-      restricted_token.AddRestrictingSidCurrentUser();
-      restricted_token.AddRestrictingSidLogonSession();
+      if (use_restricting_sids) {
+        restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+        restricted_token.AddRestrictingSid(WinWorldSid);
+        restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+        restricted_token.AddRestrictingSidCurrentUser();
+        restricted_token.AddRestrictingSidLogonSession();
+      }
       break;
     }
     case USER_LIMITED: {
       sid_exceptions.push_back(WinBuiltinUsersSid);
       sid_exceptions.push_back(WinWorldSid);
       sid_exceptions.push_back(WinInteractiveSid);
       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
-      // This breaks web audio, so we don't want to do this in the restricting
-      // SIDs (normal) case. See bug 1378061.
-      if (!gUseRestricting) {
-        restricted_token.AddUserSidForDenyOnly();
+      if (use_restricting_sids) {
+        restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+        restricted_token.AddRestrictingSid(WinWorldSid);
+        restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+
+        // This token has to be able to create objects in BNO.
+        // Unfortunately, on Vista+, it needs the current logon sid
+        // in the token to achieve this. You should also set the process to be
+        // low integrity level so it can't access object created by other
+        // processes.
+        restricted_token.AddRestrictingSidLogonSession();
       }
-      restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
-      restricted_token.AddRestrictingSid(WinWorldSid);
-      restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
-
-      // This token has to be able to create objects in BNO.
-      // Unfortunately, on Vista+, it needs the current logon sid
-      // in the token to achieve this. You should also set the process to be
-      // low integrity level so it can't access object created by other
-      // processes.
-      restricted_token.AddRestrictingSidLogonSession();
       break;
     }
     case USER_RESTRICTED: {
       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
       restricted_token.AddUserSidForDenyOnly();
-      restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+      if (use_restricting_sids) {
+        restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+      }
       break;
     }
     case USER_LOCKDOWN: {
       restricted_token.AddUserSidForDenyOnly();
-      restricted_token.AddRestrictingSid(WinNullSid);
+      if (use_restricting_sids) {
+        restricted_token.AddRestrictingSid(WinNullSid);
+      }
       break;
     }
     default: {
       return ERROR_BAD_ARGUMENTS;
     }
   }
 
   DWORD err_code = ERROR_SUCCESS;
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
@@ -35,16 +35,17 @@ enum TokenType {
 // running under the token.
 // If the function succeeds, the return value is ERROR_SUCCESS. If the
 // function fails, the return value is the win32 error code corresponding to
 // the error.
 DWORD CreateRestrictedToken(TokenLevel security_level,
                             IntegrityLevel integrity_level,
                             TokenType token_type,
                             bool lockdown_default_dacl,
+                            bool use_restricting_sids,
                             base::win::ScopedHandle* token);
 
 // Sets the integrity label on a object handle.
 DWORD SetObjectIntegrityLabel(HANDLE handle, SE_OBJECT_TYPE type,
                               const wchar_t* ace_access,
                               const wchar_t* integrity_level_sid);
 
 // Sets the integrity level on a token. This is only valid on Vista. It returns
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
@@ -95,16 +95,21 @@ class TargetPolicy {
   virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0;
 
   // Returns the initial token level.
   virtual TokenLevel GetInitialTokenLevel() const = 0;
 
   // Returns the lockdown token level.
   virtual TokenLevel GetLockdownTokenLevel() const = 0;
 
+  // Sets that we should not use restricting SIDs in the access tokens. We need
+  // to do this in some circumstances even though it weakens the sandbox.
+  // The default is to use them.
+  virtual void SetDoNotUseRestrictingSIDs() = 0;
+
   // Sets the security level of the Job Object to which the target process will
   // belong. This setting is permanent and cannot be changed once the target
   // process is spawned. The job controls the global security settings which
   // can not be specified in the token security profile.
   // job_level: the security level for the job. See the explanation of each
   //   level in the JobLevel definition.
   // ui_exceptions: specify what specific rights that are disabled in the
   //   chosen job_level that need to be granted. Use this parameter to avoid
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -178,16 +178,20 @@ ResultCode PolicyBase::SetTokenLevel(Tok
 TokenLevel PolicyBase::GetInitialTokenLevel() const {
   return initial_level_;
 }
 
 TokenLevel PolicyBase::GetLockdownTokenLevel() const {
   return lockdown_level_;
 }
 
+void PolicyBase::SetDoNotUseRestrictingSIDs() {
+  use_restricting_sids_ = false;
+}
+
 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) {
   if (memory_limit_ && job_level == JOB_NONE) {
     return SBOX_ERROR_BAD_PARAMS;
   }
   job_level_ = job_level;
   ui_exceptions_ = ui_exceptions;
   return SBOX_ALL_OK;
 }
@@ -432,17 +436,18 @@ ResultCode PolicyBase::MakeJobObject(bas
 
 ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
                                   base::win::ScopedHandle* lockdown,
                                   base::win::ScopedHandle* lowbox) {
   // Create the 'naked' token. This will be the permanent token associated
   // with the process and therefore with any thread that is not impersonating.
   DWORD result =
       CreateRestrictedToken(lockdown_level_, integrity_level_, PRIMARY,
-                            lockdown_default_dacl_, lockdown);
+                            lockdown_default_dacl_, use_restricting_sids_,
+                            lockdown);
   if (ERROR_SUCCESS != result)
     return SBOX_ERROR_GENERIC;
 
   // If we're launching on the alternate desktop we need to make sure the
   // integrity label on the object is no higher than the sandboxed process's
   // integrity level. So, we lower the label on the desktop process if it's
   // not already low enough for our process.
   if (alternate_desktop_handle_ && use_alternate_desktop_ &&
@@ -488,17 +493,18 @@ ResultCode PolicyBase::MakeTokens(base::
     lowbox->Set(token_lowbox);
   }
 
   // Create the 'better' token. We use this token as the one that the main
   // thread uses when booting up the process. It should contain most of
   // what we need (before reaching main( ))
   result =
       CreateRestrictedToken(initial_level_, integrity_level_, IMPERSONATION,
-                            lockdown_default_dacl_, initial);
+                            lockdown_default_dacl_, use_restricting_sids_,
+                            initial);
   if (ERROR_SUCCESS != result)
     return SBOX_ERROR_GENERIC;
 
   return SBOX_ALL_OK;
 }
 
 PSID PolicyBase::GetLowBoxSid() const {
   return lowbox_sid_;
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
@@ -37,16 +37,17 @@ class PolicyBase final : public TargetPo
   PolicyBase();
 
   // TargetPolicy:
   void AddRef() override;
   void Release() override;
   ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) override;
   TokenLevel GetInitialTokenLevel() const override;
   TokenLevel GetLockdownTokenLevel() const override;
+  void SetDoNotUseRestrictingSIDs() final;
   ResultCode SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) override;
   JobLevel GetJobLevel() const override;
   ResultCode SetJobMemoryLimit(size_t memory_limit) override;
   ResultCode SetAlternateDesktop(bool alternate_winstation) override;
   base::string16 GetAlternateDesktop() const override;
   ResultCode CreateAlternateDesktop(bool alternate_winstation) override;
   void DestroyAlternateDesktop() override;
   ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override;
@@ -122,16 +123,17 @@ class PolicyBase final : public TargetPo
   // The policy takes ownership of them.
   typedef std::list<TargetProcess*> TargetSet;
   TargetSet targets_;
   // Standard object-lifetime reference counter.
   volatile LONG ref_count;
   // The user-defined global policy settings.
   TokenLevel lockdown_level_;
   TokenLevel initial_level_;
+  bool use_restricting_sids_ = true;
   JobLevel job_level_;
   uint32_t ui_exceptions_;
   size_t memory_limit_;
   bool use_alternate_desktop_;
   bool use_alternate_winstation_;
   // Helps the file system policy initialization.
   bool file_system_init_;
   bool relaxed_interceptions_;
--- a/security/sandbox/win/SandboxInitialization.cpp
+++ b/security/sandbox/win/SandboxInitialization.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=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 "SandboxInitialization.h"
 
-#include "sandbox/win/src/restricted_token.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "mozilla/sandboxing/permissionsService.h"
 
 namespace mozilla {
 namespace sandboxing {
 
 static sandbox::TargetServices*
 InitializeTargetServices()
@@ -74,31 +73,15 @@ sandbox::BrokerServices*
 GetInitializedBrokerServices()
 {
   static sandbox::BrokerServices* sInitializedBrokerServices =
     InitializeBrokerServices();
 
   return sInitializedBrokerServices;
 }
 
-void
-NetworkDriveCheck()
-{
-  wchar_t exePath[MAX_PATH];
-  if (!::GetModuleFileNameW(nullptr, exePath, MAX_PATH)) {
-    return;
-  }
-
-  wchar_t volPath[MAX_PATH];
-  if (!::GetVolumePathNameW(exePath, volPath, MAX_PATH)) {
-    return;
-  }
-
-  sandbox::gUseRestricting = (::GetDriveTypeW(volPath) != DRIVE_REMOTE);
-}
-
 PermissionsService* GetPermissionsService()
 {
   return PermissionsService::GetInstance();
 }
 
 } // sandboxing
 } // mozilla
--- a/security/sandbox/win/SandboxInitialization.h
+++ b/security/sandbox/win/SandboxInitialization.h
@@ -38,22 +38,14 @@ void LowerSandbox();
 
 /**
  * Initializes (if required) and returns the Chromium sandbox BrokerServices.
  *
  * @return the BrokerServices or null if the creation or initialization failed.
  */
 sandbox::BrokerServices* GetInitializedBrokerServices();
 
-/**
- * Checks to see if we are running from a network drive and sets a flag in
- * sandbox code to disable the use of restricting SIDs.
- * Using restricting SIDs blocks access to network drives and prevents DLL
- * loading during initial sandboxed child process start-up.
- */
-void NetworkDriveCheck();
-
 PermissionsService* GetPermissionsService();
 
 } // sandboxing
 } // mozilla
 
 #endif // mozilla_sandboxing_SandboxInitialization_h
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -1,38 +1,47 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=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 "sandboxBroker.h"
 
+#include <string>
+
 #include "base/win/windows_version.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Logging.h"
 #include "mozilla/NSPRLogModulesParser.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Telemetry.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsCOMPtr.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsIProperties.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/security_level.h"
+#include "WinUtils.h"
 
 namespace mozilla
 {
 
 sandbox::BrokerServices *SandboxBroker::sBrokerService = nullptr;
 
+// This is set to true in Initialize when our exe file name has a drive type of
+// DRIVE_REMOTE, so that we can tailor the sandbox policy as some settings break
+// fundamental things when running from a network drive. We default to false in
+// case those checks fail as that gives us the strongest policy.
+bool SandboxBroker::sRunningFromNetworkDrive = false;
+
 // Cached special directories used for adding policy rules.
 static UniquePtr<nsString> sBinDir;
 static UniquePtr<nsString> sProfileDir;
 static UniquePtr<nsString> sContentTempDir;
 static UniquePtr<nsString> sRoamingAppDataDir;
 static UniquePtr<nsString> sLocalAppDataDir;
 
 static LazyLogModule sSandboxBrokerLog("SandboxBroker");
@@ -40,16 +49,33 @@ static LazyLogModule sSandboxBrokerLog("
 #define LOG_E(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Error, (__VA_ARGS__))
 #define LOG_W(...) MOZ_LOG(sSandboxBrokerLog, LogLevel::Warning, (__VA_ARGS__))
 
 /* static */
 void
 SandboxBroker::Initialize(sandbox::BrokerServices* aBrokerServices)
 {
   sBrokerService = aBrokerServices;
+
+  wchar_t exePath[MAX_PATH];
+  if (!::GetModuleFileNameW(nullptr, exePath, MAX_PATH)) {
+    return;
+  }
+
+  std::wstring exeString(exePath);
+  if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(exeString)) {
+    return;
+  }
+
+  wchar_t volPath[MAX_PATH];
+  if (!::GetVolumePathNameW(exeString.c_str(), volPath, MAX_PATH)) {
+    return;
+  }
+
+  sRunningFromNetworkDrive = (::GetDriveTypeW(volPath) == DRIVE_REMOTE);
 }
 
 static void
 CacheDirAndAutoClear(nsIProperties* aDirSvc, const char* aDirKey,
                      UniquePtr<nsString>* cacheVar)
 {
   nsCOMPtr<nsIFile> dirToCache;
   nsresult rv =
@@ -92,16 +118,19 @@ SandboxBroker::CacheRulesDirectories()
   CacheDirAndAutoClear(dirSvc, NS_WIN_APPDATA_DIR, &sRoamingAppDataDir);
   CacheDirAndAutoClear(dirSvc, NS_WIN_LOCAL_APPDATA_DIR, &sLocalAppDataDir);
 }
 
 SandboxBroker::SandboxBroker()
 {
   if (sBrokerService) {
     mPolicy = sBrokerService->CreatePolicy();
+    if (sRunningFromNetworkDrive) {
+      mPolicy->SetDoNotUseRestrictingSIDs();
+    }
   } else {
     mPolicy = nullptr;
   }
 }
 
 bool
 SandboxBroker::LaunchApp(const wchar_t *aPath,
                          const wchar_t *aArguments,
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
@@ -60,14 +60,15 @@ public:
   // processes can be added as handle duplication targets.
   bool AddTargetPeer(HANDLE aPeerProcess);
 
   // Set up dummy interceptions via the broker, so we can log calls.
   void ApplyLoggingPolicy();
 
 private:
   static sandbox::BrokerServices *sBrokerService;
+  static bool sRunningFromNetworkDrive;
   sandbox::TargetPolicy *mPolicy;
 };
 
 } // mozilla
 
 #endif
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -418,18 +418,18 @@ def set_target(config, tests):
 @transforms.add
 def set_treeherder_machine_platform(config, tests):
     """Set the appropriate task.extra.treeherder.machine.platform"""
     translation = {
         # Linux64 build platforms for asan and pgo are specified differently to
         # treeherder.
         'linux64-asan/opt': 'linux64/asan',
         'linux64-pgo/opt': 'linux64/pgo',
-        'macosx64/debug': 'osx-cross/debug',
-        'macosx64/opt': 'osx-cross/opt',
+        'macosx64/debug': 'osx-10-10/debug',
+        'macosx64/opt': 'osx-10-10/opt',
         'win64-asan/opt': 'windows10-64/asan',
         # The build names for Android platforms have partially evolved over the
         # years and need to be translated.
         'android-api-15/debug': 'android-4-3-armv7-api15/debug',
         'android-api-15/opt': 'android-4-3-armv7-api15/opt',
         'android-x86/opt': 'android-4-2-x86/opt',
         'android-api-15-gradle/opt': 'android-api-15-gradle/opt',
     }
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
@@ -4,17 +4,17 @@ skip-if = manage_instance == false || ap
 [test_geckoinstance.py]
 [test_data_driven.py]
 [test_session.py]
 [test_capabilities.py]
 [test_accessibility.py]
 [test_expectedfail.py]
 expected = fail
 [test_click.py]
-skip-if = debug && e10s # Bug 1360446
+skip-if = e10s # Bug 1360446
 [test_click_chrome.py]
 skip-if = appname == 'fennec'
 [test_checkbox.py]
 [test_checkbox_chrome.py]
 skip-if = appname == 'fennec'
 [test_elementsize.py]
 [test_elementsize_chrome.py]
 skip-if = appname == 'fennec'
--- a/testing/talos/talos/tests/perf-reftest-singletons/bloom_basic_singleton.manifest
+++ b/testing/talos/talos/tests/perf-reftest-singletons/bloom_basic_singleton.manifest
@@ -1,1 +1,1 @@
-% http://localhost/tests/perf-reftest/bloom-basic.html
+% http://localhost/tests/perf-reftest-singletons/bloom-basic.html
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -46,16 +46,17 @@
 #include "nsNetCID.h"
 #include "nsReadableUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
 #include "nsIContentPolicy.h"
+#include "nsICryptoHash.h"
 #include "nsILoadInfo.h"
 #include "nsContentUtils.h"
 #include "nsWeakReference.h"
 #include "nsIRedirectHistoryEntry.h"
 
 using mozilla::ArrayLength;
 using mozilla::BasePrincipal;
 using mozilla::OriginAttributes;
@@ -180,18 +181,21 @@ private:
   // Wrapper function for nsIStreamListener.onStopRequest to make it easy to
   // guarantee calling the callback
   nsresult OnStopRequestInternal(nsIRequest *aRequest,
                                  nsISupports *aContext,
                                  nsresult aResult,
                                  bool* aShouldBlock,
                                  uint32_t* aVerdict);
 
+  // Return the hex-encoded hash of the whole URI.
+  nsresult GetSpecHash(nsACString& aSpec, nsACString& hexEncodedHash);
+
   // Strip url parameters, fragments, and user@pass fields from the URI spec
-  // using nsIURL. If aURI is not an nsIURL, returns the original nsIURI.spec.
+  // using nsIURL. Hash data URIs and return blob URIs unfiltered.
   nsresult GetStrippedSpec(nsIURI* aUri, nsACString& spec);
 
   // Escape '/' and '%' in certificate attribute values.
   nsCString EscapeCertificateAttribute(const nsACString& aAttribute);
 
   // Escape ':' in fingerprint values.
   nsCString EscapeFingerprint(const nsACString& aAttribute);
 
@@ -290,18 +294,21 @@ nsresult
 PendingDBLookup::LookupSpec(const nsACString& aSpec,
                             bool aAllowlistOnly)
 {
   LOG(("Checking principal %s [this=%p]", aSpec.Data(), this));
   mSpec = aSpec;
   mAllowlistOnly = aAllowlistOnly;
   nsresult rv = LookupSpecInternal(aSpec);
   if (NS_FAILED(rv)) {
-    LOG(("Error in LookupSpecInternal"));
-    return mPendingLookup->OnComplete(false, NS_OK);
+    nsAutoCString errorName;
+    mozilla::GetErrorName(rv, errorName);
+    LOG(("Error in LookupSpecInternal() [rv = %s, this = %p]",
+         errorName.get(), this));
+    return mPendingLookup->LookupNext(); // ignore this lookup and move to next
   }
   // LookupSpecInternal has called nsIUrlClassifierCallback.lookup, which is
   // guaranteed to call HandleEvent.
   return rv;
 }
 
 nsresult
 PendingDBLookup::LookupSpecInternal(const nsACString& aSpec)
@@ -978,40 +985,108 @@ PendingLookup::StartLookup()
   nsresult rv = DoLookupInternal();
   if (NS_FAILED(rv)) {
     return OnComplete(false, NS_OK);
   }
   return rv;
 }
 
 nsresult
+PendingLookup::GetSpecHash(nsACString& aSpec, nsACString& hexEncodedHash)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsICryptoHash> cryptoHash =
+    do_CreateInstance("@mozilla.org/security/hash;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = cryptoHash->Init(nsICryptoHash::SHA256);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = cryptoHash->Update(reinterpret_cast<const uint8_t*>(aSpec.BeginReading()),
+                          aSpec.Length());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString binaryHash;
+  rv = cryptoHash->Finish(false, binaryHash);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // This needs to match HexEncode() in Chrome's
+  // src/base/strings/string_number_conversions.cc
+  static const char* const hex = "0123456789ABCDEF";
+  hexEncodedHash.SetCapacity(2 * binaryHash.Length());
+  for (size_t i = 0; i < binaryHash.Length(); ++i) {
+    auto c = static_cast<const unsigned char>(binaryHash[i]);
+    hexEncodedHash.Append(hex[(c >> 4) & 0x0F]);
+    hexEncodedHash.Append(hex[c & 0x0F]);
+  }
+
+  return NS_OK;
+}
+
+nsresult
 PendingLookup::GetStrippedSpec(nsIURI* aUri, nsACString& escaped)
 {
+  if (NS_WARN_IF(!aUri)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsresult rv;
+  rv = aUri->GetScheme(escaped);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (escaped.EqualsLiteral("blob")) {
+    aUri->GetSpec(escaped);
+    LOG(("PendingLookup::GetStrippedSpec(): blob URL left unstripped as '%s' [this = %p]",
+         PromiseFlatCString(escaped).get(), this));
+    return NS_OK;
+
+  } else if (escaped.EqualsLiteral("data")) {
+    // Replace URI with "data:<everything before comma>,SHA256(<whole URI>)"
+    aUri->GetSpec(escaped);
+    int32_t comma = escaped.FindChar(',');
+    if (comma > -1 &&
+        static_cast<nsCString::size_type>(comma) < escaped.Length() - 1) {
+      MOZ_ASSERT(comma > 4, "Data URIs start with 'data:'");
+      nsAutoCString hexEncodedHash;
+      rv = GetSpecHash(escaped, hexEncodedHash);
+      if (NS_SUCCEEDED(rv)) {
+        escaped.Truncate(comma + 1);
+        escaped.Append(hexEncodedHash);
+      }
+    }
+
+    LOG(("PendingLookup::GetStrippedSpec(): data URL stripped to '%s' [this = %p]",
+         PromiseFlatCString(escaped).get(), this));
+    return NS_OK;
+  }
+
   // If aURI is not an nsIURL, we do not want to check the lists or send a
   // remote query.
-  nsresult rv;
   nsCOMPtr<nsIURL> url = do_QueryInterface(aUri, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = url->GetScheme(escaped);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    LOG(("PendingLookup::GetStrippedSpec(): scheme '%s' is not supported [this = %p]",
+         PromiseFlatCString(escaped).get(), this));
+    return rv;
+  }
 
   nsCString temp;
   rv = url->GetHostPort(temp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   escaped.Append("://");
   escaped.Append(temp);
 
   rv = url->GetFilePath(temp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // nsIUrl.filePath starts with '/'
   escaped.Append(temp);
 
+  LOG(("PendingLookup::GetStrippedSpec(): URL stripped to '%s' [this = %p]",
+       PromiseFlatCString(escaped).get(), this));
   return NS_OK;
 }
 
 nsresult
 PendingLookup::DoLookupInternal()
 {
   // We want to check the target URI, its referrer, and associated redirects
   // against the local lists.
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -378,16 +378,17 @@ this.ExtensionData = class {
 
       try {
         await iter.forEach(entry => {
           results.push(entry);
         });
       } catch (e) {
         // Always return a list, even if the directory does not exist (or is
         // not a directory) for symmetry with the ZipReader behavior.
+        Cu.reportError(e);
       }
       iter.close();
 
       return results;
     }
 
     // FIXME: We need a way to do this without main thread IO.
 
@@ -635,42 +636,55 @@ this.ExtensionData = class {
       let messages = await this.readJSON(file);
       return this.localeData.addLocale(locale, messages, this);
     } catch (e) {
       this.packagingError(`Loading locale file ${file}: ${e}`);
       return new Map();
     }
   }
 
+  async _promiseLocaleMap() {
+    let locales = new Map();
+
+    let entries = await this.readDirectory("_locales");
+    for (let file of entries) {
+      if (file.isDir) {
+        let locale = this.normalizeLocaleCode(file.name);
+        locales.set(locale, file.name);
+      }
+    }
+
+    return locales;
+  }
+
+  _setupLocaleData(locales) {
+    if (this.localeData) {
+      return this.localeData.locales;
+    }
+
+    this.localeData = new LocaleData({
+      defaultLocale: this.defaultLocale,
+      locales,
+      builtinMessages: this.builtinMessages,
+    });
+
+    return locales;
+  }
+
   // Reads the list of locales available in the extension, and returns a
   // Promise which resolves to a Map upon completion.
   // Each map key is a Gecko-compatible locale code, and each value is the
   // "_locales" subdirectory containing that locale:
   //
   // Map(gecko-locale-code -> locale-directory-name)
   promiseLocales() {
     if (!this._promiseLocales) {
       this._promiseLocales = (async () => {
-        let locales = new Map();
-
-        let entries = await this.readDirectory("_locales");
-        for (let file of entries) {
-          if (file.isDir) {
-            let locale = this.normalizeLocaleCode(file.name);
-            locales.set(locale, file.name);
-          }
-        }
-
-        this.localeData = new LocaleData({
-          defaultLocale: this.defaultLocale,
-          locales,
-          builtinMessages: this.builtinMessages,
-        });
-
-        return locales;
+        let locales = this._promiseLocaleMap();
+        return this._setupLocaleData(locales);
       })();
     }
 
     return this._promiseLocales;
   }
 
   // Reads the locale messages for all locales, and returns a promise which
   // resolves to a Map of locale messages upon completion. Each key in the map
@@ -880,16 +894,23 @@ this.Extension = class extends Extension
   // Checks that the given URL is a child of our baseURI.
   isExtensionURL(url) {
     let uri = Services.io.newURI(url);
 
     let common = this.baseURI.getCommonBaseSpec(uri);
     return common == this.baseURI.spec;
   }
 
+  async promiseLocales(locale) {
+    let locales = await StartupCache.locales
+      .get([this.id, "@@all_locales"], () => this._promiseLocaleMap());
+
+    return this._setupLocaleData(locales);
+  }
+
   readLocaleFile(locale) {
     return StartupCache.locales.get([this.id, this.version, locale],
                                     () => super.readLocaleFile(locale))
       .then(result => {
         this.localeData.messages.set(locale, result);
       });
   }
 
@@ -1048,16 +1069,20 @@ this.Extension = class extends Extension
       Services.perms.removeFromPrincipal(principal, "WebExtensions-unlimitedStorage");
       Services.perms.removeFromPrincipal(principal, "indexedDB");
       Services.perms.removeFromPrincipal(principal, "persistent-storage");
     }
   }
 
   startup() {
     this.startupPromise = this._startup();
+
+    this._startupComplete = this.startupPromise.catch(() => {});
+    OS.File.shutdown.addBlocker("Extension startup", this._startupComplete);
+
     return this.startupPromise;
   }
 
   async _startup() {
     if (shutdownPromises.has(this.id)) {
       await shutdownPromises.get(this.id);
     }
 
@@ -1075,17 +1100,20 @@ this.Extension = class extends Extension
       // so during upgrades and add-on restarts, startup() gets called
       // before the last shutdown has completed, and this fails when
       // there's another active add-on with the same ID.
       this.policy.active = true;
     }
 
     TelemetryStopwatch.start("WEBEXT_EXTENSION_STARTUP_MS", this);
     try {
-      let [, perms] = await Promise.all([this.loadManifest(), ExtensionPermissions.get(this)]);
+      let [perms] = await Promise.all([
+        ExtensionPermissions.get(this),
+        this.loadManifest(),
+      ]);
 
       if (!this.hasShutdown) {
         await this.initLocale();
       }
 
       if (this.errors.length) {
         return Promise.reject({errors: this.errors});
       }
@@ -1127,17 +1155,17 @@ this.Extension = class extends Extension
       Management.emit("startup", this);
 
       await this.runManifest(this.manifest);
 
       Management.emit("ready", this);
       this.emit("ready");
       TelemetryStopwatch.finish("WEBEXT_EXTENSION_STARTUP_MS", this);
     } catch (e) {
-      dump(`Extension error: ${e.message} ${e.filename || e.fileName}:${e.lineNumber} :: ${e.stack || new Error().stack}\n`);
+      dump(`Extension error: ${e.message || e} ${e.filename || e.fileName}:${e.lineNumber} :: ${e.stack || new Error().stack}\n`);
       Cu.reportError(e);
 
       if (this.policy) {
         this.policy.active = false;
       }
 
       this.cleanupGeneratedFile();
 
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -17,34 +17,41 @@ this.EXPORTED_SYMBOLS = ["ExtensionParen
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "DeferredSave",
+                                  "resource://gre/modules/DeferredSave.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
                                   "resource:///modules/E10SUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+                                  "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "IndexedDB",
                                   "resource://gre/modules/IndexedDB.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
                                   "resource://gre/modules/MessageChannel.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
                                   "resource://gre/modules/NativeMessaging.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gAddonPolicyService",
                                    "@mozilla.org/addons/policy-service;1",
                                    "nsIAddonPolicyService");
+XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
+                                   "@mozilla.org/addons/addon-manager-startup;1",
+                                   "amIAddonManagerStartup");
 
 Cu.import("resource://gre/modules/ExtensionCommon.jsm");
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 
 var {
   BaseContext,
   CanOfAPIs,
   SchemaAPIManager,
@@ -53,16 +60,17 @@ var {
 
 var {
   DefaultWeakMap,
   ExtensionError,
   MessageManagerProxy,
   defineLazyGetter,
   promiseDocumentLoaded,
   promiseEvent,
+  promiseFileContents,
   promiseObserved,
 } = ExtensionUtils;
 
 const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
 const CATEGORY_EXTENSION_SCHEMAS = "webextension-schemas";
 const CATEGORY_EXTENSION_SCRIPTS = "webextension-scripts";
 
 const XUL_URL = "data:application/vnd.mozilla.xul+xml;charset=utf-8," + encodeURI(
@@ -1333,133 +1341,141 @@ let IconDetails = {
   escapeUrl(url) {
     return url.replace(/[\\\s"]/g, encodeURIComponent);
   },
 };
 
 let StartupCache = {
   DB_NAME: "ExtensionStartupCache",
 
-  SCHEMA_VERSION: 4,
+  STORE_NAMES: Object.freeze(["locales", "manifests", "permissions", "schemas"]),
+
+  get file() {
+    return FileUtils.getFile("ProfLD", ["startupCache", "webext.sc.lz4"]);
+  },
 
-  STORE_NAMES: Object.freeze(["locales", "manifests", "schemas"]),
+  get saver() {
+    if (!this._saver) {
+      this._saver = new DeferredSave(this.file.path,
+                                     () => this.getBlob(),
+                                     {delay: 5000});
+    }
+    return this._saver;
+  },
 
-  dbPromise: null,
+  async save() {
+    return this.saver.saveChanges();
+  },
+
+  getBlob() {
+    return new Uint8Array(aomStartup.encodeBlob(this._data));
+  },
 
-  initDB(db) {
-    for (let name of StartupCache.STORE_NAMES) {
-      try {
-        db.deleteObjectStore(name);
-      } catch (e) {
-        // Don't worry if the store doesn't already exist.
+  _data: null,
+  async _readData() {
+    let result = new Map();
+    try {
+      let data = await promiseFileContents(this.file);
+
+      result = aomStartup.decodeBlob(data);
+    } catch (e) {
+      if (!e.becauseNoSuchFile) {
+        Cu.reportError(e);
       }
-      db.createObjectStore(name, {keyPath: "key"});
     }
+
+    this._data = result;
+    return result;
+  },
+
+  get dataPromise() {
+    if (!this._dataPromise) {
+      this._dataPromise = this._readData();
+    }
+    return this._dataPromise;
   },
 
   clearAddonData(id) {
-    let range = IDBKeyRange.bound([id], [id, "\uFFFF"]);
-
     return Promise.all([
-      this.locales.delete(range),
-      this.manifests.delete(range),
+      this.locales.delete(id),
+      this.manifests.delete(id),
+      this.permissions.delete(id),
     ]).catch(e => {
       // Ignore the error. It happens when we try to flush the add-on
       // data after the AddonManager has flushed the entire startup cache.
-      this.dbPromise = this.reallyOpen(true).catch(e => {});
     });
   },
 
-  async reallyOpen(invalidate = false) {
-    if (this.dbPromise) {
-      let db = await this.dbPromise;
-      db.close();
-    }
-
-    if (invalidate) {
-      IndexedDB.deleteDatabase(this.DB_NAME, {storage: "persistent"});
-    }
-
-    return IndexedDB.open(this.DB_NAME,
-                          {storage: "persistent", version: this.SCHEMA_VERSION},
-                          db => this.initDB(db));
-  },
-
-  async open() {
-    if (!this.dbPromise) {
-      this.dbPromise = this.reallyOpen();
-    }
-
-    return this.dbPromise;
-  },
-
   observe(subject, topic, data) {
     if (topic === "startupcache-invalidate") {
-      this.dbPromise = this.reallyOpen(true).catch(e => {});
+      this._data = new Map();
+      this._dataPromise = Promise.resolve(this._data);
     }
   },
 };
 
+// void StartupCache.dataPromise;
+
 Services.obs.addObserver(StartupCache, "startupcache-invalidate");
 
 class CacheStore {
   constructor(storeName) {
     this.storeName = storeName;
   }
 
-  async get(key, createFunc) {
-    let db;
-    let result;
-    try {
-      db = await StartupCache.open();
+  async getStore(path = null) {
+    let data = await StartupCache.dataPromise;
+
+    let store = data.get(this.storeName);
+    if (!store) {
+      store = new Map();
+      data.set(this.storeName, store);
+    }
 
-      result = await db.objectStore(this.storeName)
-                      .get(key);
-    } catch (e) {
-      Cu.reportError(e);
+    let key = path;
+    if (Array.isArray(path)) {
+      for (let elem of path.slice(0, -1)) {
+        let next = store.get(elem);
+        if (!next) {
+          next = new Map();
+          store.set(elem, next);
+        }
+        store = next;
+      }
+      key = path[path.length - 1];
+    }
 
-      return createFunc(key);
-    }
+    return [store, key];
+  }
+
+  async get(path, createFunc) {
+    let [store, key] = await this.getStore(path);
+
+    let result = store.get(key);
 
     if (result === undefined) {
-      let value = await createFunc(key);
-      result = {key, value};
-
-      try {
-        db.objectStore(this.storeName, "readwrite")
-          .put(result);
-      } catch (e) {
-        Cu.reportError(e);
-      }
-    }
-
-    return result && result.value;
-  }
-
-  async getAll() {
-    let result = new Map();
-    try {
-      let db = await StartupCache.open();
-
-      let results = await db.objectStore(this.storeName)
-                            .getAll();
-      for (let {key, value} of results) {
-        result.set(key, value);
-      }
-    } catch (e) {
-      Cu.reportError(e);
+      result = await createFunc(path);
+      store.set(key, result);
+      StartupCache.save();
     }
 
     return result;
   }
 
-  async delete(key) {
-    let db = await StartupCache.open();
+  async getAll() {
+    let [store] = await this.getStore();
+
+    return new Map(store);
+  }
 
-    return db.objectStore(this.storeName, "readwrite").delete(key);
+  async delete(path) {
+    let [store, key] = await this.getStore(path);
+
+    store.delete(key);
+    StartupCache.save();
   }
 }
 
 for (let name of StartupCache.STORE_NAMES) {
   StartupCache[name] = new CacheStore(name);
 }
 
 var ExtensionParent = {
--- a/toolkit/components/extensions/ExtensionPermissions.jsm
+++ b/toolkit/components/extensions/ExtensionPermissions.jsm
@@ -1,58 +1,94 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
+                                  "resource://gre/modules/ExtensionParent.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
+                                  "resource://gre/modules/ExtensionUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+                                  "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
                                   "resource://gre/modules/JSONFile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 
+XPCOMUtils.defineLazyGetter(this, "StartupCache", () => ExtensionParent.StartupCache);
+
 this.EXPORTED_SYMBOLS = ["ExtensionPermissions"];
 
 const FILE_NAME = "extension-preferences.json";
 
 let prefs;
 let _initPromise;
+
+async function _lazyInit() {
+  let file = FileUtils.getFile("ProfD", [FILE_NAME]);
+
+  prefs = new JSONFile({path: file.path});
+  prefs.data = {};
+
+  try {
+    let blob = await ExtensionUtils.promiseFileContents(file);
+    prefs.data = JSON.parse(new TextDecoder().decode(blob));
+  } catch (e) {
+    if (!e.becauseNoSuchFile) {
+      Cu.reportError(e);
+    }
+  }
+}
+
 function lazyInit() {
   if (!_initPromise) {
-    prefs = new JSONFile({path: OS.Path.join(OS.Constants.Path.profileDir, FILE_NAME)});
-
-    _initPromise = prefs.load();
+    _initPromise = _lazyInit();
   }
   return _initPromise;
 }
 
 function emptyPermissions() {
   return {permissions: [], origins: []};
 }
 
 this.ExtensionPermissions = {
-  async get(extension) {
+  async _saveSoon(extension) {
+    await lazyInit();
+
+    prefs.data[extension.id] = await this._getCached(extension);
+    return prefs.saveSoon();
+  },
+
+  async _get(extension) {
     await lazyInit();
 
-    let perms = emptyPermissions();
-    if (prefs.data[extension.id]) {
-      Object.assign(perms, prefs.data[extension.id]);
+    let perms = prefs.data[extension.id];
+    if (!perms) {
+      perms = emptyPermissions();
+      prefs.data[extension.id] = perms;
     }
+
     return perms;
   },
 
+  async _getCached(extension) {
+    return StartupCache.permissions.get(extension.id,
+                                        () => this._get(extension));
+  },
+
+  get(extension) {
+    return this._getCached(extension);
+  },
+
   // Add new permissions for the given extension.  `permissions` is
   // in the format that is passed to browser.permissions.request().
   async add(extension, perms) {
-    await lazyInit();
-
-    if (!prefs.data[extension.id]) {
-      prefs.data[extension.id] = emptyPermissions();
-    }
-    let {permissions, origins} = prefs.data[extension.id];
+    let {permissions, origins} = await this._getCached(extension);
 
     let added = emptyPermissions();
 
     for (let perm of perms.permissions) {
       if (!permissions.includes(perm)) {
         added.permissions.push(perm);
         permissions.push(perm);
       }
@@ -62,30 +98,25 @@ this.ExtensionPermissions = {
       origin = new MatchPattern(origin, {ignorePath: true}).pattern;
       if (!origins.includes(origin)) {
         added.origins.push(origin);
         origins.push(origin);
       }
     }
 
     if (added.permissions.length > 0 || added.origins.length > 0) {
-      prefs.saveSoon();
+      this._saveSoon(extension);
       extension.emit("add-permissions", added);
     }
   },
 
   // Revoke permissions from the given extension.  `permissions` is
   // in the format that is passed to browser.permissions.remove().
   async remove(extension, perms) {
-    await lazyInit();
-
-    if (!prefs.data[extension.id]) {
-      return;
-    }
-    let {permissions, origins} = prefs.data[extension.id];
+    let {permissions, origins} = await this._getCached(extension);
 
     let removed = emptyPermissions();
 
     for (let perm of perms.permissions) {
       let i = permissions.indexOf(perm);
       if (i >= 0) {
         removed.permissions.push(perm);
         permissions.splice(i, 1);
@@ -98,25 +129,28 @@ this.ExtensionPermissions = {
       let i = origins.indexOf(origin);
       if (i >= 0) {
         removed.origins.push(origin);
         origins.splice(i, 1);
       }
     }
 
     if (removed.permissions.length > 0 || removed.origins.length > 0) {
-      prefs.saveSoon();
+      this._saveSoon(extension);
       extension.emit("remove-permissions", removed);
     }
   },
 
   async removeAll(extension) {
-    await lazyInit();
-    delete prefs.data[extension.id];
-    prefs.saveSoon();
+    let perms = await this._getCached(extension);
+
+    if (perms.permissions.length || perms.origins.length) {
+      Object.assign(perms, emptyPermissions());
+      prefs.saveSoon();
+    }
   },
 
   // This is meant for tests only
   async _uninit() {
     if (!_initPromise) {
       return;
     }
 
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -13,33 +13,42 @@ const Cr = Components.results;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
                                   "resource://gre/modules/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
                                   "resource://gre/modules/MessageChannel.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+                                  "resource://gre/modules/osfile.jsm");
 
 function getConsole() {
   return new ConsoleAPI({
     maxLogLevelPref: "extensions.webextensions.log.level",
     prefix: "WebExtensions",
   });
 }
 
 XPCOMUtils.defineLazyGetter(this, "console", getConsole);
 
+const appinfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
+
 let nextId = 0;
-XPCOMUtils.defineLazyGetter(this, "uniqueProcessID", () => Services.appinfo.uniqueProcessID);
+XPCOMUtils.defineLazyGetter(this, "uniqueProcessID", () => appinfo.uniqueProcessID);
 
 function getUniqueId() {
   return `${nextId++}-${uniqueProcessID}`;
 }
 
+async function promiseFileContents(file) {
+  let res = await OS.File.read(file.path);
+  return res.buffer;
+}
+
 
 /**
  * An Error subclass for which complete error messages are always passed
  * to extensions, rather than being interpreted as an unknown error.
  */
 class ExtensionError extends Error {}
 
 function filterStack(error) {
@@ -628,16 +637,17 @@ this.ExtensionUtils = {
   getUniqueId,
   filterStack,
   getWinUtils,
   instanceOf,
   normalizeTime,
   promiseDocumentLoaded,
   promiseDocumentReady,
   promiseEvent,
+  promiseFileContents,
   promiseObserved,
   runSafe,
   runSafeSync,
   runSafeSyncWithoutClone,
   runSafeWithoutClone,
   withHandlingUserInput,
   DefaultMap,
   DefaultWeakMap,
--- a/toolkit/mozapps/extensions/AddonManagerStartup.cpp
+++ b/toolkit/mozapps/extensions/AddonManagerStartup.cpp
@@ -2,29 +2,33 @@
 /* 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 "AddonManagerStartup.h"
 #include "AddonManagerStartup-inlines.h"
 
 #include "jsapi.h"
+#include "jsfriendapi.h"
 #include "js/TracingAPI.h"
 #include "xpcpublic.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Compression.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/Unused.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsAppRunner.h"
+#include "nsContentUtils.h"
 #include "nsIAddonInterposition.h"
 #include "nsXULAppAPI.h"
 
 #include <stdlib.h>
 
 namespace mozilla {
 
 template <>
@@ -57,16 +61,17 @@ WrapNSResult(nsresult aRv)
     }
     return Ok();
 }
 
 #define NS_TRY(expr) MOZ_TRY(WrapNSResult(expr))
 
 
 using Compression::LZ4;
+using dom::ipc::StructuredCloneData;
 
 #ifdef XP_WIN
 #  define READ_BINARYMODE "rb"
 #else
 #  define READ_BINARYMODE "r"
 #endif
 
 AddonManagerStartup&
@@ -146,54 +151,98 @@ ReadFile(const char* path)
   size_t rd = fread(result.BeginWriting(), sizeof(char), len, fd);
   if (rd != len) {
     result.Truncate();
   }
 
   return result;
 }
 
+static const char STRUCTURED_CLONE_MAGIC[] = "mozJSSCLz40v001";
+
+template <typename T>
+static Result<nsCString, nsresult>
+DecodeLZ4(const nsACString& lz4, const T& magicNumber)
+{
+  constexpr auto HEADER_SIZE = sizeof(magicNumber) + 4;
+
+  // Note: We want to include the null terminator here.
+  nsDependentCSubstring magic(magicNumber, sizeof(magicNumber));
+
+  if (lz4.Length() < HEADER_SIZE || StringHead(lz4, magic.Length()) != magic) {
+    return Err(NS_ERROR_UNEXPECTED);
+  }
+
+  auto data = lz4.BeginReading() + magic.Length();
+  auto size = LittleEndian::readUint32(data);
+  data += 4;
+
+  nsCString result;
+  if (!result.SetLength(size, fallible) ||
+      !LZ4::decompress(data, result.BeginWriting(), size)) {
+    return Err(NS_ERROR_UNEXPECTED);
+  }
+
+  return result;
+}
+
+// Our zlib headers redefine this to MOZ_Z_compress, which breaks LZ4::compress
+#undef compress
+
+template <typename T>
+static Result<nsCString, nsresult>
+EncodeLZ4(const nsACString& data, const T& magicNumber)
+{
+  // Note: We want to include the null terminator here.
+  nsDependentCSubstring magic(magicNumber, sizeof(magicNumber));
+
+  nsAutoCString result;
+  result.Append(magic);
+
+  auto off = result.Length();
+  result.SetLength(off + 4);
+
+  LittleEndian::writeUint32(result.BeginWriting() + off, data.Length());
+  off += 4;
+
+  auto size = LZ4::maxCompressedSize(data.Length());
+  result.SetLength(off + size);
+
+  size = LZ4::compress(data.BeginReading(), data.Length(),
+                       result.BeginWriting() + off);
+
+  result.SetLength(off + size);
+  return result;
+}
+
+static_assert(sizeof STRUCTURED_CLONE_MAGIC % 8 == 0,
+              "Magic number should be an array of uint64_t");
+
 /**
  * Reads the contents of a LZ4-compressed file, as stored by the OS.File
  * module, and returns the decompressed contents on success.
  *
  * A nonexistent or empty file is treated as success. A corrupt or non-LZ4
  * file is treated as failure.
  */
 static Result<nsCString, nsresult>
 ReadFileLZ4(const char* path)
 {
   static const char MAGIC_NUMBER[] = "mozLz40";
-  constexpr auto HEADER_SIZE = sizeof(MAGIC_NUMBER) + 4;
 
   nsCString result;
 
   nsCString lz4 = ReadFile(path);
   if (lz4.IsEmpty()) {
     return result;
   }
 
-  // Note: We want to include the null terminator here.
-  nsDependentCSubstring magic(MAGIC_NUMBER, sizeof(MAGIC_NUMBER));
-
-  if (lz4.Length() < HEADER_SIZE || StringHead(lz4, magic.Length()) != magic) {
-    return Err(NS_ERROR_UNEXPECTED);
-  }
-
-  auto size = LittleEndian::readUint32(lz4.get() + magic.Length());
-
-  if (!result.SetLength(size, fallible) ||
-      !LZ4::decompress(lz4.get() + HEADER_SIZE, result.BeginWriting(), size)) {
-    return Err(NS_ERROR_UNEXPECTED);
-  }
-
-  return result;
+  return DecodeLZ4(lz4, MAGIC_NUMBER);
 }
 
-
 static bool
 ParseJSON(JSContext* cx, nsACString& jsonData, JS::MutableHandleValue result)
 {
   NS_ConvertUTF8toUTF16 str(jsonData);
   jsonData.Truncate();
 
   return JS_ParseJSON(cx, str.Data(), str.Length(), result);
 }
@@ -583,16 +632,78 @@ AddonManagerStartup::InitializeExtension
       }
     }
   }
 
   return NS_OK;
 }
 
 nsresult
+AddonManagerStartup::EncodeBlob(JS::HandleValue value, JSContext* cx, JS::MutableHandleValue result)
+{
+  StructuredCloneData holder;
+
+  ErrorResult rv;
+  holder.Write(cx, value, rv);
+  if (rv.Failed()) {
+    return rv.StealNSResult();
+  }
+
+  nsAutoCString scData;
+
+  auto& data = holder.Data();
+  auto iter = data.Iter();
+  while (!iter.Done()) {
+    scData.Append(nsDependentCSubstring(iter.Data(), iter.RemainingInSegment()));
+    iter.Advance(data, iter.RemainingInSegment());
+  }
+
+  nsCString lz4;
+  MOZ_TRY_VAR(lz4, EncodeLZ4(scData, STRUCTURED_CLONE_MAGIC));
+
+  JS::RootedObject obj(cx);
+  NS_TRY(nsContentUtils::CreateArrayBuffer(cx, lz4, &obj.get()));
+
+  result.set(JS::ObjectValue(*obj));
+  return NS_OK;
+}
+
+nsresult
+AddonManagerStartup::DecodeBlob(JS::HandleValue value, JSContext* cx, JS::MutableHandleValue result)
+{
+  NS_ENSURE_TRUE(value.isObject() &&
+                 JS_IsArrayBufferObject(&value.toObject()) &&
+                 JS_ArrayBufferHasData(&value.toObject()),
+                 NS_ERROR_INVALID_ARG);
+
+  StructuredCloneData holder;
+
+  nsCString data;
+  {
+    JS::AutoCheckCannotGC nogc;
+
+    auto obj = &value.toObject();
+    bool isShared;
+
+    nsDependentCSubstring lz4(
+      reinterpret_cast<char*>(JS_GetArrayBufferData(obj, &isShared, nogc)),
+      JS_GetArrayBufferByteLength(obj));
+
+    MOZ_TRY_VAR(data, DecodeLZ4(lz4, STRUCTURED_CLONE_MAGIC));
+  }
+
+  bool ok = holder.CopyExternalData(data.get(), data.Length());
+  NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
+
+  ErrorResult rv;
+  holder.Read(cx, result, rv);
+  return rv.StealNSResult();;
+}
+
+nsresult
 AddonManagerStartup::Reset()
 {
   MOZ_RELEASE_ASSERT(xpc::IsInAutomation());
 
   mInitialized = false;
 
   mExtensionPaths.Clear();
   mThemePaths.Clear();
--- a/toolkit/mozapps/extensions/DeferredSave.jsm
+++ b/toolkit/mozapps/extensions/DeferredSave.jsm
@@ -38,16 +38,21 @@ parentLogger.addAppender(new Log.DumpApp
 // messages at runtime.
 // If the "extensions.logging.enabled" preference is
 // missing or 'false', messages at the WARNING and higher
 // severity should be logged to the JS console and standard error.
 // If "extensions.logging.enabled" is set to 'true', messages
 // at DEBUG and higher should go to JS console and standard error.
 Cu.import("resource://gre/modules/Services.jsm");
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
+                                  "resource://gre/modules/AsyncShutdown.jsm");
+
 const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 
 /**
 * Preference listener which listens for a change in the
 * "extensions.logging.enabled" preference and changes the logging level of the
 * parent 'addons' level logger accordingly.
 */
@@ -78,31 +83,40 @@ PrefObserver.init();
 /**
  * A module to manage deferred, asynchronous writing of data files
  * to disk. Writing is deferred by waiting for a specified delay after
  * a request to save the data, before beginning to write. If more than
  * one save request is received during the delay, all requests are
  * fulfilled by a single write.
  *
  * @constructor
- * @param aPath
+ * @param {string} aPath
  *        String representing the full path of the file where the data
  *        is to be written.
- * @param aDataProvider
+ * @param {function} aDataProvider
  *        Callback function that takes no argument and returns the data to
  *        be written. If aDataProvider returns an ArrayBufferView, the
  *        bytes it contains are written to the file as is.
  *        If aDataProvider returns a String the data are UTF-8 encoded
  *        and then written to the file.
- * @param [optional] aDelay
+ * @param {object | integer} [aOptions]
  *        The delay in milliseconds between the first saveChanges() call
  *        that marks the data as needing to be saved, and when the DeferredSave
  *        begins writing the data to disk. Default 50 milliseconds.
+ *
+ *        Or, an options object containing:
+ *         - delay: A delay in milliseconds.
+ *         - finalizeAt: An AsyncShutdown blocker during which to
+ *           finalize any pending writes.
  */
-this.DeferredSave = function(aPath, aDataProvider, aDelay) {
+this.DeferredSave = function(aPath, aDataProvider, aOptions = {}) {
+  if (typeof aOptions == "number") {
+    aOptions = {delay: aOptions};
+  }
+
   // Create a new logger (child of 'DeferredSave' logger)
   // for use by this particular instance of DeferredSave object
   let leafName = OS.Path.basename(aPath);
   let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName;
   this.logger = Log.repository.getLogger(logger_id);
 
   // @type {Deferred|null}, null when no data needs to be written
   // @resolves with the result of OS.File.writeAtomic when all writes complete
@@ -136,31 +150,40 @@ this.DeferredSave = function(aPath, aDat
 
   // The number of times the data became dirty while
   // another save was in progress
   this.overlappedSaves = 0;
 
   // Error returned by the most recent write (if any)
   this._lastError = null;
 
-  if (aDelay && (aDelay > 0))
-    this._delay = aDelay;
+  if (aOptions.delay && (aOptions.delay > 0))
+    this._delay = aOptions.delay;
   else
     this._delay = DEFAULT_SAVE_DELAY_MS;
+
+  this._finalizeAt = aOptions.finalizeAt || AsyncShutdown.profileBeforeChange;
+  this._finalize = this._finalize.bind(this);
+  this._finalizeAt.addBlocker(`DeferredSave: writing data to ${aPath}`,
+                              this._finalize);
 }
 
 this.DeferredSave.prototype = {
   get dirty() {
     return this._pending || this.writeInProgress;
   },
 
   get lastError() {
     return this._lastError;
   },
 
+  get path() {
+    return this._path;
+  },
+
   // Start the pending timer if data is dirty
   _startTimer() {
     if (!this._pending) {
       return;
     }
 
       this.logger.debug("Starting timer");
     if (!this._timer)
@@ -258,10 +281,15 @@ this.DeferredSave.prototype = {
       if (this._timer) {
         this._timer.cancel();
         this._timer = null;
       }
       this._deferredSave();
     }
 
     return this._writing;
-  }
+  },
+
+  _finalize() {
+    return this.flush().catch(Cu.reportError);
+  },
+
 };
--- a/toolkit/mozapps/extensions/amIAddonManagerStartup.idl
+++ b/toolkit/mozapps/extensions/amIAddonManagerStartup.idl
@@ -19,16 +19,22 @@ interface amIAddonManagerStartup : nsISu
 
   /**
    * Initializes the chrome registry for the enabled, non-restartless add-on
    * in the given state data.
    */
   [implicit_jscontext]
   void initializeExtensions(in jsval locations);
 
+  [implicit_jscontext]
+  jsval encodeBlob(in jsval value);
+
+  [implicit_jscontext]
+  jsval decodeBlob(in jsval value);
+
   /**
    * Resets the internal state of the startup service, and allows
    * initializeExtensions() to be called again. Does *not* fully unregister
    * chrome registry locations for previously registered add-ons.
    *
    * NOT FOR USE OUTSIDE OF UNIT TESTS.
    */
   void reset();
--- a/widget/cocoa/nsAppShell.mm
+++ b/widget/cocoa/nsAppShell.mm
@@ -320,17 +320,22 @@ nsAppShell::Init()
     // running in a Cocoa embedder. See bug 604901.
     if (!mRunningCocoaEmbedded) {
       nsToolkit::SwizzleMethods([NSApplication class], @selector(terminate:),
                                 @selector(nsAppShell_NSApplication_terminate:));
     }
     gAppShellMethodsSwizzled = true;
   }
 
-  if (nsCocoaFeatures::OnYosemiteOrLater()) {
+  // The bug that this works around was introduced in OS X 10.10.0
+  // and fixed in OS X 10.10.2. Order these version checks so as
+  // few as possible will actually end up running.
+  if (nsCocoaFeatures::OSXVersionMinor() == 10 &&
+      nsCocoaFeatures::OSXVersionBugFix() < 2 &&
+      nsCocoaFeatures::OSXVersionMajor() == 10) {
     // Explicitly turn off CGEvent logging.  This works around bug 1092855.
     // If there are already CGEvents in the log, turning off logging also
     // causes those events to be written to disk.  But at this point no
     // CGEvents have yet been processed.  CGEvents are events (usually
     // input events) pulled from the WindowServer.  An option of 0x80000008
     // turns on CGEvent logging.
     CGSSetDebugOptions(0x80000007);
   }
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -504,17 +504,17 @@ MozCrashWarningReporter(JSContext*, JSEr
 }
 
 CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSContext* aCx)
   : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal)
   , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal)
   , mJSRuntime(JS_GetRuntime(aCx))
   , mPrevGCSliceCallback(nullptr)
   , mPrevGCNurseryCollectionCallback(nullptr)
-  , mJSHolders(256)
+  , mJSHolderMap(256)
   , mOutOfMemoryState(OOMState::OK)
   , mLargeAllocationFailureState(OOMState::OK)
 {
   MOZ_COUNT_CTOR(CycleCollectedJSRuntime);
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(mJSRuntime);