merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 28 Sep 2016 15:56:33 +0200
changeset 315518 b1d60f2f68c7cccc96fcf9a2075bb430a500a0f2
parent 315414 1e7f590415adb88c3699ff073111027e1edf1592 (current diff)
parent 315517 51836860e20bbd0b146ea11810750d7f986cddcf (diff)
child 315528 3a5db9f20b43e149a61507707b559773e6a3debe
child 315598 9e14e5227101a0b6bbffa6ffca12b669cd6b1fbe
child 315643 2a3ee1d58982e0c6a2f9587d9eb95cfc758bc089
push id30750
push usercbook@mozilla.com
push dateWed, 28 Sep 2016 13:57:20 +0000
treeherdermozilla-central@b1d60f2f68c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/app/profile/firefox.js
dom/indexedDB/ActorsParent.cpp
dom/media/AudioStream.cpp
dom/media/eme/EMEUtils.cpp
dom/media/eme/EMEUtils.h
dom/media/eme/MediaKeySession.cpp
dom/media/eme/MediaKeys.cpp
dom/tests/mochitest/bugs/bug918719.sjs
dom/tests/mochitest/bugs/test_bug918719.html
modules/libpref/init/all.js
netwerk/base/security-prefs.js
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/test/unit/xpcshell.ini
old-configure.in
security/manager/ssl/SSLServerCertVerification.cpp
security/manager/ssl/nsSiteSecurityService.cpp
testing/web-platform/meta/IndexedDB/transaction-lifetime-empty.html.ini
toolkit/components/places/nsPlacesAutoComplete.js
toolkit/components/places/nsPlacesAutoComplete.manifest
toolkit/components/places/tests/autocomplete/.eslintrc
toolkit/components/places/tests/autocomplete/head_autocomplete.js
toolkit/components/places/tests/autocomplete/test_416211.js
toolkit/components/places/tests/autocomplete/test_416214.js
toolkit/components/places/tests/autocomplete/test_417798.js
toolkit/components/places/tests/autocomplete/test_418257.js
toolkit/components/places/tests/autocomplete/test_422277.js
toolkit/components/places/tests/autocomplete/test_autocomplete_on_value_removed_479089.js
toolkit/components/places/tests/autocomplete/test_download_embed_bookmarks.js
toolkit/components/places/tests/autocomplete/test_empty_search.js
toolkit/components/places/tests/autocomplete/test_enabled.js
toolkit/components/places/tests/autocomplete/test_escape_self.js
toolkit/components/places/tests/autocomplete/test_ignore_protocol.js
toolkit/components/places/tests/autocomplete/test_keyword_search.js
toolkit/components/places/tests/autocomplete/test_match_beginning.js
toolkit/components/places/tests/autocomplete/test_multi_word_search.js
toolkit/components/places/tests/autocomplete/test_special_search.js
toolkit/components/places/tests/autocomplete/test_swap_protocol.js
toolkit/components/places/tests/autocomplete/test_tabmatches.js
toolkit/components/places/tests/autocomplete/test_word_boundary_search.js
toolkit/components/places/tests/autocomplete/xpcshell.ini
toolkit/components/telemetry/Histograms.json
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1451,17 +1451,17 @@ pref("dom.ipc.cpow.timeout", 500);
 
 // Causes access on unsafe CPOWs from browser code to throw by default.
 pref("dom.ipc.cpows.forbid-unsafe-from-browser", true);
 
 // Don't allow add-ons marked as multiprocessCompatible to use CPOWs.
 pref("dom.ipc.cpows.forbid-cpows-in-compat-addons", true);
 
 // ...except for these add-ons:
-pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,firegestures@xuldev.org,treestyletab@piro.sakura.ne.jp,{DDC359D1-844A-42a7-9AA1-88A850A938A8},ich@maltegoetz.de,{AE93811A-5C9A-4d34-8462-F7B864FC4696}");
+pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},firegestures@xuldev.org,{DDC359D1-844A-42a7-9AA1-88A850A938A8},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,treestyletab@piro.sakura.ne.jp,cliqz@cliqz.com,{AE93811A-5C9A-4d34-8462-F7B864FC4696},contextsearch2@lwz.addons.mozilla.org,{EF522540-89F5-46b9-B6FE-1829E2B572C6},{677a8f98-fd64-40b0-a883-b8c95d0cbf17},images@wink.su,fx-devtools,toolkit/require,url_advisor@kaspersky.com,{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d},{dc572301-7619-498c-a57d-39143191b318},dta@downthemall.net,{86095750-AD15-46d8-BF32-C0789F7E6A32},screenwise-prod@google.com,{91aa5abe-9de4-4347-b7b5-322c38dd9271},secureLogin@blueimp.net,ich@maltegoetz.de,come.back.block.image.from@cat-in-136.blogspot.com,{7b1bf0b6-a1b9-42b0-b75d-252036438bdc},s3crypto@data,{1e0fd655-5aea-4b4c-a583-f76ef1e3af9c},akahuku.fx.sp@toshiakisp.github.io,{aff87fa2-a58e-4edd-b852-0a20203c1e17},{1018e4d6-728f-4b20-ad56-37578a4de76b},rehostimage@engy.us,lazarus@interclue.com,{b2e69492-2358-071a-7056-24ad0c3defb1},flashstopper@byo.co.il,{e4a8a97b-f2ed-450b-b12d-ee082ba24781},jid1-f3mYMbCpz2AZYl@jetpack,{8c550e28-88c9-4764-bb52-aa489cf2efcd},{37fa1426-b82d-11db-8314-0800200c9a66},{ac2cfa60-bc96-11e0-962b-0800200c9a66},igetter@presenta.net,killspinners@byo.co.il,abhere2@moztw.org,{fc6339b8-9581-4fc7-b824-dffcb091fcb7},wampi@wink.su,backtrack@byalexv.co.uk,Gladiator_X@mail.ru,{73a6fe31-595d-460b-a920-fcc0f8843232},{46551EC9-40F0-4e47-8E18-8E5CF550CFB8},acewebextension_unlisted@acestream.org,@screen_maker,yasearch@yandex.ru,sp@avast.com,s3google@translator,igetterextension@presenta.net,{C1A2A613-35F1-4FCF-B27F-2840527B6556},screenwise-testing@google.com,helper-sig@savefrom.net,browser-loader,ImageSaver@Merci.chao,proxtube@abz.agency,wrc@avast.com,{9AA46F4F-4DC7-4c06-97AF-5035170634FE},jid1-CikLKKPVkw6ipw@jetpack,artur.dubovoy@gmail.com,nlgfeb@nlgfeb.ext,{A065A84F-95B6-433A-A0C8-4C040B77CE8A},fdm_ffext@freedownloadmanager.org");
 
 // Enable e10s hang monitoring (slow script checking and plugin hang
 // detection).
 pref("dom.ipc.processHangMonitor", true);
 
 #ifdef DEBUG
 // Don't report hangs in DEBUG builds. They're too slow and often a
 // debugger is attached.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1123,31 +1123,35 @@ var gBrowserInit = {
           Cu.reportError(e);
         }
       }
       // window.arguments[2]: referrer (nsIURI | string)
       //                 [3]: postData (nsIInputStream)
       //                 [4]: allowThirdPartyFixup (bool)
       //                 [5]: referrerPolicy (int)
       //                 [6]: userContextId (int)
+      //                 [7]: originPrincipal (nsIPrincipal)
       else if (window.arguments.length >= 3) {
         let referrerURI = window.arguments[2];
         if (typeof(referrerURI) == "string") {
           try {
             referrerURI = makeURI(referrerURI);
           } catch (e) {
             referrerURI = null;
           }
         }
         let referrerPolicy = (window.arguments[5] != undefined ?
             window.arguments[5] : Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT);
         let userContextId = (window.arguments[6] != undefined ?
             window.arguments[6] : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID);
         loadURI(uriToLoad, referrerURI, window.arguments[3] || null,
-                window.arguments[4] || false, referrerPolicy, userContextId);
+                window.arguments[4] || false, referrerPolicy, userContextId,
+                // pass the origin principal (if any) and force its use to create
+                // an initial about:blank viewer if present:
+                window.arguments[7], !!window.arguments[7]);
         window.focus();
       }
       // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
       // Such callers expect that window.arguments[0] is handled as a single URI.
       else {
         loadOneOrMoreURIs(uriToLoad);
       }
     }
@@ -2028,24 +2032,27 @@ function BrowserCloseTabOrWindow() {
 
 function BrowserTryToCloseWindow()
 {
   if (WindowIsClosing())
     window.close();     // WindowIsClosing does all the necessary checks
 }
 
 function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy,
-                 userContextId) {
+                 userContextId, originPrincipal, forceAboutBlankViewerInCurrent) {
   try {
     openLinkIn(uri, "current",
                { referrerURI: referrer,
                  referrerPolicy: referrerPolicy,
                  postData: postData,
                  allowThirdPartyFixup: allowThirdPartyFixup,
-                 userContextId: userContextId });
+                 userContextId: userContextId,
+                 originPrincipal,
+                 forceAboutBlankViewerInCurrent,
+               });
   } catch (e) {}
 }
 
 /**
  * Given a urlbar value, discerns between URIs, keywords and aliases.
  *
  * @param url
  *        The urlbar value.
@@ -5579,21 +5586,24 @@ function handleLinkClick(event, href, li
     let referrerAttrValue = Services.netUtils.parseAttributePolicyString(linkNode.
                             getAttribute("referrerpolicy"));
     if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_UNSET) {
       referrerPolicy = referrerAttrValue;
     }
   }
 
   urlSecurityCheck(href, doc.nodePrincipal);
-  let params = { charset: doc.characterSet,
-                 allowMixedContent: persistAllowMixedContentInChildTab,
-                 referrerURI: referrerURI,
-                 referrerPolicy: referrerPolicy,
-                 noReferrer: BrowserUtils.linkHasNoReferrer(linkNode) };
+  let params = {
+    charset: doc.characterSet,
+    allowMixedContent: persistAllowMixedContentInChildTab,
+    referrerURI: referrerURI,
+    referrerPolicy: referrerPolicy,
+    noReferrer: BrowserUtils.linkHasNoReferrer(linkNode),
+    originPrincipal: doc.nodePrincipal,
+  };
 
   // The new tab/window must use the same userContextId
   if (doc.nodePrincipal.originAttributes.userContextId) {
     params.userContextId = doc.nodePrincipal.originAttributes.userContextId;
   }
 
   openLinkIn(href, where, params);
   event.preventDefault();
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -502,16 +502,17 @@ var ClickEventHandler = {
       if (docShell.mixedContentChannel) {
         const sm = Services.scriptSecurityManager;
         try {
           let targetURI = BrowserUtils.makeURI(href);
           sm.checkSameOriginURI(docshell.mixedContentChannel.URI, targetURI, false);
           json.allowMixedContent = true;
         } catch (e) {}
       }
+      json.originPrincipal = ownerDoc.nodePrincipal;
 
       sendAsyncMessage("Content:Click", json);
       return;
     }
 
     // This might be middle mouse navigation.
     if (event.button == 1) {
       sendAsyncMessage("Content:Click", json);
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -960,16 +960,17 @@ nsContextMenu.prototype = {
 
   _isProprietaryDRM: function() {
     return this.target.isEncrypted && this.target.mediaKeys &&
            this.target.mediaKeys.keySystem != "org.w3.clearkey";
   },
 
   _openLinkInParameters : function (extra) {
     let params = { charset: gContextMenuContentData.charSet,
+                   originPrincipal: this.principal,
                    referrerURI: gContextMenuContentData.documentURIObject,
                    referrerPolicy: gContextMenuContentData.referrerPolicy,
                    noReferrer: this.linkHasNoReferrer };
     for (let p in extra) {
       params[p] = extra[p];
     }
 
     // If we want to change userContextId, we must be sure that we don't
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1495,16 +1495,17 @@
             var aFromExternal;
             var aRelatedToCurrent;
             var aAllowMixedContent;
             var aSkipAnimation;
             var aForceNotRemote;
             var aNoReferrer;
             var aUserContextId;
             var aRelatedBrowser;
+            var aOriginPrincipal;
             if (arguments.length == 2 &&
                 typeof arguments[1] == "object" &&
                 !(arguments[1] instanceof Ci.nsIURI)) {
               let params = arguments[1];
               aReferrerURI          = params.referrerURI;
               aReferrerPolicy       = params.referrerPolicy;
               aCharset              = params.charset;
               aPostData             = params.postData;
@@ -1513,16 +1514,17 @@
               aFromExternal         = params.fromExternal;
               aRelatedToCurrent     = params.relatedToCurrent;
               aAllowMixedContent    = params.allowMixedContent;
               aSkipAnimation        = params.skipAnimation;
               aForceNotRemote       = params.forceNotRemote;
               aNoReferrer           = params.noReferrer;
               aUserContextId        = params.userContextId;
               aRelatedBrowser       = params.relatedBrowser;
+              aOriginPrincipal      = params.originPrincipal;
             }
 
             var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
                          Services.prefs.getBoolPref("browser.tabs.loadInBackground");
             var owner = bgLoad ? null : this.selectedTab;
             var tab = this.addTab(aURI, {
                                   referrerURI: aReferrerURI,
                                   referrerPolicy: aReferrerPolicy,
@@ -1532,16 +1534,17 @@
                                   allowThirdPartyFixup: aAllowThirdPartyFixup,
                                   fromExternal: aFromExternal,
                                   relatedToCurrent: aRelatedToCurrent,
                                   skipAnimation: aSkipAnimation,
                                   allowMixedContent: aAllowMixedContent,
                                   forceNotRemote: aForceNotRemote,
                                   noReferrer: aNoReferrer,
                                   userContextId: aUserContextId,
+                                  originPrincipal: aOriginPrincipal,
                                   relatedBrowser: aRelatedBrowser });
             if (!bgLoad)
               this.selectedTab = tab;
 
             return tab;
          ]]>
         </body>
       </method>
@@ -2038,16 +2041,17 @@
             var aRelatedToCurrent;
             var aSkipAnimation;
             var aAllowMixedContent;
             var aForceNotRemote;
             var aNoReferrer;
             var aUserContextId;
             var aEventDetail;
             var aRelatedBrowser;
+            var aOriginPrincipal;
             if (arguments.length == 2 &&
                 typeof arguments[1] == "object" &&
                 !(arguments[1] instanceof Ci.nsIURI)) {
               let params = arguments[1];
               aReferrerURI          = params.referrerURI;
               aReferrerPolicy       = params.referrerPolicy;
               aCharset              = params.charset;
               aPostData             = params.postData;
@@ -2057,16 +2061,17 @@
               aRelatedToCurrent     = params.relatedToCurrent;
               aSkipAnimation        = params.skipAnimation;
               aAllowMixedContent    = params.allowMixedContent;
               aForceNotRemote       = params.forceNotRemote;
               aNoReferrer           = params.noReferrer;
               aUserContextId        = params.userContextId;
               aEventDetail          = params.eventDetail;
               aRelatedBrowser       = params.relatedBrowser;
+              aOriginPrincipal      = params.originPrincipal;
             }
 
             // if we're adding tabs, we're past interrupt mode, ditch the owner
             if (this.mCurrentTab.owner)
               this.mCurrentTab.owner = null;
 
             var t = document.createElementNS(NS_XUL, "tab");
 
@@ -2136,16 +2141,20 @@
 
             // Dispatch a new tab notification.  We do this once we're
             // entirely done, so that things are in a consistent state
             // even if the event listener opens or closes tabs.
             var detail = aEventDetail || {};
             var evt = new CustomEvent("TabOpen", { bubbles: true, detail });
             t.dispatchEvent(evt);
 
+            if (!usingPreloadedContent && aOriginPrincipal) {
+              b.createAboutBlankContentViewer(aOriginPrincipal);
+            }
+
             // If we didn't swap docShells with a preloaded browser
             // then let's just continue loading the page normally.
             if (!usingPreloadedContent && !uriIsAboutBlank) {
               // pretend the user typed this so it'll be available till
               // the document successfully loads
               if (aURI && gInitialPages.indexOf(aURI) == -1)
                 b.userTypedValue = aURI;
 
@@ -3664,17 +3673,21 @@
               }
 
               this.lastVisibleTab = this.visibleTab;
             },
 
             assert: function(cond) {
               if (!cond) {
                 dump("Assertion failure\n" + Error().stack);
-                throw new Error("Assertion failure");
+
+                // Don't break a user's browser if an assertion fails.
+                if (this.tabbrowser.AppConstants.DEBUG) {
+                  throw new Error("Assertion failure");
+                }
               }
             },
 
             // We've decided to try to load requestedTab.
             loadRequestedTab: function() {
               this.assert(!this.loadTimer);
               this.assert(!this.minimized);
 
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -113,16 +113,17 @@ support-files =
   test_mcb_redirect_image.html
   test_mcb_double_redirect_image.html
   test_mcb_redirect.js
   test_mcb_redirect.sjs
   file_bug1045809_1.html
   file_bug1045809_2.html
   file_csp_block_all_mixedcontent.html
   file_csp_block_all_mixedcontent.js
+  !/image/test/mochitest/blue.png
   !/toolkit/components/passwordmgr/test/browser/form_basic.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
   !/toolkit/content/tests/browser/common/mockTransfer.js
   !/toolkit/modules/tests/browser/metadata_*.html
   !/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi
@@ -337,16 +338,17 @@ skip-if = toolkit == "windows" # Disable
 skip-if = os != "win" # The Fitts Law menu button is only supported on Windows (bug 969376)
 [browser_middleMouse_noJSPaste.js]
 subsuite = clipboard
 [browser_minimize.js]
 [browser_misused_characters_in_strings.js]
 [browser_mixed_content_cert_override.js]
 [browser_mixedcontent_securityflags.js]
 tags = mcb
+[browser_modifiedclick_inherit_principal.js]
 [browser_offlineQuotaNotification.js]
 skip-if = buildapp == 'mulet'
 [browser_feed_discovery.js]
 support-files = feed_discovery.html
 [browser_gZipOfflineChild.js]
 skip-if = buildapp == 'mulet' # Bug 1066070 - I don't think either popup notifications nor addon install stuff works?
 support-files = test_offline_gzip.html gZipOfflineChild.cacheManifest gZipOfflineChild.cacheManifest^headers^ gZipOfflineChild.html gZipOfflineChild.html^headers^
 [browser_overflowScroll.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_modifiedclick_inherit_principal.js
@@ -0,0 +1,30 @@
+"use strict";
+
+const kURL =
+  "http://example.com/browser/browser/base/content/test/general/dummy_page.html";
+  "data:text/html,<a href=''>Middle-click me</a>";
+
+/*
+ * Check that when manually opening content JS links in new tabs/windows,
+ * we use the correct principal, and we don't clear the URL bar.
+ */
+add_task(function* () {
+ yield BrowserTestUtils.withNewTab(kURL, function* (browser) {
+   let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+   yield ContentTask.spawn(browser, null, function* () {
+     let a = content.document.createElement("a");
+     a.href = "javascript:document.write('spoof'); void(0);";
+     a.textContent = "Some link";
+     content.document.body.appendChild(a);
+   });
+   info("Added element");
+   yield BrowserTestUtils.synthesizeMouseAtCenter("a", {button: 1}, browser);
+   let newTab = yield newTabPromise;
+   is(newTab.linkedBrowser.contentPrincipal.origin, "http://example.com",
+      "Principal should be for example.com");
+   yield BrowserTestUtils.switchTab(gBrowser, newTab);
+   info(gURLBar.value);
+   isnot(gURLBar.value, "", "URL bar should not be empty.");
+   yield BrowserTestUtils.removeTab(newTab);
+ });
+});
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -217,16 +217,19 @@ function openLinkIn(url, where, params) 
   var aInitiatingDoc        = params.initiatingDoc;
   var aIsPrivate            = params.private;
   var aSkipTabAnimation     = params.skipTabAnimation;
   var aAllowPinnedTabHostChange = !!params.allowPinnedTabHostChange;
   var aNoReferrer           = params.noReferrer;
   var aAllowPopups          = !!params.allowPopups;
   var aUserContextId        = params.userContextId;
   var aIndicateErrorPageLoad = params.indicateErrorPageLoad;
+  var aPrincipal            = params.originPrincipal;
+  var aForceAboutBlankViewerInCurrent =
+      params.forceAboutBlankViewerInCurrent;
 
   if (where == "save") {
     // TODO(1073187): propagate referrerPolicy.
 
     // ContentClick.jsm passes isContentWindowPrivate for saveURL instead of passing a CPOW initiatingDoc
     if ("isContentWindowPrivate" in params) {
       saveURL(url, null, null, true, true, aNoReferrer ? null : aReferrerURI, null, params.isContentWindowPrivate);
     }
@@ -285,16 +288,17 @@ function openLinkIn(url, where, params) 
 
     sa.AppendElement(wuri);
     sa.AppendElement(charset);
     sa.AppendElement(referrerURISupports);
     sa.AppendElement(aPostData);
     sa.AppendElement(allowThirdPartyFixupSupports);
     sa.AppendElement(referrerPolicySupports);
     sa.AppendElement(userContextIdSupports);
+    sa.AppendElement(aPrincipal);
 
     let features = "chrome,dialog=no,all";
     if (aIsPrivate) {
       features += ",private";
     }
 
     Services.ww.openWindow(w || window, getBrowserURL(), null, features, sa);
     return;
@@ -352,16 +356,20 @@ function openLinkIn(url, where, params) 
 
     if (aAllowPopups) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_POPUPS;
     }
     if (aIndicateErrorPageLoad) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ERROR_LOAD_CHANGES_RV;
     }
 
+    if (aForceAboutBlankViewerInCurrent) {
+      w.gBrowser.selectedBrowser.createAboutBlankContentViewer(aPrincipal);
+    }
+
     w.gBrowser.loadURIWithFlags(url, {
       flags: flags,
       referrerURI: aNoReferrer ? null : aReferrerURI,
       referrerPolicy: aReferrerPolicy,
       postData: aPostData,
       userContextId: aUserContextId
     });
     break;
@@ -375,17 +383,18 @@ function openLinkIn(url, where, params) 
       charset: aCharset,
       postData: aPostData,
       inBackground: loadInBackground,
       allowThirdPartyFixup: aAllowThirdPartyFixup,
       relatedToCurrent: aRelatedToCurrent,
       skipAnimation: aSkipTabAnimation,
       allowMixedContent: aAllowMixedContent,
       noReferrer: aNoReferrer,
-      userContextId: aUserContextId
+      userContextId: aUserContextId,
+      originPrincipal: aPrincipal,
     });
     break;
   }
 
   w.gBrowser.selectedBrowser.focus();
 
   if (!loadInBackground && w.isBlankPageURL(url)) {
     w.focusAndSelectUrlBar();
--- a/browser/modules/ContentClick.jsm
+++ b/browser/modules/ContentClick.jsm
@@ -72,22 +72,25 @@ var ContentClick = {
 
     // This part is based on handleLinkClick.
     var where = window.whereToOpenLink(json);
     if (where == "current")
       return;
 
     // Todo(903022): code for where == save
 
-    let params = { charset: browser.characterSet,
-                   referrerURI: browser.documentURI,
-                   referrerPolicy: json.referrerPolicy,
-                   noReferrer: json.noReferrer,
-                   allowMixedContent: json.allowMixedContent,
-                   isContentWindowPrivate: json.isContentWindowPrivate};
+    let params = {
+      charset: browser.characterSet,
+      referrerURI: browser.documentURI,
+      referrerPolicy: json.referrerPolicy,
+      noReferrer: json.noReferrer,
+      allowMixedContent: json.allowMixedContent,
+      isContentWindowPrivate: json.isContentWindowPrivate,
+      originPrincipal: json.originPrincipal,
+    };
 
     // The new tab/window must use the same userContextId.
     if (json.originAttributes.userContextId) {
       params.userContextId = json.originAttributes.userContextId;
     }
 
     window.openLinkIn(json.href, where, params);
   }
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -186,32 +186,21 @@ toolbar[brighttext] #downloads-indicator
 #navigator-toolbox .searchbar-textbox {
   background-color: var(--url-and-searchbar-background-color) !important;
   background-image: none !important;
   color: inherit !important;
   border: 1px solid var(--chrome-nav-bar-controls-border-color) !important;
   box-shadow: none !important;
 }
 
-:root[devtoolstheme="dark"] #identity-icon:-moz-lwtheme {
-  --identity-icon-normal: url(chrome://browser/skin/identity-icon.svg#normal-white);
-  --identity-icon-hover: url(chrome://browser/skin/identity-icon.svg#hover-white);
-  --identity-icon-notice: url(chrome://browser/skin/identity-icon.svg#notice-white);
-  --identity-icon-notice-hover: url(chrome://browser/skin/identity-icon.svg#notice-hover-white);
-}
-
-:root[devtoolstheme="dark"] #tracking-protection-icon:-moz-lwtheme {
-  --tracking-protection-icon-enabled: url(chrome://browser/skin/tracking-protection-16.svg#enabled-white);
-  --tracking-protection-icon-disabled: url(chrome://browser/skin/tracking-protection-16.svg#disabled-white);
-}
-
-:root[devtoolstheme="dark"] #connection-icon:-moz-lwtheme {
-  --connection-icon-mixed-passive-loaded: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon-white);
-  --connection-icon-mixed-active-loaded: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon-white);
-}
+%filter substitution
+%define selectorPrefix :root[devtoolstheme="dark"] 
+%define selectorSuffix :-moz-lwtheme
+%define iconVariant -white
+%include identity-block/icons.inc.css
 
 #urlbar {
   border-inline-start: none !important;
   opacity: 1 !important;
 }
 
 window:not([chromehidden~="toolbar"]) #urlbar-wrapper {
   overflow: -moz-hidden-unscrollable;
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/identity-block/icons.inc.css
@@ -0,0 +1,62 @@
+%if 0
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+%endif
+
+@selectorPrefix@#identity-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/identity-icon.svg#normal@iconVariant@);
+}
+
+@selectorPrefix@#identity-box:hover > #identity-icon:not(.no-hover)@selectorSuffix@,
+@selectorPrefix@#identity-box[open=true] > #identity-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/identity-icon.svg#hover@iconVariant@);
+}
+
+@selectorPrefix@#identity-box.grantedPermissions > #identity-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/identity-icon.svg#notice@iconVariant@);
+}
+
+@selectorPrefix@#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover)@selectorSuffix@,
+@selectorPrefix@#identity-box.grantedPermissions[open=true] > #identity-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/identity-icon.svg#notice-hover@iconVariant@);
+}
+
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon@selectorSuffix@ {
+  list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
+}
+
+
+@selectorPrefix@#tracking-protection-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/tracking-protection-16.svg#enabled@iconVariant@);
+}
+
+@selectorPrefix@#tracking-protection-icon[state="loaded-tracking-content"]@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/tracking-protection-16.svg#disabled@iconVariant@);
+}
+
+
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon@selectorSuffix@,
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon@selectorSuffix@,
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/connection-secure.svg);
+  visibility: visible;
+}
+
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@);
+  visibility: visible;
+}
+
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon@selectorSuffix@,
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon@iconVariant@);
+  visibility: visible;
+}
+
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon@selectorSuffix@,
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon@selectorSuffix@,
+@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon@selectorSuffix@ {
+  list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@);
+  visibility: visible;
+}
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -1,14 +1,26 @@
 %if 0
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 
+%filter substitution
+
+%define selectorPrefix
+%define selectorSuffix
+%define iconVariant
+%include icons.inc.css
+
+%define selectorPrefix
+%define selectorSuffix :-moz-lwtheme
+%define iconVariant -black
+%include icons.inc.css
+
 #identity-box {
   font-size: .9em;
   padding: 3px 5px;
   overflow: hidden;
   /* The padding-left and padding-right transitions handle the delayed hiding of
      the forward button when hovered. */
   transition: padding-left, padding-right;
 }
@@ -47,49 +59,18 @@
 @conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #identity-box {
   /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
   padding-inline-start: calc(var(--backbutton-urlbar-overlap) + 5.01px);
 }
 
 /* MAIN IDENTITY ICON */
 
 #identity-icon {
-  --identity-icon-normal: url(chrome://browser/skin/identity-icon.svg#normal);
-  --identity-icon-hover: url(chrome://browser/skin/identity-icon.svg#hover);
-  --identity-icon-notice: url(chrome://browser/skin/identity-icon.svg#notice);
-  --identity-icon-notice-hover: url(chrome://browser/skin/identity-icon.svg#notice-hover);
-
   width: 16px;
   height: 16px;
-  list-style-image: var(--identity-icon-normal);
-}
-
-#identity-icon:-moz-lwtheme {
-  --identity-icon-normal: url(chrome://browser/skin/identity-icon.svg#normal-black);
-  --identity-icon-hover: url(chrome://browser/skin/identity-icon.svg#hover-black);
-  --identity-icon-notice: url(chrome://browser/skin/identity-icon.svg#notice-black);
-  --identity-icon-notice-hover: url(chrome://browser/skin/identity-icon.svg#notice-hover-black);
-}
-
-#identity-box:hover > #identity-icon:not(.no-hover),
-#identity-box[open=true] > #identity-icon {
-  list-style-image: var(--identity-icon-hover);
-}
-
-#identity-box.grantedPermissions > #identity-icon {
-  list-style-image: var(--identity-icon-notice);
-}
-
-#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover),
-#identity-box.grantedPermissions[open=true] > #identity-icon {
-  list-style-image: var(--identity-icon-notice-hover);
-}
-
-#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon {
-  list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
 }
 
 #urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon {
   opacity: .3;
 }
 
 #urlbar[actiontype="searchengine"] > #identity-box > #identity-icon {
   -moz-image-region: inherit;
@@ -137,33 +118,20 @@
   33.33%, 66.66% {
     opacity: 1;
   }
 }
 
 /* TRACKING PROTECTION ICON */
 
 #tracking-protection-icon {
-  --tracking-protection-icon-enabled: url(chrome://browser/skin/tracking-protection-16.svg#enabled);
-  --tracking-protection-icon-disabled: url(chrome://browser/skin/tracking-protection-16.svg#disabled);
-
   width: 16px;
   height: 16px;
   margin-inline-start: 2px;
   margin-inline-end: 0;
-  list-style-image: var(--tracking-protection-icon-enabled);
-}
-
-#tracking-protection-icon:-moz-lwtheme {
-  --tracking-protection-icon-enabled: url(chrome://browser/skin/tracking-protection-16.svg#enabled-black);
-  --tracking-protection-icon-disabled: url(chrome://browser/skin/tracking-protection-16.svg#disabled-black);
-}
-
-#tracking-protection-icon[state="loaded-tracking-content"] {
-  list-style-image: var(--tracking-protection-icon-disabled);
 }
 
 #tracking-protection-icon[animate] {
   transition: margin-left 200ms ease-out, margin-right 200ms ease-out;
 }
 
 #tracking-protection-icon:not([state]) {
   margin-inline-end: -18px;
@@ -179,42 +147,10 @@
 
 /* CONNECTION ICON */
 
 #connection-icon {
   width: 16px;
   height: 16px;
   margin-inline-start: 2px;
   visibility: collapse;
-
-  --connection-icon-mixed-passive-loaded: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon);
-  --connection-icon-mixed-active-loaded: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon);
-}
-
-#connection-icon:-moz-lwtheme {
-  --connection-icon-mixed-passive-loaded: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon-black);
-  --connection-icon-mixed-active-loaded: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon-black);
-}
-
-#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon,
-#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon,
-#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon {
-  list-style-image: url(chrome://browser/skin/connection-secure.svg);
-  visibility: visible;
 }
 
-#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon {
-  list-style-image: var(--connection-icon-mixed-passive-loaded);
-  visibility: visible;
-}
-
-#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon,
-#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon {
-  list-style-image: var(--connection-icon-mixed-active-loaded);
-  visibility: visible;
-}
-
-#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon,
-#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon,
-#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon {
-  list-style-image: var(--connection-icon-mixed-passive-loaded);
-  visibility: visible;
-}
--- a/caps/tests/mochitest/test_bug995943.xul
+++ b/caps/tests/mochitest/test_bug995943.xul
@@ -22,17 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   const Ci = Components.interfaces;
   Cu.import("resource://gre/modules/Services.jsm");
   function debug(msg) { info(msg); }
 
   /** Test for CAPS file:// URI prefs. **/
   SimpleTest.waitForExplicitFinish();
   SimpleTest.requestCompleteLog();
   if (navigator.userAgent.indexOf("Mac OS X 10.10") != -1)
-    SimpleTest.expectAssertions(6, 9); // See bug 1067022
+    SimpleTest.expectAssertions(5, 9); // See bug 1067022
   else if (Services.appinfo.OS == "WINNT")
     SimpleTest.expectAssertions(0, 1); // See bug 1067022
 
   var rootdir = Services.appinfo.OS == "WINNT" ? "file:///C:" : "file:///";
 
   function checkLoadFileURI(domain, shouldLoad) {
     debug("Invoking checkLoadFileURI with domain: " + domain + ", shouldLoad: " + shouldLoad);
     return new Promise(function(resolve, reject) {
new file mode 100644
--- /dev/null
+++ b/config/check_js_msg_encoding.py
@@ -0,0 +1,63 @@
+# vim: set ts=8 sts=4 et sw=4 tw=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/.
+
+#----------------------------------------------------------------------------
+# This script checks encoding of the files that define JSErrorFormatStrings.
+#
+# JSErrorFormatString.format member should be in ASCII encoding.
+#----------------------------------------------------------------------------
+
+from __future__ import print_function
+
+import os
+import sys
+from check_utils import get_all_toplevel_filenames
+
+scriptname = os.path.basename(__file__);
+expected_encoding = 'ascii'
+
+# The following files don't define JSErrorFormatString.
+ignore_files = [
+    'dom/base/domerr.msg',
+    'js/xpconnect/src/xpc.msg',
+]
+
+def log_pass(filename, text):
+    print('TEST-PASS | {} | {} | {}'.format(scriptname, filename, text))
+
+def log_fail(filename, text):
+    print('TEST-UNEXPECTED-FAIL | {} | {} | {}'.format(scriptname, filename,
+                                                       text))
+
+def check_single_file(filename):
+    with open(filename, 'rb') as f:
+        data = f.read()
+        try:
+            data.decode(expected_encoding)
+        except:
+            log_fail(filename, 'not in {} encoding'.format(expected_encoding))
+
+    log_pass(filename, 'ok')
+    return True
+
+def check_files():
+    result = True
+
+    for filename in get_all_toplevel_filenames():
+        if filename.endswith('.msg'):
+            if filename not in ignore_files:
+                if not check_single_file(filename):
+                    result = False
+
+    return result
+
+def main():
+    if not check_files():
+        sys.exit(1)
+
+    sys.exit(0)
+
+if __name__ == '__main__':
+    main()
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -929,19 +929,22 @@ cargo_build_flags += --manifest-path $(C
 cargo_build_flags += --target=$(RUST_TARGET)
 cargo_build_flags += --verbose
 
 # Assume any system libraries rustc links against are already in the target's LIBS.
 #
 # We need to run cargo unconditionally, because cargo is the only thing that
 # has full visibility into how changes in Rust sources might affect the final
 # build.
+#
+# XXX: We're passing `-C debuginfo=1` to rustc to work around an llvm-dsymutil
+# crash (bug 1301751). This should be temporary until we upgrade to Rust 1.12.
 force-cargo-build:
 	$(REPORT_BUILD)
-	env CARGO_TARGET_DIR=. RUSTC=$(RUSTC) $(CARGO) build $(cargo_build_flags) --
+	env CARGO_TARGET_DIR=. RUSTC=$(RUSTC) RUSTFLAGS='-C debuginfo=1' $(CARGO) build $(cargo_build_flags) --
 
 $(RUST_LIBRARY_FILE): force-cargo-build
 endif # CARGO_FILE
 
 ifdef RUST_PRELINK
 # Make target for building a prelinked rust library. This merges rust .rlibs
 # together into a single .a file which is used within the FINAL_LIBRARY.
 #
--- a/devtools/client/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js
+++ b/devtools/client/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js
@@ -55,17 +55,19 @@ add_task(function* () {
   yield testClickOpenNewTab(hud, results2[0]);
 });
 
 function pushPrefEnv() {
   let deferred = promise.defer();
   let options = {
     "set": [
       ["security.mixed_content.block_active_content", true],
-      ["security.mixed_content.block_display_content", true]
+      ["security.mixed_content.block_display_content", true],
+      ["security.mixed_content.use_hsts", false],
+      ["security.mixed_content.send_hsts_priming", false],
     ]
   };
   SpecialPowers.pushPrefEnv(options, deferred.resolve);
   return deferred.promise;
 }
 
 function mixedContentOverrideTest2(hud, browser) {
   let deferred = promise.defer();
--- a/devtools/client/webconsole/test/browser_webconsole_bug_632817.js
+++ b/devtools/client/webconsole/test/browser_webconsole_bug_632817.js
@@ -89,16 +89,23 @@ function testXhrGet() {
 
 function testXhrWarn() {
   // Start the XMLHttpRequest() warn test.
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
     content.wrappedJSObject.testXhrWarn();
   });
 
   let lastRequest = yield waitForFinishedRequest(XHR_WARN_REQUEST_PREDICATE);
+  if (lastRequest.request.method == "HEAD") {
+    // in non-e10s, we get the HEAD request that priming sends, so make sure
+    // a priming request should be sent, and then get the actual request
+    is(Services.prefs.getBoolPref("security.mixed_content.send_hsts_priming"),
+        true, "Found HSTS Priming Request");
+    lastRequest = yield waitForFinishedRequest(XHR_WARN_REQUEST_PREDICATE);
+  }
 
   ok(lastRequest, "testXhrWarn() was logged");
   is(lastRequest.request.method, "GET", "Method is correct");
   ok(lastRequest.isXHR, "It's an XHR request");
   is(lastRequest.securityInfo, "insecure", "It's an insecure request");
 }
 
 function testXhrPost() {
--- a/devtools/shared/DevToolsUtils.js
+++ b/devtools/shared/DevToolsUtils.js
@@ -375,17 +375,18 @@ exports.defineLazyGetter(this, "NetworkH
  *        An object with the following optional properties:
  *        - loadFromCache: if false, will bypass the cache and
  *          always load fresh from the network (default: true)
  *        - policy: the nsIContentPolicy type to apply when fetching the URL
  *                  (only works when loading from system principal)
  *        - window: the window to get the loadGroup from
  *        - charset: the charset to use if the channel doesn't provide one
  *        - principal: the principal to use, if omitted, the request is loaded
- *                     with the system principal
+ *                     with a codebase principal corresponding to the url being
+ *                     loaded, using the origin attributes of the window, if any.
  *        - cacheKey: when loading from cache, use this key to retrieve a cache
  *                    specific to a given SHEntry. (Allows loading POST
  *                    requests from cache)
  * @returns Promise that resolves with an object with the following members on
  *          success:
  *           - content: the document at that URL, as a string,
  *           - contentType: the content type of the document
  *
@@ -521,61 +522,54 @@ function mainThreadFetch(aURL, aOptions 
  * Opens a channel for given URL. Tries a bit harder than NetUtil.newChannel.
  *
  * @param {String} url - The URL to open a channel for.
  * @param {Object} options - The options object passed to @method fetch.
  * @return {nsIChannel} - The newly created channel. Throws on failure.
  */
 function newChannelForURL(url, { policy, window, principal }) {
   var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
-  if (window) {
-    // Respect private browsing.
-    var req = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocumentLoader)
-                    .loadGroup;
-    if (req) {
-      var nc = req.notificationCallbacks;
-      if (nc) {
-        try {
-          var lc = nc.getInterface(Ci.nsILoadContext);
-          if (lc) {
-            if (lc.usePrivateBrowsing) {
-              securityFlags |= Ci.nsILoadInfo.SEC_FORCE_PRIVATE_BROWSING;
-            }
-          }
-        } catch (ex) {}
-      }
-    }
+
+  let uri;
+  try {
+    uri = Services.io.newURI(url, null, null);
+  } catch (e) {
+    // In the xpcshell tests, the script url is the absolute path of the test
+    // file, which will make a malformed URI error be thrown. Add the file
+    // scheme to see if it helps.
+    uri = Services.io.newURI("file://" + url, null, null);
   }
-
   let channelOptions = {
     contentPolicyType: policy,
     securityFlags: securityFlags,
-    uri: url
+    uri: uri
   };
-  if (principal) {
-    // contentPolicyType is required when loading with a custom principal
-    if (!channelOptions.contentPolicyType) {
-      channelOptions.contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER;
+  let prin = principal;
+  if (!prin) {
+    let oa = {};
+    if (window) {
+      oa = window.document.nodePrincipal.originAttributes;
     }
-    channelOptions.loadingPrincipal = principal;
-  } else {
-    channelOptions.loadUsingSystemPrincipal = true;
+    prin = Services.scriptSecurityManager
+                   .createCodebasePrincipal(uri, oa);
   }
+  // contentPolicyType is required when specifying a principal
+  if (!channelOptions.contentPolicyType) {
+    channelOptions.contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER;
+  }
+  channelOptions.loadingPrincipal = prin;
 
   try {
     return NetUtil.newChannel(channelOptions);
   } catch (e) {
-    // In the xpcshell tests, the script url is the absolute path of the test
-    // file, which will make a malformed URI error be thrown. Add the file
-    // scheme to see if it helps.
-    channelOptions.uri = "file://" + url;
-
-    return NetUtil.newChannel(channelOptions);
+    // In xpcshell tests on Windows, nsExternalProtocolHandler::NewChannel()
+    // can throw NS_ERROR_UNKNOWN_PROTOCOL if the external protocol isn't
+    // supported by Windows, so we also need to handle the exception here if
+    // parsing the URL above doesn't throw.
+    return newChannelForURL("file://" + url, { policy, window, principal });
   }
 }
 
 // Fetch is defined differently depending on whether we are on the main thread
 // or a worker thread.
 if (!this.isWorker) {
   exports.fetch = mainThreadFetch;
 } else {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4981,20 +4981,20 @@ nsDocShell::DisplayLoadError(nsresult aE
           UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
         bool isStsHost = false;
         bool isPinnedHost = false;
         if (XRE_IsParentProcess()) {
           nsCOMPtr<nsISiteSecurityService> sss =
             do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
-                                flags, &isStsHost);
+                                flags, nullptr, &isStsHost);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
-                                flags, &isPinnedHost);
+                                flags, nullptr, &isPinnedHost);
           NS_ENSURE_SUCCESS(rv, rv);
         } else {
           mozilla::dom::ContentChild* cc =
             mozilla::dom::ContentChild::GetSingleton();
           mozilla::ipc::URIParams uri;
           SerializeURI(aURI, uri);
           cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
                               &isStsHost);
@@ -9857,16 +9857,35 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
     if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
       return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
     }
 
     return NS_ERROR_CONTENT_BLOCKED;
   }
 
+  // If HSTS priming was set by nsMixedContentBlocker::ShouldLoad, and we
+  // would block due to mixed content, go ahead and block here. If we try to
+  // proceed with priming, we will error out later on.
+  nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(context);
+  NS_ENSURE_TRUE(docShell, NS_OK);
+  if (docShell) {
+    nsIDocument* document = docShell->GetDocument();
+    NS_ENSURE_TRUE(document, NS_OK);
+
+    HSTSPrimingState state = document->GetHSTSPrimingStateForLocation(aURI);
+    if (state == HSTSPrimingState::eHSTS_PRIMING_BLOCK) {
+      // HSTS Priming currently disabled for InternalLoad, so we need to clear
+      // the location that was added by nsMixedContentBlocker::ShouldLoad
+      // Bug 1269815 will address images loaded via InternalLoad
+      document->ClearHSTSPrimingLocation(aURI);
+      return NS_ERROR_CONTENT_BLOCKED;
+    }
+  }
+
   nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
   //
   // Get a principal from the current document if necessary.  Note that we only
   // do this for URIs that inherit a security context and local file URIs;
   // in particular we do NOT do this for about:blank.  This way, random
   // about:blank loads that have no principal (which basically means they were
   // done by someone from chrome manually messing with our nsIWebNavigation
   // or by C++ setting document.location) don't get a funky principal.  If
@@ -10833,20 +10852,16 @@ nsDocShell::DoURILoad(nsIURI* aURI,
 
   if (inherit) {
     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
   if (isSandBoxed) {
     securityFlags |= nsILoadInfo::SEC_SANDBOXED;
   }
 
-  if (UsePrivateBrowsing()) {
-    securityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING;
-  }
-
   nsCOMPtr<nsILoadInfo> loadInfo =
     (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
       new LoadInfo(loadingWindow, triggeringPrincipal,
                    securityFlags) :
       new LoadInfo(loadingPrincipal, triggeringPrincipal, loadingNode,
                    securityFlags, aContentPolicyType);
 
   if (aPrincipalToInherit) {
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -16,17 +16,18 @@
 #include "nsIDocumentObserver.h"         // for typedef (nsUpdateType)
 #include "nsILoadGroup.h"                // for member (in nsCOMPtr)
 #include "nsINode.h"                     // for base class
 #include "nsIScriptGlobalObject.h"       // for member (in nsCOMPtr)
 #include "nsIServiceManager.h"
 #include "nsIUUIDGenerator.h"
 #include "nsPIDOMWindow.h"               // for use in inline functions
 #include "nsPropertyTable.h"             // for member
-#include "nsTHashtable.h"                // for member
+#include "nsDataHashtable.h"             // for member
+#include "nsURIHashKey.h"                // for member
 #include "mozilla/net/ReferrerPolicy.h"  // for member
 #include "nsWeakReference.h"
 #include "mozilla/UseCounter.h"
 #include "mozilla/WeakPtr.h"
 #include "Units.h"
 #include "nsContentListDeclarations.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
@@ -170,16 +171,23 @@ typedef CallbackObjectHolder<NodeFilter,
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
   DocumentFlavorSVG, // SVGDocument
   DocumentFlavorPlain, // Just a Document
 };
 
+// Enum for HSTS priming states
+enum class HSTSPrimingState {
+  eNO_HSTS_PRIMING = 0,    // don't do HSTS Priming
+  eHSTS_PRIMING_ALLOW = 1, // if HSTS priming fails, allow the load to proceed
+  eHSTS_PRIMING_BLOCK = 2  // if HSTS priming fails, block the load
+};
+
 // Document states
 
 // RTL locale: specific to the XUL localedir attribute
 #define NS_DOCUMENT_STATE_RTL_LOCALE              NS_DEFINE_EVENT_STATE_MACRO(0)
 // Window activation status
 #define NS_DOCUMENT_STATE_WINDOW_INACTIVE         NS_DEFINE_EVENT_STATE_MACRO(1)
 
 // Some function forward-declarations
@@ -360,16 +368,44 @@ public:
     return mUpgradeInsecureRequests;
   }
 
   void SetReferrer(const nsACString& aReferrer) {
     mReferrer = aReferrer;
   }
 
   /**
+   * Check to see if a subresource we want to load requires HSTS priming
+   * to be done.
+   */
+  HSTSPrimingState GetHSTSPrimingStateForLocation(nsIURI* aContentLocation) const
+  {
+    HSTSPrimingState state;
+    if (mHSTSPrimingURIList.Get(aContentLocation, &state)) {
+      return state;
+    }
+    return HSTSPrimingState::eNO_HSTS_PRIMING;
+  }
+
+  /**
+   * Add a subresource to the HSTS priming list. If this URI is
+   * not in the HSTS cache, it will trigger an HSTS priming request
+   * when we try to load it.
+   */
+  void AddHSTSPrimingLocation(nsIURI* aContentLocation, HSTSPrimingState aState)
+  {
+    mHSTSPrimingURIList.Put(aContentLocation, aState);
+  }
+
+  void ClearHSTSPrimingLocation(nsIURI* aContentLocation)
+  {
+    mHSTSPrimingURIList.Remove(aContentLocation);
+  }
+
+  /**
    * Set the principal responsible for this document.
    */
   virtual void SetPrincipal(nsIPrincipal *aPrincipal) = 0;
 
   /**
    * Return the LoadGroup for the document. May return null.
    */
   already_AddRefed<nsILoadGroup> GetDocumentLoadGroup() const
@@ -2763,26 +2799,16 @@ public:
   bool HasScriptsBlockedBySandbox();
 
   void ReportHasScrollLinkedEffect();
   bool HasScrollLinkedEffect() const
   {
     return mHasScrollLinkedEffect;
   }
 
-  bool MayHavePluginFramesForPrinting()
-  {
-    return mMayHavePluginFramesForPrinting;
-  }
-
-  void SetMayHavePluginFramesForPrinting()
-  {
-    mMayHavePluginFramesForPrinting = true;
-  }
-
 protected:
   bool GetUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mUseCounters[aUseCounter];
   }
 
   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
@@ -2861,16 +2887,21 @@ protected:
   bool mReferrerPolicySet;
   ReferrerPolicyEnum mReferrerPolicy;
 
   bool mBlockAllMixedContent;
   bool mBlockAllMixedContentPreloads;
   bool mUpgradeInsecureRequests;
   bool mUpgradeInsecurePreloads;
 
+  // if nsMixedContentBlocker requires sending an HSTS priming request,
+  // temporarily store that in the document so that it can be propogated to the
+  // LoadInfo and eventually the HTTP Channel
+  nsDataHashtable<nsURIHashKey, HSTSPrimingState> mHSTSPrimingURIList;
+
   mozilla::WeakPtr<nsDocShell> mDocumentContainer;
 
   nsCString mCharacterSet;
   int32_t mCharacterSetSource;
 
   // This is just a weak pointer; the parent document owns its children.
   nsIDocument* mParentDocument;
 
@@ -3069,20 +3100,16 @@ protected:
   bool mGetUserFontSetCalled : 1;
 
   // Do we currently have an event posted to call FlushUserFontSet?
   bool mPostedFlushUserFontSet : 1;
 
   // True is document has ever been in a foreground window.
   bool mEverInForeground : 1;
 
-  // True if this document is a static clone for printing and may
-  // have elements referring to plugins in the original document.
-  bool mMayHavePluginFramesForPrinting : 1;
-
   enum Type {
     eUnknown, // should never be used
     eHTML,
     eXHTML,
     eGenericXML,
     eSVG,
     eXUL
   };
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1760,17 +1760,18 @@ void
 nsINode::Before(const Sequence<OwningNodeOrString>& aNodes,
                 ErrorResult& aRv)
 {
   nsCOMPtr<nsINode> parent = GetParentNode();
   if (!parent) {
     return;
   }
 
-  nsINode* viablePreviousSibling = FindViablePreviousSibling(*this, aNodes);
+  nsCOMPtr<nsINode> viablePreviousSibling =
+    FindViablePreviousSibling(*this, aNodes);
 
   nsCOMPtr<nsINode> node =
     ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
   if (aRv.Failed()) {
     return;
   }
 
   viablePreviousSibling = viablePreviousSibling ?
@@ -1783,17 +1784,17 @@ void
 nsINode::After(const Sequence<OwningNodeOrString>& aNodes,
                ErrorResult& aRv)
 {
   nsCOMPtr<nsINode> parent = GetParentNode();
   if (!parent) {
     return;
   }
 
-  nsINode* viableNextSibling = FindViableNextSibling(*this, aNodes);
+  nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
 
   nsCOMPtr<nsINode> node =
     ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
   if (aRv.Failed()) {
     return;
   }
 
   parent->InsertBefore(*node, viableNextSibling, aRv);
@@ -1803,17 +1804,17 @@ void
 nsINode::ReplaceWith(const Sequence<OwningNodeOrString>& aNodes,
                      ErrorResult& aRv)
 {
   nsCOMPtr<nsINode> parent = GetParentNode();
   if (!parent) {
     return;
   }
 
-  nsINode* viableNextSibling = FindViableNextSibling(*this, aNodes);
+  nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
 
   nsCOMPtr<nsINode> node =
     ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
   if (aRv.Failed()) {
     return;
   }
 
   if (parent == GetParentNode()) {
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -2902,23 +2902,19 @@ nsObjectLoadingContent::CreateStaticClon
   aDest->mType = mType;
   nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
   if (thisObj->mPrintFrame.IsAlive()) {
     aDest->mPrintFrame = thisObj->mPrintFrame;
   } else {
     aDest->mPrintFrame = const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame();
   }
 
-  nsCOMPtr<nsIContent> content =
-    do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
-  if (aDest->mPrintFrame) {
-    content->OwnerDoc()->SetMayHavePluginFramesForPrinting();
-  }
-
   if (mFrameLoader) {
+    nsCOMPtr<nsIContent> content =
+      do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
     nsFrameLoader* fl = nsFrameLoader::Create(content->AsElement(), false);
     if (fl) {
       aDest->mFrameLoader = fl;
       mFrameLoader->CreateStaticClone(fl);
     }
   }
 }
 
--- a/dom/base/test/bug704320.sjs
+++ b/dom/base/test/bug704320.sjs
@@ -189,16 +189,22 @@ function createPolicyTest(policy, option
                     onload="incrementLoad2(\'img\', 2);">\n\
             <img src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=img"\n\
                     onload="incrementLoad2(\'img\', 2);">\n\
           </body>\n\
           </html>';
 }
 
 function handleRequest(request, response) {
+  if (request.method == 'HEAD') {
+    // respond to a HEAD request with a 418 so that we can easily distinguish
+    // HSTS priming responses and ignore them
+    response.setStatusLine('1.1', 418, "I'm a teapot");
+    return;
+  }
   var sharedKey = 'bug704320.sjs';
   var params = request.queryString.split('&');
   var action = params[0].split('=')[1];
 
   if (action === 'create-1st-level-iframe') {
     // ?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin
     var schemeFrom = params[1].split('=')[1];
     var schemeTo = params[2].split('=')[1];
--- a/dom/base/test/referrerHelper.js
+++ b/dom/base/test/referrerHelper.js
@@ -20,16 +20,19 @@ window.addEventListener("message", funct
 /**
  * helper to perform an XHR.
  */
 function doXHR(url, onSuccess, onFail) {
   var xhr = new XMLHttpRequest();
   xhr.onload = function () {
     if (xhr.status == 200) {
       onSuccess(xhr);
+    } else if (xhr.status == 418) {
+      // Ignore HSTS priming responses
+      return;
     } else {
       onFail(xhr);
     }
   };
   xhr.open('GET', url, true);
   xhr.send(null);
 }
 
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -89,17 +89,17 @@ MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMET
 MSG_DEF(MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
 MSG_DEF(MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
 MSG_DEF(MSG_PROMISE_ARG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable")
 MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
 MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
 MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
 MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer")
 MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 3, JSEXN_TYPEERR, "Cache got {0} response with bad status {1} while trying to add request {2}")
-MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 2, JSEXN_TYPEERR, "Failed to update the ServiceWorker for scope {0] because the registration has been {1} since the update was scheduled.")
+MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 2, JSEXN_TYPEERR, "Failed to update the ServiceWorker for scope {0} because the registration has been {1} since the update was scheduled.")
 MSG_DEF(MSG_INVALID_DURATION_ERROR, 1, JSEXN_TYPEERR, "Invalid duration '{0}'.")
 MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.")
 MSG_DEF(MSG_INVALID_SPACING_MODE_ERROR, 1, JSEXN_TYPEERR, "Invalid spacing '{0}'.")
 MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
 MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")
 MSG_DEF(MSG_CACHE_STREAM_CLOSED, 0, JSEXN_TYPEERR, "Response body is a cache file stream that has already been closed.")
 MSG_DEF(MSG_TIME_VALUE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "{0} is outside the supported range for time values.")
 MSG_DEF(MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN, 1, JSEXN_TYPEERR, "Request mode '{0}' was used, but request cache mode 'only-if-cached' can only be used with request mode 'same-origin'.")
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5763,16 +5763,18 @@ CanvasRenderingContext2D::PutImageData_e
     return NS_ERROR_FAILURE;
   }
 
   uint32_t copyX = dirtyRect.x - aX;
   uint32_t copyY = dirtyRect.y - aY;
   //uint8_t *src = aArray->Data();
   uint8_t *dst = imgsurf->Data();
   uint8_t* srcLine = aArray->Data() + copyY * (aW * 4) + copyX * 4;
+  // For opaque canvases, we must still premultiply the RGB components, but write the alpha as opaque.
+  uint8_t alphaMask = mOpaque ? 255 : 0;
 #if 0
   printf("PutImageData_explicit: dirty x=%d y=%d w=%d h=%d copy x=%d y=%d w=%d h=%d ext x=%d y=%d w=%d h=%d\n",
        dirtyRect.x, dirtyRect.y, copyWidth, copyHeight,
        copyX, copyY, copyWidth, copyHeight,
        x, y, w, h);
 #endif
   for (uint32_t j = 0; j < copyHeight; j++) {
     uint8_t *src = srcLine;
@@ -5782,19 +5784,19 @@ CanvasRenderingContext2D::PutImageData_e
       uint8_t b = *src++;
       uint8_t a = *src++;
 
       // Convert to premultiplied color (losslessly if the input came from getImageData)
 #if MOZ_LITTLE_ENDIAN
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r];
-      *dst++ = a;
+      *dst++ = a | alphaMask;
 #else
-      *dst++ = a;
+      *dst++ = a | alphaMask;
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g];
       *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b];
 #endif
     }
     srcLine += aW * 4;
   }
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -564,17 +564,17 @@ BaseCaps(const WebGLContextOptions& opti
         if (!layerManager)
             break;
 
         // XXX we really want "AsSurfaceAllocator" here for generality
         layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder();
         if (!forwarder)
             break;
 
-        baseCaps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
+        baseCaps.surfaceAllocator = forwarder->GetTextureForwarder();
     } while (false);
 #endif
 
     // Done with baseCaps construction.
 
     if (!gfxPrefs::WebGLForceMSAA()) {
         const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
 
new file mode 100644
--- /dev/null
+++ b/dom/canvas/crashtests/1305312-1.html
@@ -0,0 +1,5 @@
+<canvas id='cid'></canvas>
+<script>
+var x=document.getElementById('cid').getContext('2d',{alpha: false});
+x.putImageData(x.createImageData(250,27434.63),Number.MAX_SAFE_INTEGER,23);
+</script>
\ No newline at end of file
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -32,9 +32,10 @@ load 1284356-1.html
 load 1284578-1.html
 skip-if(d2d) load 1287515-1.html
 load 1287652-1.html
 load 1288872-1.html
 load 1290628-1.html
 load 1283113-1.html
 load 1286458-1.html
 load 1299062-1.html
+load 1305312-1.html
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3437,17 +3437,17 @@ HTMLInputElement::Focus(ErrorResult& aEr
         break;
       }
     }
   }
 
   return;
 }
 
-#if defined(XP_WIN) || defined(XP_LINUX)
+#if !defined(ANDROID) && !defined(XP_MACOSX)
 bool
 HTMLInputElement::IsNodeApzAwareInternal() const
 {
   // Tell APZC we may handle mouse wheel event and do preventDefault when input
   // type is number.
   return (mType == NS_FORM_INPUT_NUMBER) || (mType == NS_FORM_INPUT_RANGE) ||
          nsINode::IsNodeApzAwareInternal();
 }
@@ -4533,17 +4533,17 @@ HTMLInputElement::PostHandleEvent(EventC
               // aggressive about stopping the spin. (And don't set
               // nsEventStatus_eConsumeNoDefault after doing so, since that
               // might prevent, say, the context menu from opening.)
               StopNumberControlSpinnerSpin();
             }
           }
           break;
         }
-#if defined(XP_WIN) || defined(XP_LINUX)
+#if !defined(ANDROID) && !defined(XP_MACOSX)
         case eWheel: {
           // Handle wheel events as increasing / decreasing the input element's
           // value when it's focused and it's type is number or range.
           WidgetWheelEvent* wheelEvent = aVisitor.mEvent->AsWheelEvent();
           if (!aVisitor.mEvent->DefaultPrevented() &&
               aVisitor.mEvent->IsTrusted() && IsMutable() && wheelEvent &&
               wheelEvent->mDeltaY != 0 &&
               wheelEvent->mDeltaMode != nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
@@ -6198,17 +6198,17 @@ FireEventForAccessibility(nsIDOMHTMLInpu
 
   return NS_OK;
 }
 #endif
 
 void
 HTMLInputElement::UpdateApzAwareFlag()
 {
-#if defined(XP_WIN) || defined(XP_LINUX)
+#if !defined(ANDROID) && !defined(XP_MACOSX)
   if ((mType == NS_FORM_INPUT_NUMBER) || (mType == NS_FORM_INPUT_RANGE)) {
     SetMayBeApzAware();
   }
 #endif
 }
 
 nsresult
 HTMLInputElement::SetDefaultValueAsValue()
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -130,17 +130,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual int32_t TabIndexDefault() override;
   using nsGenericHTMLElement::Focus;
   virtual void Blur(ErrorResult& aError) override;
   virtual void Focus(ErrorResult& aError) override;
 
   // nsINode
-#if defined(XP_WIN) || defined(XP_LINUX)
+#if !defined(ANDROID) && !defined(XP_MACOSX)
   virtual bool IsNodeApzAwareInternal() const override;
 #endif
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
   // nsIDOMHTMLInputElement
   NS_DECL_NSIDOMHTMLINPUTELEMENT
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -560,26 +560,16 @@ public:
       securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
     }
 
     MOZ_ASSERT(aElement->IsAnyOfHTMLElements(nsGkAtoms::audio, nsGkAtoms::video));
     nsContentPolicyType contentPolicyType = aElement->IsHTMLElement(nsGkAtoms::audio)
       ? nsIContentPolicy::TYPE_INTERNAL_AUDIO :
         nsIContentPolicy::TYPE_INTERNAL_VIDEO;
 
-    nsCOMPtr<nsIDocShell> docShell = aElement->OwnerDoc()->GetDocShell();
-    if (docShell) {
-      nsDocShell* docShellPtr = nsDocShell::Cast(docShell);
-      bool privateBrowsing;
-      docShellPtr->GetUsePrivateBrowsing(&privateBrowsing);
-      if (privateBrowsing) {
-        securityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING;
-      }
-    }
-
     nsCOMPtr<nsILoadGroup> loadGroup = aElement->GetDocumentLoadGroup();
     nsCOMPtr<nsIChannel> channel;
     nsresult rv = NS_NewChannel(getter_AddRefs(channel),
                                 aElement->mLoadingSrc,
                                 static_cast<Element*>(aElement),
                                 securityFlags,
                                 contentPolicyType,
                                 loadGroup,
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -617,19 +617,19 @@ skip-if = buildapp == 'b2g' # bug 112901
 [test_bug1166138.html]
 [test_bug1230665.html]
 [test_filepicker_default_directory.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
 [test_bug1233598.html]
 [test_bug1250401.html]
 [test_bug1260664.html]
 [test_bug1261673.html]
-skip-if = (os != 'win' && os != 'linux')
+skip-if = (os == 'android' || os == 'mac')
 [test_bug1261674-1.html]
-skip-if = (os != 'win' && os != 'linux')
+skip-if = (os == 'android' || os == 'mac')
 [test_bug1261674-2.html]
-skip-if = (os != 'win' && os != 'linux')
+skip-if = (os == 'android' || os == 'mac')
 [test_bug1260704.html]
 [test_allowMedia.html]
 [test_bug1292522_same_domain_with_different_port_number.html]
 [test_bug1295719_event_sequence_for_arrow_keys.html]
 skip-if = os == "android" || appname == "b2g" # up/down arrow keys not supported on android/b2g
 [test_bug1295719_event_sequence_for_number_keys.html]
--- a/dom/html/test/test_anchor_ping.html
+++ b/dom/html/test/test_anchor_ping.html
@@ -36,21 +36,24 @@ addLoadEvent(function () {
 
 let tests = [
 
   // Ensure that sending pings is enabled.
   function* setup() {
     Services.prefs.setBoolPref("browser.send_pings", true);
     Services.prefs.setIntPref("browser.send_pings.max_per_link", -1);
     Services.prefs.setBoolPref("security.mixed_content.block_active_content", false);
+    // The server we create can't handle the priming HEAD requests
+    Services.prefs.setBoolPref("security.mixed_content.send_hsts_priming", false);
 
     SimpleTest.registerCleanupFunction(() => {
       Services.prefs.clearUserPref("browser.send_pings");
       Services.prefs.clearUserPref("browser.send_pings.max_per_link");
       Services.prefs.clearUserPref("security.mixed_content.block_active_content");
+      Services.prefs.clearUserPref("security.mixed_content.send_hsts_priming");
     });
   },
 
   // If both the address of the document containing the hyperlink being audited
   // and ping URL have the same origin then the request must include a Ping-From
   // HTTP header with, as its value, the address of the document containing the
   // hyperlink, and a Ping-To HTTP header with, as its value, the target URL.
   // The request must not include a Referer (sic) HTTP header.
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -5309,17 +5309,17 @@ private:
   struct DatabasesCompleteCallback;
   class FinishCallbackWrapper;
   class IdleConnectionRunnable;
   struct IdleDatabaseInfo;
   struct IdleResource;
   struct IdleThreadInfo;
   struct ThreadInfo;
   class ThreadRunnable;
-  struct TransactionInfo;
+  class TransactionInfo;
   struct TransactionInfoPair;
 
   // This mutex guards mDatabases, see below.
   Mutex mDatabasesMutex;
 
   nsTArray<IdleThreadInfo> mIdleThreads;
   nsTArray<IdleDatabaseInfo> mIdleDatabases;
   nsTArray<DatabaseInfo*> mDatabasesPerformingIdleMaintenance;
@@ -5708,28 +5708,31 @@ public:
   }
 
 private:
   ~ThreadRunnable();
 
   NS_DECL_NSIRUNNABLE
 };
 
-struct ConnectionPool::TransactionInfo final
+class ConnectionPool::TransactionInfo final
 {
   friend class nsAutoPtr<TransactionInfo>;
 
+  nsTHashtable<nsPtrHashKey<TransactionInfo>> mBlocking;
+  nsTArray<TransactionInfo*> mBlockingOrdered;
+
+public:
   DatabaseInfo* mDatabaseInfo;
   const nsID mBackgroundChildLoggingId;
   const nsCString mDatabaseId;
   const uint64_t mTransactionId;
   const int64_t mLoggingSerialNumber;
   const nsTArray<nsString> mObjectStoreNames;
   nsTHashtable<nsPtrHashKey<TransactionInfo>> mBlockedOn;
-  nsTHashtable<nsPtrHashKey<TransactionInfo>> mBlocking;
   nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
   const bool mIsWriteTransaction;
   bool mRunning;
 
 #ifdef DEBUG
   bool mFinished;
 #endif
 
@@ -5738,20 +5741,26 @@ struct ConnectionPool::TransactionInfo f
                   const nsACString& aDatabaseId,
                   uint64_t aTransactionId,
                   int64_t aLoggingSerialNumber,
                   const nsTArray<nsString>& aObjectStoreNames,
                   bool aIsWriteTransaction,
                   TransactionDatabaseOperationBase* aTransactionOp);
 
   void
-  Schedule();
+  AddBlockingTransaction(TransactionInfo* aTransactionInfo);
+
+  void
+  RemoveBlockingTransactions();
 
 private:
   ~TransactionInfo();
+
+  void
+  MaybeUnblock(TransactionInfo* aTransactionInfo);
 };
 
 struct ConnectionPool::TransactionInfoPair final
 {
   friend class nsAutoPtr<TransactionInfoPair>;
 
   // Multiple reading transactions can block future writes.
   nsTArray<TransactionInfo*> mLastBlockingWrites;
@@ -11740,28 +11749,28 @@ ConnectionPool::Start(const nsID& aBackg
     if (!blockInfo) {
       blockInfo = new TransactionInfoPair();
       blockingTransactions.Put(objectStoreName, blockInfo);
     }
 
     // Mark what we are blocking on.
     if (TransactionInfo* blockingRead = blockInfo->mLastBlockingReads) {
       transactionInfo->mBlockedOn.PutEntry(blockingRead);
-      blockingRead->mBlocking.PutEntry(transactionInfo);
+      blockingRead->AddBlockingTransaction(transactionInfo);
     }
 
     if (aIsWriteTransaction) {
       if (const uint32_t writeCount = blockInfo->mLastBlockingWrites.Length()) {
         for (uint32_t writeIndex = 0; writeIndex < writeCount; writeIndex++) {
           TransactionInfo* blockingWrite =
             blockInfo->mLastBlockingWrites[writeIndex];
           MOZ_ASSERT(blockingWrite);
 
           transactionInfo->mBlockedOn.PutEntry(blockingWrite);
-          blockingWrite->mBlocking.PutEntry(transactionInfo);
+          blockingWrite->AddBlockingTransaction(transactionInfo);
         }
       }
 
       blockInfo->mLastBlockingReads = transactionInfo;
       blockInfo->mLastBlockingWrites.Clear();
     } else {
       blockInfo->mLastBlockingWrites.AppendElement(transactionInfo);
     }
@@ -12283,28 +12292,17 @@ ConnectionPool::NoteFinishedTransaction(
     if (transactionInfo->mIsWriteTransaction &&
         blockInfo->mLastBlockingReads == transactionInfo) {
       blockInfo->mLastBlockingReads = nullptr;
     }
 
     blockInfo->mLastBlockingWrites.RemoveElement(transactionInfo);
   }
 
-  for (auto iter = transactionInfo->mBlocking.Iter();
-       !iter.Done();
-       iter.Next()) {
-    TransactionInfo* blockedInfo = iter.Get()->GetKey();
-    MOZ_ASSERT(blockedInfo);
-    MOZ_ASSERT(blockedInfo->mBlockedOn.Contains(transactionInfo));
-
-    blockedInfo->mBlockedOn.RemoveEntry(transactionInfo);
-    if (!blockedInfo->mBlockedOn.Count()) {
-      blockedInfo->Schedule();
-    }
-  }
+  transactionInfo->RemoveBlockingTransactions();
 
   if (transactionInfo->mIsWriteTransaction) {
     MOZ_ASSERT(dbInfo->mWriteTransactionCount);
     dbInfo->mWriteTransactionCount--;
   } else {
     MOZ_ASSERT(dbInfo->mReadTransactionCount);
     dbInfo->mReadTransactionCount--;
   }
@@ -13063,28 +13061,65 @@ TransactionInfo::~TransactionInfo()
   MOZ_ASSERT(!mRunning);
   MOZ_ASSERT(mFinished);
 
   MOZ_COUNT_DTOR(ConnectionPool::TransactionInfo);
 }
 
 void
 ConnectionPool::
-TransactionInfo::Schedule()
-{
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(mDatabaseInfo);
-
-  ConnectionPool* connectionPool = mDatabaseInfo->mConnectionPool;
-  MOZ_ASSERT(connectionPool);
-  connectionPool->AssertIsOnOwningThread();
-
-  Unused <<
-    connectionPool->ScheduleTransaction(this,
-                                        /* aFromQueuedTransactions */ false);
+TransactionInfo::AddBlockingTransaction(TransactionInfo* aTransactionInfo)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aTransactionInfo);
+
+  if (!mBlocking.Contains(aTransactionInfo)) {
+    mBlocking.PutEntry(aTransactionInfo);
+    mBlockingOrdered.AppendElement(aTransactionInfo);
+  }
+}
+
+void
+ConnectionPool::
+TransactionInfo::RemoveBlockingTransactions()
+{
+  AssertIsOnBackgroundThread();
+
+  for (uint32_t index = 0, count = mBlockingOrdered.Length();
+       index < count;
+       index++) {
+    TransactionInfo* blockedInfo = mBlockingOrdered[index];
+    MOZ_ASSERT(blockedInfo);
+
+    blockedInfo->MaybeUnblock(this);
+  }
+
+  mBlocking.Clear();
+  mBlockingOrdered.Clear();
+}
+
+void
+ConnectionPool::
+TransactionInfo::MaybeUnblock(TransactionInfo* aTransactionInfo)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mBlockedOn.Contains(aTransactionInfo));
+
+  mBlockedOn.RemoveEntry(aTransactionInfo);
+  if (!mBlockedOn.Count()) {
+    MOZ_ASSERT(mDatabaseInfo);
+
+    ConnectionPool* connectionPool = mDatabaseInfo->mConnectionPool;
+    MOZ_ASSERT(connectionPool);
+    connectionPool->AssertIsOnOwningThread();
+
+    Unused <<
+      connectionPool->ScheduleTransaction(this,
+                                          /* aFromQueuedTransactions */ false);
+  }
 }
 
 ConnectionPool::
 TransactionInfoPair::TransactionInfoPair()
   : mLastBlockingReads(nullptr)
 {
   AssertIsOnBackgroundThread();
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1549,25 +1549,27 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObject
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 
   // Don't unlink mTransaction!
 
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedIndexes)
 
   tmp->mCachedKeyPath.setUndefined();
 
   if (tmp->mRooted) {
     mozilla::DropJSObjects(tmp);
     tmp->mRooted = false;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -1769,23 +1771,21 @@ IDBObjectStore::CreateIndex(const nsAStr
 
   if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
       mDeletedSpec) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
     return nullptr;
   }
 
   IDBTransaction* transaction = IDBTransaction::GetCurrent();
-  if (!transaction || transaction != mTransaction) {
+  if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return nullptr;
   }
 
-  MOZ_ASSERT(transaction->IsOpen());
-
   auto& indexes = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
   for (uint32_t count = indexes.Length(), index = 0;
        index < count;
        index++) {
     if (aName == indexes[index].name()) {
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
       return nullptr;
     }
@@ -1883,23 +1883,21 @@ IDBObjectStore::DeleteIndex(const nsAStr
 
   if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
       mDeletedSpec) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
     return;
   }
 
   IDBTransaction* transaction = IDBTransaction::GetCurrent();
-  if (!transaction || transaction != mTransaction) {
+  if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return;
   }
 
-  MOZ_ASSERT(transaction->IsOpen());
-
   auto& metadataArray = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
 
   int64_t foundId = 0;
 
   for (uint32_t metadataCount = metadataArray.Length(), metadataIndex = 0;
        metadataIndex < metadataCount;
        metadataIndex++) {
     const IndexMetadata& metadata = metadataArray[metadataIndex];
@@ -1911,16 +1909,21 @@ IDBObjectStore::DeleteIndex(const nsAStr
       // Must do this before altering the metadata array!
       for (uint32_t indexCount = mIndexes.Length(), indexIndex = 0;
            indexIndex < indexCount;
            indexIndex++) {
         RefPtr<IDBIndex>& index = mIndexes[indexIndex];
 
         if (index->Id() == foundId) {
           index->NoteDeletion();
+
+          RefPtr<IDBIndex>* deletedIndex =
+            mDeletedIndexes.AppendElement();
+          deletedIndex->swap(mIndexes[indexIndex]);
+
           mIndexes.RemoveElementAt(indexIndex);
           break;
         }
       }
 
       metadataArray.RemoveElementAt(metadataIndex);
 
       RefreshSpec(/* aMayDelete */ false);
@@ -2125,16 +2128,22 @@ IDBObjectStore::RefreshSpec(bool aMayDel
       mSpec = &objSpec;
 
       for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
            idxIndex < idxCount;
            idxIndex++) {
         mIndexes[idxIndex]->RefreshMetadata(aMayDelete);
       }
 
+      for (uint32_t idxCount = mDeletedIndexes.Length(), idxIndex = 0;
+           idxIndex < idxCount;
+           idxIndex++) {
+        mDeletedIndexes[idxIndex]->RefreshMetadata(false);
+      }
+
       found = true;
       break;
     }
   }
 
   MOZ_ASSERT_IF(!aMayDelete && !mDeletedSpec, found);
 
   if (found) {
@@ -2197,23 +2206,21 @@ IDBObjectStore::SetName(const nsAString&
 
   if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
       mDeletedSpec) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   IDBTransaction* transaction = IDBTransaction::GetCurrent();
-  if (!transaction || transaction != mTransaction) {
+  if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
     return;
   }
 
-  MOZ_ASSERT(transaction->IsOpen());
-
   if (aName == mSpec->metadata().name()) {
     return;
   }
 
   // Cache logging string of this object store before renaming.
   const LoggingString loggingOldObjectStore(this);
 
   nsresult rv =
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -62,16 +62,17 @@ class IDBObjectStore final
   // This normally points to the ObjectStoreSpec owned by the parent IDBDatabase
   // object. However, if this objectStore is part of a versionchange transaction
   // and it gets deleted then the spec is copied into mDeletedSpec and mSpec is
   // set to point at mDeletedSpec.
   const ObjectStoreSpec* mSpec;
   nsAutoPtr<ObjectStoreSpec> mDeletedSpec;
 
   nsTArray<RefPtr<IDBIndex>> mIndexes;
+  nsTArray<RefPtr<IDBIndex>> mDeletedIndexes;
 
   const int64_t mId;
   bool mRooted;
 
 public:
   struct StructuredCloneWriteInfo;
 
   static already_AddRefed<IDBObjectStore>
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -648,16 +648,22 @@ IDBTransaction::AbortInternal(nsresult a
   if (isVersionChange) {
     // If a version change transaction is aborted, we must revert the world
     // back to its previous state unless we're being invalidated after the
     // transaction already completed.
     if (!isInvalidated) {
       mDatabase->RevertToPreviousState();
     }
 
+    // We do the reversion only for the mObjectStores/mDeletedObjectStores but
+    // not for the mIndexes/mDeletedIndexes of each IDBObjectStore because it's
+    // time-consuming(O(m*n)) and mIndexes/mDeletedIndexes won't be used anymore
+    // in IDBObjectStore::(Create|Delete)Index() and IDBObjectStore::Index() in
+    // which all the executions are returned earlier by !transaction->IsOpen().
+
     const nsTArray<ObjectStoreSpec>& specArray =
       mDatabase->Spec()->objectStores();
 
     if (specArray.IsEmpty()) {
       mObjectStores.Clear();
       mDeletedObjectStores.Clear();
     } else {
       nsTHashtable<nsUint64HashKey> validIds(specArray.Length());
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -14,16 +14,18 @@ support-files =
   file_app_isolation.html
   file_app_isolation.js
   helpers.js
   leaving_page_iframe.html
   service_worker.js
   service_worker_client.html
   third_party_iframe1.html
   third_party_iframe2.html
+  unit/test_abort_deleted_index.js
+  unit/test_abort_deleted_objectStore.js
   unit/test_add_put.js
   unit/test_add_twice_failure.js
   unit/test_advance.js
   unit/test_autoIncrement.js
   unit/test_autoIncrement_indexes.js
   unit/test_blob_file_backed.js
   unit/test_blocked_order.js
   unit/test_clear.js
@@ -110,16 +112,20 @@ support-files =
   unit/test_transaction_lifetimes_nested.js
   unit/test_transaction_ordering.js
   unit/test_unique_index_update.js
   unit/test_writer_starvation.js
   webapp_clearBrowserData.js
   webapp_clearBrowserData_appFrame.html
   webapp_clearBrowserData_browserFrame.html
 
+[test_abort_deleted_index.html]
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+[test_abort_deleted_objectStore.html]
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_add_put.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_add_twice_failure.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_advance.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_app_isolation_inproc.html]
 # The app isolation tests are only supposed to run in the main process.
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_abort_deleted_index.html
@@ -0,0 +1,19 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Abort Deleted Index Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7" src="unit/test_abort_deleted_index.js"></script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_abort_deleted_objectStore.html
@@ -0,0 +1,19 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Abort Deleted ObjectStore Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7" src="unit/test_abort_deleted_objectStore.js"></script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_abort_deleted_index.js
@@ -0,0 +1,78 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const name = this.window ? window.location.pathname : "Splendid Test";
+  const storeName = "test store";
+  const indexName_ToBeDeleted = "test index to be deleted";
+
+  info("Create index in v1.");
+  let request = indexedDB.open(name, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = unexpectedSuccessHandler;
+  let event = yield undefined;
+
+  let db = event.target.result;
+  let txn = event.target.transaction;
+
+  is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
+
+  let objectStore = db.createObjectStore(storeName, { keyPath: "foo" });
+  is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
+  is(db.objectStoreNames.item(0), objectStore.name, "Correct object store name");
+
+  // create index to be deleted later in v2.
+  objectStore.createIndex(indexName_ToBeDeleted, "foo");
+  ok(objectStore.index(indexName_ToBeDeleted), "Index created.");
+
+  txn.oncomplete = continueToNextStepSync;
+  yield undefined;
+  request.onsuccess = continueToNextStep;
+  yield undefined;
+  db.close();
+
+  info("Delete index in v2.");
+  request = indexedDB.open(name, 2);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = unexpectedSuccessHandler;
+  event = yield undefined;
+
+  db = event.target.result;
+  txn = event.target.transaction;
+
+  objectStore = txn.objectStore(storeName);
+  let index = objectStore.index(indexName_ToBeDeleted);
+  ok(index, "index is valid.");
+  objectStore.deleteIndex(indexName_ToBeDeleted);
+
+  // Aborting the transaction.
+  request.onerror = expectedErrorHandler("AbortError");
+  txn.abort();
+  try {
+    index.get('foo');
+    ok(false, "TransactionInactiveError shall be thrown right after a deletion of an index is aborted.");
+  } catch (e) {
+    ok(e instanceof DOMException, "got a database exception");
+    is(e.name, "TransactionInactiveError", "TransactionInactiveError shall be thrown right after a deletion of an index is aborted.");
+  }
+
+  yield undefined;
+
+  try {
+    index.get('foo');
+    ok(false, "TransactionInactiveError shall be thrown after the transaction is inactive.");
+  } catch (e) {
+    ok(e instanceof DOMException, "got a database exception");
+    is(e.name, "TransactionInactiveError", "TransactionInactiveError shall be thrown after the transaction is inactive.");
+  }
+
+  finishTest();
+  yield undefined;
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_abort_deleted_objectStore.js
@@ -0,0 +1,74 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const name = this.window ? window.location.pathname : "Splendid Test";
+  const storeName_ToBeDeleted = "test store to be deleted";
+
+  info("Create objectStore in v1.");
+  let request = indexedDB.open(name, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = unexpectedSuccessHandler;
+  let event = yield undefined;
+
+  let db = event.target.result;
+  let txn = event.target.transaction;
+
+  is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
+
+  // create objectstore to be deleted later in v2.
+  db.createObjectStore(storeName_ToBeDeleted, { keyPath: "foo" });
+  is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
+  ok(db.objectStoreNames.contains(storeName_ToBeDeleted), "Correct name");
+
+  txn.oncomplete = continueToNextStepSync;
+  yield undefined;
+  request.onsuccess = continueToNextStep;
+  yield undefined;
+  db.close();
+
+  info("Delete objectStore in v2.");
+  request = indexedDB.open(name, 2);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = unexpectedSuccessHandler;
+  event = yield undefined;
+
+  db = event.target.result;
+  txn = event.target.transaction;
+
+  let objectStore = txn.objectStore(storeName_ToBeDeleted);
+  ok(objectStore, "objectStore is available");
+
+  db.deleteObjectStore(storeName_ToBeDeleted);
+
+  // Aborting the transaction.
+  request.onerror = expectedErrorHandler("AbortError");
+  txn.abort();
+  try {
+    objectStore.get('foo');
+    ok(false, "TransactionInactiveError shall be thrown if the transaction is inactive.");
+  } catch (e) {
+    ok(e instanceof DOMException, "got a database exception");
+    is(e.name, "TransactionInactiveError", "correct error");
+  }
+
+  yield undefined;
+
+  try {
+    objectStore.get('foo');
+    ok(false, "TransactionInactiveError shall be thrown if the transaction is inactive.");
+  } catch (e) {
+    ok(e instanceof DOMException, "got a database exception");
+    is(e.name, "TransactionInactiveError", "correct error");
+  }
+
+  finishTest();
+  yield undefined;
+}
--- a/dom/indexedDB/test/unit/xpcshell-shared.ini
+++ b/dom/indexedDB/test/unit/xpcshell-shared.ini
@@ -1,12 +1,14 @@
 # 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/.
 
+[test_abort_deleted_index.js]
+[test_abort_deleted_objectStore.js]
 [test_add_put.js]
 [test_add_twice_failure.js]
 [test_advance.js]
 [test_autoIncrement.js]
 [test_autoIncrement_indexes.js]
 [test_blocked_order.js]
 [test_clear.js]
 [test_complex_keyPaths.js]
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -3569,20 +3569,17 @@ BlobChild::SetMysteryBlobInfo(const nsSt
 
 bool
 BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mBlobImpl);
   MOZ_ASSERT(mRemoteBlobImpl);
 
-  nsString voidString;
-  voidString.SetIsVoid(true);
-
-  mBlobImpl->SetLazyData(voidString, aContentType, aLength, INT64_MAX);
+  mBlobImpl->SetLazyData(NullString(), aContentType, aLength, INT64_MAX);
 
   NormalBlobConstructorParams params(aContentType,
                                      aLength,
                                      void_t() /* optionalBlobData */);
   return SendResolveMystery(params);
 }
 
 void
@@ -4395,20 +4392,17 @@ BlobParent::RecvResolveMystery(const Res
       const NormalBlobConstructorParams& params =
         aParams.get_NormalBlobConstructorParams();
 
       if (NS_WARN_IF(params.length() == UINT64_MAX)) {
         ASSERT_UNLESS_FUZZING();
         return false;
       }
 
-      nsString voidString;
-      voidString.SetIsVoid(true);
-
-      mBlobImpl->SetLazyData(voidString,
+      mBlobImpl->SetLazyData(NullString(),
                              params.contentType(),
                              params.length(),
                              INT64_MAX);
       return true;
     }
 
     case ResolveMysteryParams::TFileBlobConstructorParams: {
       const FileBlobConstructorParams& params =
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -817,24 +817,25 @@ ContentChild::ProvideWindowCommon(TabChi
     return NS_ERROR_ABORT;
   }
 
   if (layersId == 0) { // if renderFrame is invalid.
     PRenderFrameChild::Send__delete__(renderFrame);
     renderFrame = nullptr;
   }
 
-  ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0);
+  ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0, 0);
   auto* opener = nsPIDOMWindowOuter::From(aParent);
   nsIDocShell* openerShell;
   if (opener && (openerShell = opener->GetDocShell())) {
     nsCOMPtr<nsILoadContext> context = do_QueryInterface(openerShell);
     showInfo = ShowInfo(EmptyString(), false,
                         context->UsePrivateBrowsing(), true, false,
-                        aTabOpener->mDPI, aTabOpener->mDefaultScale);
+                        aTabOpener->mDPI, aTabOpener->mRounding,
+                        aTabOpener->mDefaultScale);
   }
 
   // Unfortunately we don't get a window unless we've shown the frame.  That's
   // pretty bogus; see bug 763602.
   newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame,
                        showInfo);
 
   for (size_t i = 0; i < frameScripts.Length(); i++) {
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3896,28 +3896,28 @@ ContentParent::RecvIsSecureURI(const uin
   nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
   if (!sss) {
     return false;
   }
   nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
   if (!ourURI) {
     return false;
   }
-  nsresult rv = sss->IsSecureURI(type, ourURI, flags, isSecureURI);
+  nsresult rv = sss->IsSecureURI(type, ourURI, flags, nullptr, isSecureURI);
   return NS_SUCCEEDED(rv);
 }
 
 bool
-ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive)
+ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive, const bool& aHSTSPriming)
 {
   nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI);
   if (!ourURI) {
     return false;
   }
-  nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive);
+  nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aHSTSPriming);
   return true;
 }
 
 bool
 ContentParent::RecvLoadURIExternal(const URIParams& uri,
                                    PBrowserParent* windowContext)
 {
   nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -784,17 +784,18 @@ private:
                                    nsTArray<uint8_t>&& aChallenge,
                                    nsTArray<uint8_t>&& aKeyHandle,
                                    nsTArray<uint8_t>* aSignature) override;
 
   virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
                                const uint32_t& aFlags, bool* aIsSecureURI) override;
 
   virtual bool RecvAccumulateMixedContentHSTS(const URIParams& aURI,
-                                              const bool& aActive) override;
+                                              const bool& aActive,
+                                              const bool& aHSTSPriming) override;
 
   virtual bool DeallocPHalParent(PHalParent*) override;
 
   virtual bool
   DeallocPHeapSnapshotTempFileHelperParent(PHeapSnapshotTempFileHelperParent*) override;
 
   virtual PIccParent* AllocPIccParent(const uint32_t& aServiceId) override;
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -96,16 +96,17 @@ union MaybeNativeKeyBinding
 struct ShowInfo
 {
   nsString name;
   bool fullscreenAllowed;
   bool isPrivate;
   bool fakeShowInfo;
   bool isTransparent;
   float dpi;
+  int32_t widgetRounding;
   double defaultScale;
 };
 
 union OptionalShmem
 {
   void_t;
   Shmem;
 };
@@ -371,16 +372,21 @@ parent:
     sync GetDPI() returns (float value);
 
     /**
      * Gets the default scaling factor of the screen corresponding to this browser.
      */
     sync GetDefaultScale() returns (double value);
 
     /**
+     * Gets the rounding of coordinates in the widget.
+     */
+    sync GetWidgetRounding() returns (int32_t value);
+
+    /**
      * Gets maximum of touch points at current device.
      */
     sync GetMaxTouchPoints() returns (uint32_t value);
 
     /**
      * Set the native cursor.
      * @param value
      *   The widget cursor to set.
@@ -788,17 +794,17 @@ child:
      * Tell the child that the UI resolution changed for the containing
      * window.
      * To avoid some sync messages from child to parent, we also send the dpi
      * and default scale with the notification.
      * If we don't know the dpi and default scale, we just pass in a negative
      * value (-1) but in the majority of the cases this saves us from two
      * sync requests from the child to the parent.
      */
-    async UIResolutionChanged(float dpi, double scale);
+    async UIResolutionChanged(float dpi, int32_t rounding, double scale);
 
     /**
      * Tell the child that the system theme has changed, and that a repaint
      * is necessary.
      */
     async ThemeChanged(LookAndFeelInt[] lookAndFeelIntCache);
 
     /**
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -833,17 +833,17 @@ parent:
      */
     sync NSSU2FTokenSign(uint8_t[] application, uint8_t[] challenge,
                          uint8_t[] keyHandle)
         returns (uint8_t[] signature);
 
     sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
         returns (bool isSecureURI);
 
-    async AccumulateMixedContentHSTS(URIParams uri, bool active);
+    async AccumulateMixedContentHSTS(URIParams uri, bool active, bool hasHSTSPriming);
 
     sync GetLookAndFeelCache()
         returns (LookAndFeelInt[] lookAndFeelIntCache);
 
     prio(urgent) async PHal();
 
     async PHeapSnapshotTempFileHelper();
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -536,16 +536,17 @@ TabChild::TabChild(nsIContentChild* aMan
   , mTriedBrowserInit(false)
   , mOrientation(eScreenOrientation_PortraitPrimary)
   , mUpdateHitRegion(false)
   , mIgnoreKeyPressEvent(false)
   , mHasValidInnerSize(false)
   , mDestroyed(false)
   , mUniqueId(aTabId)
   , mDPI(0)
+  , mRounding(0)
   , mDefaultScale(0)
   , mIsTransparent(false)
   , mIPCOpen(false)
   , mParentIsActive(false)
   , mDidSetRealShowInfo(false)
   , mDidLoadURLInit(false)
   , mAPZChild(nullptr)
   , mLayerObserverEpoch(0)
@@ -1544,16 +1545,17 @@ TabChild::ApplyShowInfo(const ShowInfo& 
           DocShellOriginAttributes attrs(nsDocShell::Cast(docShell)->GetOriginAttributes());
           attrs.SyncAttributesWithPrivateBrowsing(true);
           nsDocShell::Cast(docShell)->SetOriginAttributes(attrs);
         }
       }
     }
   }
   mDPI = aInfo.dpi();
+  mRounding = aInfo.widgetRounding();
   mDefaultScale = aInfo.defaultScale();
   mIsTransparent = aInfo.isTransparent();
 }
 
 #ifdef MOZ_WIDGET_GONK
 void
 TabChild::MaybeRequestPreinitCamera()
 {
@@ -2938,16 +2940,32 @@ TabChild::GetDefaultScale(double* aScale
       return;
     }
 
     // Fallback to a sync call if needed.
     SendGetDefaultScale(aScale);
 }
 
 void
+TabChild::GetWidgetRounding(int32_t* aRounding)
+{
+  *aRounding = 1;
+  if (!mRemoteFrame) {
+    return;
+  }
+  if (mRounding > 0) {
+    *aRounding = mRounding;
+    return;
+  }
+
+  // Fallback to a sync call if needed.
+  SendGetWidgetRounding(aRounding);
+}
+
+void
 TabChild::GetMaxTouchPoints(uint32_t* aTouchPoints)
 {
   // Fallback to a sync call.
   SendGetMaxTouchPoints(aTouchPoints);
 }
 
 void
 TabChild::NotifyPainted()
@@ -3280,22 +3298,25 @@ TabChild::RecvRequestNotifyAfterRemotePa
   // Tell the CompositorBridgeChild that, when it gets a RemotePaintIsReady
   // message that it should forward it us so that we can bounce it to our
   // RenderFrameParent.
   compositor->RequestNotifyAfterRemotePaint(this);
   return true;
 }
 
 bool
-TabChild::RecvUIResolutionChanged(const float& aDpi, const double& aScale)
+TabChild::RecvUIResolutionChanged(const float& aDpi,
+                                  const int32_t& aRounding,
+                                  const double& aScale)
 {
   ScreenIntSize oldScreenSize = GetInnerSize();
   mDPI = 0;
+  mRounding = 0;
   mDefaultScale = 0;
-  static_cast<PuppetWidget*>(mPuppetWidget.get())->UpdateBackingScaleCache(aDpi, aScale);
+  static_cast<PuppetWidget*>(mPuppetWidget.get())->UpdateBackingScaleCache(aDpi, aRounding, aScale);
   nsCOMPtr<nsIDocument> document(GetDocument());
   nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   if (presShell) {
     RefPtr<nsPresContext> presContext = presShell->GetPresContext();
     if (presContext) {
       presContext->UIResolutionChangedSync();
     }
   }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -479,16 +479,18 @@ public:
 
   virtual PuppetWidget* WebWidget() override { return mPuppetWidget; }
 
   /** Return the DPI of the widget this TabChild draws to. */
   void GetDPI(float* aDPI);
 
   void GetDefaultScale(double *aScale);
 
+  void GetWidgetRounding(int32_t* aRounding);
+
   bool IsTransparent() const { return mIsTransparent; }
 
   void GetMaxTouchPoints(uint32_t* aTouchPoints);
 
   ScreenOrientationInternal GetOrientation() const { return mOrientation; }
 
   void SetBackgroundColor(const nscolor& aColor);
 
@@ -567,16 +569,17 @@ public:
   static inline TabChild* GetFrom(nsIDOMWindow* aWindow)
   {
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
     return GetFrom(docShell);
   }
 
   virtual bool RecvUIResolutionChanged(const float& aDpi,
+                                       const int32_t& aRounding,
                                        const double& aScale) override;
 
   virtual bool
   RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
 
   virtual bool RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
                                    nsTArray<uint32_t>&& aCharCodes,
                                    const int32_t& aModifierMask) override;
@@ -772,16 +775,17 @@ private:
   // Position of client area relative to the outer window
   LayoutDeviceIntPoint mClientOffset;
   // Position of tab, relative to parent widget (typically the window)
   LayoutDeviceIntPoint mChromeDisp;
   TabId mUniqueId;
 
   friend class ContentChild;
   float mDPI;
+  int32_t mRounding;
   double mDefaultScale;
 
   bool mIsTransparent;
 
   bool mIPCOpen;
   bool mParentIsActive;
   bool mAsyncPanZoomEnabled;
   CSSSize mUnscaledInnerSize;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -272,16 +272,17 @@ TabParent::TabParent(nsIContentParent* a
                      const TabContext& aContext,
                      uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mRect(0, 0, 0, 0)
   , mDimensions(0, 0)
   , mOrientation(0)
   , mDPI(0)
+  , mRounding(0)
   , mDefaultScale(0)
   , mUpdatedDimensions(false)
   , mSizeMode(nsSizeMode_Normal)
   , mManager(aManager)
   , mDocShellIsActive(false)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mIsDetached(true)
@@ -1025,17 +1026,18 @@ TabParent::UIResolutionChanged()
     // TryCacheDPIAndScale()'s cache is keyed off of
     // mDPI being greater than 0, so this invalidates it.
     mDPI = -1;
     TryCacheDPIAndScale();
     // If mDPI was set to -1 to invalidate it and then TryCacheDPIAndScale
     // fails to cache the values, then mDefaultScale.scale might be invalid.
     // We don't want to send that value to content. Just send -1 for it too in
     // that case.
-    Unused << SendUIResolutionChanged(mDPI, mDPI < 0 ? -1.0 : mDefaultScale.scale);
+    Unused << SendUIResolutionChanged(mDPI, mRounding,
+                                      mDPI < 0 ? -1.0 : mDefaultScale.scale);
   }
 }
 
 void
 TabParent::ThemeChanged()
 {
   if (!mIsDestroyed) {
     // The theme has changed, and any cached values we had sent down
@@ -2495,16 +2497,27 @@ TabParent::RecvGetDefaultScale(double* a
 
   MOZ_ASSERT(mDefaultScale.scale > 0,
              "Must not ask for scale before OwnerElement is received!");
   *aValue = mDefaultScale.scale;
   return true;
 }
 
 bool
+TabParent::RecvGetWidgetRounding(int32_t* aValue)
+{
+  TryCacheDPIAndScale();
+
+  MOZ_ASSERT(mRounding > 0,
+             "Must not ask for rounding before OwnerElement is received!");
+  *aValue = mRounding;
+  return true;
+}
+
+bool
 TabParent::RecvGetMaxTouchPoints(uint32_t* aTouchPoints)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     *aTouchPoints = widget->GetMaxTouchPoints();
   } else {
     *aTouchPoints = 0;
   }
@@ -2761,16 +2774,17 @@ TabParent::TryCacheDPIAndScale()
   if (mDPI > 0) {
     return;
   }
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
 
   if (widget) {
     mDPI = widget->GetDPI();
+    mRounding = widget->RoundsWidgetCoordinatesTo();
     mDefaultScale = widget->GetDefaultScale();
   }
 }
 
 already_AddRefed<nsIWidget>
 TabParent::GetWidget() const
 {
   if (!mFrameElement) {
@@ -3369,21 +3383,21 @@ TabParent::GetShowInfo()
     bool allowFullscreen =
       mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
       mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen);
     bool isPrivate = mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
     bool isTransparent =
       nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
       mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent);
     return ShowInfo(name, allowFullscreen, isPrivate, false,
-                    isTransparent, mDPI, mDefaultScale.scale);
+                    isTransparent, mDPI, mRounding, mDefaultScale.scale);
   }
 
   return ShowInfo(EmptyString(), false, false, false,
-                  false, mDPI, mDefaultScale.scale);
+                  false, mDPI, mRounding, mDefaultScale.scale);
 }
 
 void
 TabParent::AudioChannelChangeNotification(nsPIDOMWindowOuter* aWindow,
                                           AudioChannel aAudioChannel,
                                           float aVolume,
                                           bool aMuted)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -316,16 +316,18 @@ public:
                                const nsString& aDirection) override;
 
   virtual bool RecvHideTooltip() override;
 
   virtual bool RecvGetDPI(float* aValue) override;
 
   virtual bool RecvGetDefaultScale(double* aValue) override;
 
+  virtual bool RecvGetWidgetRounding(int32_t* aValue) override;
+
   virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override;
 
   virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override;
 
   virtual bool RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
 
   virtual bool RecvDispatchFocusToTopLevelWindow() override;
 
@@ -630,16 +632,17 @@ protected:
                                                     const bool& aActive) override;
 
   ContentCacheInParent mContentCache;
 
   nsIntRect mRect;
   ScreenIntSize mDimensions;
   ScreenOrientationInternal mOrientation;
   float mDPI;
+  int32_t mRounding;
   CSSToLayoutDeviceScale mDefaultScale;
   bool mUpdatedDimensions;
   nsSizeMode mSizeMode;
   LayoutDeviceIntPoint mClientOffset;
   LayoutDeviceIntPoint mChromeOffset;
 
 private:
   void DestroyInternal();
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -65,30 +65,28 @@ nsJSON::Encode(JS::Handle<JS::Value> aVa
                nsAString &aJSON)
 {
   // This function should only be called from JS.
   nsresult rv = WarnDeprecatedMethod(EncodeWarning);
   if (NS_FAILED(rv))
     return rv;
 
   if (aArgc == 0) {
-    aJSON.Truncate();
     aJSON.SetIsVoid(true);
     return NS_OK;
   }
 
   nsJSONWriter writer;
   rv = EncodeInternal(cx, aValue, &writer);
 
   // FIXME: bug 408838. Get exception types sorted out
   if (NS_SUCCEEDED(rv) || rv == NS_ERROR_INVALID_ARG) {
     rv = NS_OK;
     // if we didn't consume anything, it's not JSON, so return null
     if (!writer.DidWrite()) {
-      aJSON.Truncate();
       aJSON.SetIsVoid(true);
     } else {
       writer.FlushBuffer();
       aJSON.Append(writer.mOutputString);
     }
   }
 
   return rv;
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -360,17 +360,18 @@ AudioStream::Init(uint32_t aNumChannels,
 nsresult
 AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
                        TimeStamp aStartTime, bool aIsFirst)
 {
   MOZ_ASSERT(aContext);
 
   cubeb_stream* stream = nullptr;
   /* Convert from milliseconds to frames. */
-  uint32_t latency_frames = CubebUtils::GetCubebLatency() * aParams.rate / 1000;
+  uint32_t latency_frames =
+    CubebUtils::GetCubebPlaybackLatencyInMilliseconds() * aParams.rate / 1000;
   if (cubeb_stream_init(aContext, &stream, "AudioStream",
                         nullptr, nullptr, nullptr, &aParams,
                         latency_frames,
                         DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
     mCubebStream.reset(stream);
     CubebUtils::ReportCubebBackendUsed();
   } else {
     NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get());
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -14,33 +14,36 @@
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "nsThreadUtils.h"
 #include "CubebUtils.h"
 #include "nsAutoRef.h"
 #include "prdtoa.h"
 
 #define PREF_VOLUME_SCALE "media.volume_scale"
-#define PREF_CUBEB_LATENCY "media.cubeb_latency_ms"
+#define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
+#define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
 
 namespace mozilla {
 
 namespace {
 
 // This mutex protects the variables below.
 StaticMutex sMutex;
 enum class CubebState {
   Uninitialized = 0,
   Initialized,
   Shutdown
 } sCubebState = CubebState::Uninitialized;
 cubeb* sCubebContext;
 double sVolumeScale;
-uint32_t sCubebLatency;
-bool sCubebLatencyPrefSet;
+uint32_t sCubebPlaybackLatencyInMilliseconds;
+uint32_t sCubebMSGLatencyInFrames;
+bool sCubebPlaybackLatencyPrefSet;
+bool sCubebMSGLatencyPrefSet;
 bool sAudioStreamInitEverSucceeded = false;
 StaticAutoPtr<char> sBrandName;
 
 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
 
 const char* AUDIOSTREAM_BACKEND_ID_STR[] = {
   "jack",
   "pulse",
@@ -76,38 +79,49 @@ const int CUBEB_BACKEND_UNKNOWN = CUBEB_
 // visible on the querying thread/CPU.
 uint32_t sPreferredSampleRate;
 
 } // namespace
 
 extern LazyLogModule gAudioStreamLog;
 
 static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
+// Consevative default that can work on all platforms.
+static const uint32_t CUBEB_NORMAL_LATENCY_FRAMES = 1024;
 
 namespace CubebUtils {
 
 void PrefChanged(const char* aPref, void* aClosure)
 {
   if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
     nsAdoptingString value = Preferences::GetString(aPref);
     StaticMutexAutoLock lock(sMutex);
     if (value.IsEmpty()) {
       sVolumeScale = 1.0;
     } else {
       NS_ConvertUTF16toUTF8 utf8(value);
       sVolumeScale = std::max<double>(0, PR_strtod(utf8.get(), nullptr));
     }
-  } else if (strcmp(aPref, PREF_CUBEB_LATENCY) == 0) {
+  } else if (strcmp(aPref, PREF_CUBEB_LATENCY_PLAYBACK) == 0) {
     // Arbitrary default stream latency of 100ms.  The higher this
     // value, the longer stream volume changes will take to become
     // audible.
-    sCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
+    sCubebPlaybackLatencyPrefSet = Preferences::HasUserValue(aPref);
     uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
     StaticMutexAutoLock lock(sMutex);
-    sCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
+    sCubebPlaybackLatencyInMilliseconds = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
+  } else if (strcmp(aPref, PREF_CUBEB_LATENCY_MSG) == 0) {
+    sCubebMSGLatencyPrefSet = Preferences::HasUserValue(aPref);
+    uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_FRAMES);
+    StaticMutexAutoLock lock(sMutex);
+    // 128 is the block size for the Web Audio API, which limits how low the
+    // latency can be here.
+    // We don't want to limit the upper limit too much, so that people can
+    // experiment.
+    sCubebMSGLatencyInFrames = std::min<uint32_t>(std::max<uint32_t>(value, 128), 1e6);
   }
 }
 
 bool GetFirstStream()
 {
   static bool sFirstStream = true;
 
   StaticMutexAutoLock lock(sMutex);
@@ -233,43 +247,62 @@ void ReportCubebStreamInitFailure(bool a
     // failures to open multiple streams in a process over time.
     return;
   }
   Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED,
                         aIsFirst ? CUBEB_BACKEND_INIT_FAILURE_FIRST
                                  : CUBEB_BACKEND_INIT_FAILURE_OTHER);
 }
 
-uint32_t GetCubebLatency()
+uint32_t GetCubebPlaybackLatencyInMilliseconds()
+{
+  StaticMutexAutoLock lock(sMutex);
+  return sCubebPlaybackLatencyInMilliseconds;
+}
+
+bool CubebPlaybackLatencyPrefSet()
 {
   StaticMutexAutoLock lock(sMutex);
-  return sCubebLatency;
+  return sCubebPlaybackLatencyPrefSet;
+}
+
+bool CubebMSGLatencyPrefSet()
+{
+  StaticMutexAutoLock lock(sMutex);
+  return sCubebMSGLatencyPrefSet;
 }
 
-bool CubebLatencyPrefSet()
+Maybe<uint32_t> GetCubebMSGLatencyInFrames()
 {
   StaticMutexAutoLock lock(sMutex);
-  return sCubebLatencyPrefSet;
+  if (!sCubebMSGLatencyPrefSet) {
+    return Maybe<uint32_t>();
+  }
+  MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
+  return Some(sCubebMSGLatencyInFrames);
 }
 
 void InitLibrary()
 {
   PrefChanged(PREF_VOLUME_SCALE, nullptr);
   Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
-  PrefChanged(PREF_CUBEB_LATENCY, nullptr);
-  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
+  PrefChanged(PREF_CUBEB_LATENCY_PLAYBACK, nullptr);
+  PrefChanged(PREF_CUBEB_LATENCY_MSG, nullptr);
+  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
+  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
 #ifndef MOZ_WIDGET_ANDROID
   NS_DispatchToMainThread(NS_NewRunnableFunction(&InitBrandName));
 #endif
 }
 
 void ShutdownLibrary()
 {
   Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
-  Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
+  Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
+  Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
 
   StaticMutexAutoLock lock(sMutex);
   if (sCubebContext) {
     cubeb_destroy(sCubebContext);
     sCubebContext = nullptr;
   }
   sBrandName = nullptr;
   // This will ensure we don't try to re-create a context.
--- a/dom/media/CubebUtils.h
+++ b/dom/media/CubebUtils.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(CubebUtils_h_)
 #define CubebUtils_h_
 
 #include "cubeb/cubeb.h"
 #include "mozilla/dom/AudioChannelBinding.h"
+#include "mozilla/Maybe.h"
 
 namespace mozilla {
 namespace CubebUtils {
 
 typedef cubeb_devid AudioDeviceID;
 
 // Initialize Audio Library. Some Audio backends require initializing the
 // library before using it.
@@ -31,17 +32,18 @@ uint32_t PreferredSampleRate();
 
 void PrefChanged(const char* aPref, void* aClosure);
 double GetVolumeScale();
 bool GetFirstStream();
 cubeb* GetCubebContext();
 cubeb* GetCubebContextUnlocked();
 void ReportCubebStreamInitFailure(bool aIsFirstStream);
 void ReportCubebBackendUsed();
-uint32_t GetCubebLatency();
+uint32_t GetCubebPlaybackLatencyInMilliseconds();
+Maybe<uint32_t> GetCubebMSGLatencyInFrames();
 bool CubebLatencyPrefSet();
 #if defined(__ANDROID__) && defined(MOZ_B2G)
 cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel);
 #endif
 void GetCurrentBackend(nsAString& aBackend);
 
 } // namespace CubebUtils
 } // namespace mozilla
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -623,19 +623,24 @@ AudioCallbackDriver::Init()
 
   output.channels = mGraphImpl->AudioChannelCount();
   if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
     output.format = CUBEB_SAMPLE_S16NE;
   } else {
     output.format = CUBEB_SAMPLE_FLOAT32NE;
   }
 
-  if (cubeb_get_min_latency(cubebContext, output, &latency_frames) != CUBEB_OK) {
-    NS_WARNING("Could not get minimal latency from cubeb.");
-    return;
+  Maybe<uint32_t> latencyPref = CubebUtils::GetCubebMSGLatencyInFrames();
+  if (latencyPref) {
+    latency_frames = latencyPref.value();
+  } else {
+    if (cubeb_get_min_latency(cubebContext, output, &latency_frames) != CUBEB_OK) {
+      NS_WARNING("Could not get minimal latency from cubeb.");
+      return;
+    }
   }
 
   input = output;
   input.channels = mInputChannels; // change to support optional stereo capture
 
   cubeb_stream* stream = nullptr;
   CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
   // We have to translate the deviceID values to cubeb devid's since those can be
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -67,17 +67,16 @@ MediaFormatReader::MediaFormatReader(Abs
   , mVideo(this, MediaData::VIDEO_DATA,
            Preferences::GetUint("media.video-max-decode-error", 2))
   , mDemuxer(aDemuxer)
   , mDemuxerInitDone(false)
   , mLastReportedNumDecodedFrames(0)
   , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
   , mLayersBackendType(aLayersBackend)
   , mInitDone(false)
-  , mIsEncrypted(false)
   , mTrackDemuxersMayBlock(false)
   , mDemuxOnly(false)
   , mSeekScheduled(false)
   , mVideoFrameContainer(aVideoFrameContainer)
 {
   MOZ_ASSERT(aDemuxer);
   MOZ_COUNT_CTOR(MediaFormatReader);
 }
@@ -332,19 +331,16 @@ MediaFormatReader::OnDemuxerInitDone(nsr
       mTrackDemuxersMayBlock |= mAudio.mTrackDemuxer->GetSamplesMayBlock();
     } else {
       mAudio.mTrackDemuxer->BreakCycles();
       mAudio.mTrackDemuxer = nullptr;
     }
   }
 
   UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto();
-
-  mIsEncrypted = crypto && crypto->IsEncrypted();
-
   if (mDecoder && crypto && crypto->IsEncrypted()) {
 #ifdef MOZ_EME
     // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
     for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
       NS_DispatchToMainThread(
         new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType));
     }
 #endif // MOZ_EME
@@ -370,16 +366,23 @@ MediaFormatReader::OnDemuxerInitDone(nsr
 
   mInitDone = true;
   RefPtr<MetadataHolder> metadata = new MetadataHolder();
   metadata->mInfo = mInfo;
   metadata->mTags = tags->Count() ? tags.release() : nullptr;
   mMetadataPromise.Resolve(metadata, __func__);
 }
 
+bool
+MediaFormatReader::IsEncrypted() const
+{
+  return (HasAudio() && mInfo.mAudio.mCrypto.mValid) ||
+         (HasVideo() && mInfo.mVideo.mCrypto.mValid);
+}
+
 void
 MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError)
 {
   mDemuxerInitRequest.Complete();
   mMetadataPromise.Reject(aError, __func__);
 }
 
 MediaResult
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -100,18 +100,18 @@ public:
   // Returns a string describing the state of the decoder data.
   // Used for debugging purposes.
   void GetMozDebugReaderData(nsAString& aString);
 
   void SetVideoBlankDecode(bool aIsBlankDecode) override;
 
 private:
 
-  bool HasVideo() { return mVideo.mTrackDemuxer; }
-  bool HasAudio() { return mAudio.mTrackDemuxer; }
+  bool HasVideo() const { return mVideo.mTrackDemuxer; }
+  bool HasAudio() const { return mAudio.mTrackDemuxer; }
 
   bool IsWaitingOnCDMResource();
 
   bool InitDemuxer();
   // Notify the demuxer that new data has been received.
   // The next queued task calling GetBuffered() is guaranteed to have up to date
   // buffered ranges.
   void NotifyDemuxer();
@@ -523,21 +523,17 @@ private:
   static const int64_t sNoPreviousDecodedKeyframe = INT64_MAX;
 
   layers::LayersBackend mLayersBackendType;
 
   // Metadata objects
   // True if we've read the streams' metadata.
   bool mInitDone;
   MozPromiseHolder<MetadataPromise> mMetadataPromise;
-  bool IsEncrypted()
-  {
-    return mIsEncrypted;
-  }
-  bool mIsEncrypted;
+  bool IsEncrypted() const;
 
   // Set to true if any of our track buffers may be blocking.
   bool mTrackDemuxersMayBlock;
 
   // Set the demuxed-only flag.
   Atomic<bool> mDemuxOnly;
 
   // Seeking objects.
--- a/dom/media/eme/EMEUtils.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -149,9 +149,22 @@ KeySystemToGMPName(const nsAString& aKey
 }
 
 bool
 IsClearkeyKeySystem(const nsAString& aKeySystem)
 {
   return !CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem);
 }
 
+CDMType
+ToCDMTypeTelemetryEnum(const nsString& aKeySystem)
+{
+  if (!CompareUTF8toUTF16(kEMEKeySystemWidevine, aKeySystem)) {
+    return CDMType::eWidevine;
+  } else if (!CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem)) {
+    return CDMType::eClearKey;
+  } else if (!CompareUTF8toUTF16(kEMEKeySystemPrimetime, aKeySystem)) {
+    return CDMType::ePrimetime;
+  }
+  return CDMType::eUnknown;
+}
+
 } // namespace mozilla
--- a/dom/media/eme/EMEUtils.h
+++ b/dom/media/eme/EMEUtils.h
@@ -101,11 +101,21 @@ ArrayData
 GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView);
 
 nsString
 KeySystemToGMPName(const nsAString& aKeySystem);
 
 bool
 IsClearkeyKeySystem(const nsAString& aKeySystem);
 
+enum CDMType {
+  eClearKey = 0,
+  ePrimetime = 1,
+  eWidevine = 2,
+  eUnknown = 3
+};
+
+CDMType
+ToCDMTypeTelemetryEnum(const nsString& aKeySystem);
+
 } // namespace mozilla
 
 #endif // EME_LOG_H_
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -194,16 +194,19 @@ MediaKeySession::GenerateRequest(const n
   if (data.IsEmpty()) {
     promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR,
       NS_LITERAL_CSTRING("Empty initData passed to MediaKeySession.generateRequest()"));
     EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initData",
       this, NS_ConvertUTF16toUTF8(mSessionId).get());
     return promise.forget();
   }
 
+  Telemetry::Accumulate(Telemetry::VIDEO_CDM_GENERATE_REQUEST_CALLED,
+                        ToCDMTypeTelemetryEnum(mKeySystem));
+
   // Convert initData to base64 for easier logging.
   // Note: CreateSession() Move()s the data out of the array, so we have
   // to copy it here.
   nsAutoCString base64InitData(ToBase64(data));
   PromiseId pid = mKeys->StorePromise(promise);
   mKeys->GetCDMProxy()->CreateSession(Token(),
                                       mSessionType,
                                       pid,
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -396,36 +396,16 @@ MediaKeys::Init(ErrorResult& aRv)
                NS_ConvertUTF8toUTF16(origin),
                NS_ConvertUTF8toUTF16(topLevelOrigin),
                KeySystemToGMPName(mKeySystem),
                inPrivateBrowsing);
 
   return promise.forget();
 }
 
-enum CDMCreatedType {
-  eClearKey = 0,
-  ePrimetime = 1,
-  eWidevine = 2,
-  eUnknown = 3
-};
-
-static CDMCreatedType
-ToCDMCreatedTelemetryEnum(const nsString& aKeySystem)
-{
-  if (!CompareUTF8toUTF16(kEMEKeySystemWidevine, aKeySystem)) {
-    return CDMCreatedType::eWidevine;
-  } else if (!CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem)) {
-    return CDMCreatedType::eClearKey;
-  } else if (!CompareUTF8toUTF16(kEMEKeySystemPrimetime, aKeySystem)) {
-    return CDMCreatedType::ePrimetime;
-  }
-  return CDMCreatedType::eUnknown;
-}
-
 void
 MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t aPluginId)
 {
   RefPtr<DetailedPromise> promise(RetrievePromise(aId));
   if (!promise) {
     return;
   }
   mNodeId = aNodeId;
@@ -435,17 +415,17 @@ MediaKeys::OnCDMCreated(PromiseId aId, c
   if (mCreatePromiseId == aId) {
     Release();
   }
 
   MediaKeySystemAccess::NotifyObservers(mParent,
                                         mKeySystem,
                                         MediaKeySystemStatus::Cdm_created);
 
-  Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMCreatedTelemetryEnum(mKeySystem));
+  Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMTypeTelemetryEnum(mKeySystem));
 }
 
 already_AddRefed<MediaKeySession>
 MediaKeys::CreateSession(JSContext* aCx,
                          MediaKeySessionType aSessionType,
                          ErrorResult& aRv)
 {
   if (!mProxy) {
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1070,17 +1070,16 @@ TrackBuffersManager::OnDemuxerInitDone(n
         new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData,
                                    crypto->mInitDatas[i].mType));
     }
 #endif // MOZ_EME
     info.mCrypto = *crypto;
     // We clear our crypto init data array, so the MediaFormatReader will
     // not emit an encrypted event for the same init data again.
     info.mCrypto.mInitDatas.Clear();
-    mEncrypted = true;
   }
 
   {
     MonitorAutoLock mon(mMonitor);
     mInfo = info;
   }
 
   // We now have a valid init data ; we can store it for later use.
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -235,17 +235,16 @@ private:
   // Length already processed in current media segment.
   uint32_t mProcessedInput;
   Maybe<media::TimeUnit> mLastParsedEndTime;
 
   void OnDemuxerInitDone(nsresult);
   void OnDemuxerInitFailed(const MediaResult& aFailure);
   void OnDemuxerResetDone(nsresult);
   MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
-  bool mEncrypted;
 
   void OnDemuxFailed(TrackType aTrack, const MediaResult& aError);
   void DoDemuxVideo();
   void OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
   void OnVideoDemuxFailed(const MediaResult& aError)
   {
     mVideoTracks.mDemuxRequest.Complete();
     OnDemuxFailed(TrackType::kVideoTrack, aError);
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -24,43 +24,16 @@
     mozilla::LogLevel::Debug, ("AndroidDecoderModule(%p)::%s: " arg, \
       this, __func__, ##__VA_ARGS__))
 
 using namespace mozilla;
 using namespace mozilla::gl;
 using namespace mozilla::java::sdk;
 using media::TimeUnit;
 
-namespace {
-  template<class T>
-  mozilla::jni::ByteArray::LocalRef
-  CreateAndInitJByteArray(const T& data, jsize length)
-  {
-    JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-    jbyteArray result = jenv->NewByteArray(length);
-    MOZ_CATCH_JNI_EXCEPTION(jenv);
-    jenv->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte*>(const_cast<T>(data)));
-    MOZ_CATCH_JNI_EXCEPTION(jenv);
-    return mozilla::jni::ByteArray::LocalRef::Adopt(jenv, result);
-  }
-
-  template<class T>
-  mozilla::jni::IntArray::LocalRef
-  CreateAndInitJIntArray(const T& data, jsize length)
-  {
-    JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-    jintArray result = jenv->NewIntArray(length);
-    MOZ_CATCH_JNI_EXCEPTION(jenv);
-    jenv->SetIntArrayRegion(result, 0, length, reinterpret_cast<const jint*>(const_cast<T>(data)));
-    MOZ_CATCH_JNI_EXCEPTION(jenv);
-    return mozilla::jni::IntArray::LocalRef::Adopt(jenv, result);
-  }
-}
-
-
 namespace mozilla {
 
 mozilla::LazyLogModule sAndroidDecoderModuleLog("AndroidDecoderModule");
 
 static const char*
 TranslateMimeType(const nsACString& aMimeType)
 {
   if (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8)) {
@@ -120,21 +93,27 @@ GetCryptoInfoFromSample(const MediaRawDa
   auto tempIV(cryptoObj.mIV);
   auto tempIVLength = tempIV.Length();
   MOZ_ASSERT(tempIVLength <= kExpectedIVLength);
   for (size_t i = tempIVLength; i < kExpectedIVLength; i++) {
     // Padding with 0
     tempIV.AppendElement(0);
   }
 
-  auto numBytesOfPlainData = CreateAndInitJIntArray(&plainSizes[0], plainSizes.Length());
-  auto numBytesOfEncryptedData = CreateAndInitJIntArray(&cryptoObj.mEncryptedSizes[0],
-                                                        cryptoObj.mEncryptedSizes.Length());
-  auto iv = CreateAndInitJByteArray(&tempIV[0], tempIV.Length());
-  auto keyId = CreateAndInitJByteArray(&cryptoObj.mKeyId[0], cryptoObj.mKeyId.Length());
+  auto numBytesOfPlainData = mozilla::jni::IntArray::New(
+                              reinterpret_cast<int32_t*>(&plainSizes[0]),
+                              plainSizes.Length());
+
+  auto numBytesOfEncryptedData =
+    mozilla::jni::IntArray::New(reinterpret_cast<const int32_t*>(&cryptoObj.mEncryptedSizes[0]),
+                                cryptoObj.mEncryptedSizes.Length());
+  auto iv = mozilla::jni::ByteArray::New(reinterpret_cast<int8_t*>(&tempIV[0]),
+                                        tempIV.Length());
+  auto keyId = mozilla::jni::ByteArray::New(reinterpret_cast<const int8_t*>(&cryptoObj.mKeyId[0]),
+                                            cryptoObj.mKeyId.Length());
   cryptoInfo->Set(numSubSamples,
                   numBytesOfPlainData,
                   numBytesOfEncryptedData,
                   keyId,
                   iv,
                   MediaCodec::CRYPTO_MODE_AES_CTR);
 
   return cryptoInfo;
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
@@ -47,34 +47,34 @@ public:
     : ITextureClientAllocationHelper(gfx::SurfaceFormat::UNKNOWN,
                                      aSize,
                                      BackendSelector::Content,
                                      TextureFlags::DEALLOCATE_CLIENT,
                                      ALLOC_DISALLOW_BUFFERTEXTURECLIENT)
     , mGrallocFormat(aGrallocFormat)
   {}
 
-  already_AddRefed<TextureClient> Allocate(TextureForwarder* aAllocator) override
+  already_AddRefed<TextureClient> Allocate(KnowsCompositor* aAllocator) override
   {
     uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN |
                      android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                      android::GraphicBuffer::USAGE_HW_TEXTURE;
 
     GrallocTextureData* texData = GrallocTextureData::Create(mSize, mGrallocFormat,
                                                              gfx::BackendType::NONE,
-                                                             usage, aAllocator);
+                                                             usage, aAllocator->GetTextureForwarder());
     if (!texData) {
       return nullptr;
     }
     sp<GraphicBuffer> graphicBuffer = texData->GetGraphicBuffer();
     if (!graphicBuffer.get()) {
       return nullptr;
     }
     RefPtr<TextureClient> textureClient =
-      TextureClient::CreateWithData(texData, TextureFlags::DEALLOCATE_CLIENT, aAllocator);
+      TextureClient::CreateWithData(texData, TextureFlags::DEALLOCATE_CLIENT, aAllocator->GetTextureForwarder());
     return textureClient.forget();
   }
 
   bool IsCompatible(TextureClient* aTextureClient) override
   {
     if (!aTextureClient) {
       return false;
     }
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -925,8 +925,9 @@ tags = webvtt
 [test_background_video_suspend.html]
 tags = suspend
 [test_background_video_suspend_ends.html]
 tags = suspend
 [test_background_video_no_suspend_short_vid.html]
 tags = suspend
 [test_background_video_no_suspend_disabled.html]
 tags = suspend
+[test_temporary_file_blob_video_plays.html]
copy from dom/media/test/test_mediarecorder_record_canvas_captureStream.html
copy to dom/media/test/test_temporary_file_blob_video_plays.html
--- a/dom/media/test/test_mediarecorder_record_canvas_captureStream.html
+++ b/dom/media/test/test_temporary_file_blob_video_plays.html
@@ -60,14 +60,14 @@ function startTest() {
       .then(SimpleTest.finish);
   };
 
   mediaRecorder.start();
   is(mediaRecorder.state, "recording", "Media recorder should be recording");
 }
 
 SimpleTest.waitForExplicitFinish();
-startTest();
+SpecialPowers.pushPrefEnv({set:[["media.recorder.max_memory", 1]]}, startTest);
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -248,19 +248,17 @@ inline bool IsDrawingModelDirect(int16_t
 }
 
 // in NPAPI, char* == nullptr is sometimes meaningful.  the following is
 // helper code for dealing with nullable nsCString's
 inline nsCString
 NullableString(const char* aString)
 {
     if (!aString) {
-        nsCString str;
-        str.SetIsVoid(true);
-        return str;
+        return NullCString();
     }
     return nsCString(aString);
 }
 
 inline const char*
 NullableStringGet(const nsCString& str)
 {
   if (str.IsVoid())
--- a/dom/security/moz.build
+++ b/dom/security/moz.build
@@ -15,16 +15,17 @@ EXPORTS.mozilla.dom += [
     'nsMixedContentBlocker.h',
     'SRICheck.h',
     'SRILogHelper.h',
     'SRIMetadata.h',
 ]
 
 EXPORTS += [
     'nsContentSecurityManager.h',
+    'nsMixedContentBlocker.h',
 ]
 
 UNIFIED_SOURCES += [
     'ContentVerifier.cpp',
     'nsContentSecurityManager.cpp',
     'nsCSPContext.cpp',
     'nsCSPParser.cpp',
     'nsCSPService.cpp',
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -1,16 +1,18 @@
 #include "nsContentSecurityManager.h"
 #include "nsIChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIStreamListener.h"
 #include "nsILoadInfo.h"
 #include "nsContentUtils.h"
 #include "nsCORSListenerProxy.h"
 #include "nsIStreamListener.h"
+#include "nsIDocument.h"
+#include "nsMixedContentBlocker.h"
 
 #include "mozilla/dom/Element.h"
 
 NS_IMPL_ISUPPORTS(nsContentSecurityManager,
                   nsIContentSecurityManager,
                   nsIChannelEventSink)
 
 static nsresult
@@ -376,16 +378,24 @@ DoContentSecurityChecks(nsIChannel* aCha
                                  nullptr,        //extra,
                                  &shouldLoad,
                                  nsContentUtils::GetContentPolicy(),
                                  nsContentUtils::GetSecurityManager());
   NS_ENSURE_SUCCESS(rv, rv);
   if (NS_CP_REJECTED(shouldLoad)) {
     return NS_ERROR_CONTENT_BLOCKED;
   }
+
+  if (nsMixedContentBlocker::sSendHSTSPriming) {
+    rv = nsMixedContentBlocker::MarkLoadInfoForPriming(uri,
+                                                       requestingContext,
+                                                       aLoadInfo);
+    return rv;
+  }
+
   return NS_OK;
 }
 
 /*
  * Based on the security flags provided in the loadInfo of the channel,
  * doContentSecurityCheck() performs the following content security checks
  * before opening the channel:
  *
@@ -484,17 +494,17 @@ nsContentSecurityManager::AsyncOnChannel
       nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
       nsIScriptSecurityManager::DISALLOW_SCRIPT;
   nsresult rv = nsContentUtils::GetSecurityManager()->
     CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
   if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
       rv = nsContentUtils::GetSecurityManager()->
         CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
   }
-  NS_ENSURE_SUCCESS(rv, rv);  
+  NS_ENSURE_SUCCESS(rv, rv);
 
   aCb->OnRedirectVerifyCallback(NS_OK);
   return NS_OK;
 }
 
 static void
 AddLoadFlags(nsIRequest *aRequest, nsLoadFlags aNewFlags)
 {
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -49,16 +49,21 @@ enum nsMixedContentBlockerMessageType {
 
 // Is mixed script blocking (fonts, plugin content, scripts, stylesheets,
 // iframes, websockets, XHR) enabled?
 bool nsMixedContentBlocker::sBlockMixedScript = false;
 
 // Is mixed display content blocking (images, audio, video, <a ping>) enabled?
 bool nsMixedContentBlocker::sBlockMixedDisplay = false;
 
+// Do we move HSTS before mixed-content
+bool nsMixedContentBlocker::sUseHSTS = false;
+// Do we send an HSTS priming request
+bool nsMixedContentBlocker::sSendHSTSPriming = false;
+
 // Fired at the document that attempted to load mixed content.  The UI could
 // handle this event, for example, by displaying an info bar that offers the
 // choice to reload the page with mixed content permitted.
 class nsMixedContentEvent : public Runnable
 {
 public:
   nsMixedContentEvent(nsISupports *aContext, MixedContentTypes aType, bool aRootHasSecureConnection)
     : mContext(aContext), mType(aType), mRootHasSecureConnection(aRootHasSecureConnection)
@@ -190,16 +195,24 @@ nsMixedContentBlocker::nsMixedContentBlo
 {
   // Cache the pref for mixed script blocking
   Preferences::AddBoolVarCache(&sBlockMixedScript,
                                "security.mixed_content.block_active_content");
 
   // Cache the pref for mixed display blocking
   Preferences::AddBoolVarCache(&sBlockMixedDisplay,
                                "security.mixed_content.block_display_content");
+
+  // Cache the pref for HSTS
+  Preferences::AddBoolVarCache(&sUseHSTS,
+                               "security.mixed_content.use_hsts");
+
+  // Cache the pref for sending HSTS priming
+  Preferences::AddBoolVarCache(&sSendHSTSPriming,
+                               "security.mixed_content.send_hsts_priming");
 }
 
 nsMixedContentBlocker::~nsMixedContentBlocker()
 {
 }
 
 NS_IMPL_ISUPPORTS(nsMixedContentBlocker, nsIContentPolicy, nsIChannelEventSink)
 
@@ -233,18 +246,16 @@ LogMixedContentMessage(MixedContentTypes
 
   NS_ConvertUTF8toUTF16 locationSpecUTF16(aContentLocation->GetSpecOrDefault());
   const char16_t* strings[] = { locationSpecUTF16.get() };
   nsContentUtils::ReportToConsole(severityFlag, messageCategory, aRootDoc,
                                   nsContentUtils::eSECURITY_PROPERTIES,
                                   messageLookupKey.get(), strings, ArrayLength(strings));
 }
 
-
-
 /* nsIChannelEventSink implementation
  * This code is called when a request is redirected.
  * We check the channel associated with the new uri is allowed to load
  * in the current context
  */
 NS_IMETHODIMP
 nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
                                               nsIChannel* aNewChannel,
@@ -304,27 +315,45 @@ nsMixedContentBlocker::AsyncOnChannelRed
     if (nsContentUtils::IsSystemPrincipal(requestingPrincipal)) {
       return NS_OK;
     }
     // We set the requestingLocation from the RequestingPrincipal.
     rv = requestingPrincipal->GetURI(getter_AddRefs(requestingLocation));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  nsCOMPtr<nsISupports> requestingContext = loadInfo->LoadingNode();
+
   int16_t decision = REJECT_REQUEST;
   rv = ShouldLoad(contentPolicyType,
                   newUri,
                   requestingLocation,
-                  loadInfo->LoadingNode(),
+                  requestingContext,
                   EmptyCString(),       // aMimeGuess
                   nullptr,              // aExtra
                   requestingPrincipal,
                   &decision);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (nsMixedContentBlocker::sSendHSTSPriming) {
+    // The LoadInfo passed in is for the original channel, HSTS priming needs to
+    // be set on the new channel, if required. If the redirect changes
+    // http->https, or vice-versa, the need for priming may change.
+    nsCOMPtr<nsILoadInfo> newLoadInfo;
+    rv = aNewChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = nsMixedContentBlocker::MarkLoadInfoForPriming(newUri,
+                                                       requestingContext,
+                                                       newLoadInfo);
+    if (NS_FAILED(rv)) {
+      decision = REJECT_REQUEST;
+      newLoadInfo->ClearHSTSPriming();
+    }
+  }
+
   // If the channel is about to load mixed content, abort the channel
   if (!NS_CP_ACCEPTED(decision)) {
     autoCallback.DontCallback();
     return NS_BINDING_FAILED;
   }
 
   return NS_OK;
 }
@@ -458,17 +487,16 @@ nsMixedContentBlocker::ShouldLoad(bool a
       return NS_OK;
     // Creating insecure websocket connections in a secure page is blocked already
     // in the websocket constructor. We don't need to check the blocking here
     // and we don't want to un-block
     case TYPE_WEBSOCKET:
       *aDecision = ACCEPT;
       return NS_OK;
 
-
     // Static display content is considered moderate risk for mixed content so
     // these will be blocked according to the mixed display preference
     case TYPE_IMAGE:
     case TYPE_MEDIA:
     case TYPE_OBJECT_SUBREQUEST:
       classification = eMixedDisplay;
       break;
 
@@ -492,17 +520,16 @@ nsMixedContentBlocker::ShouldLoad(bool a
     case TYPE_XSLT:
     case TYPE_OTHER:
       break;
 
 
     // This content policy works as a whitelist.
     default:
       MOZ_ASSERT(false, "Mixed content of unknown type");
-      break;
   }
 
   // Make sure to get the URI the load started with. No need to check
   // outer schemes because all the wrapping pseudo protocols inherit the
   // security properties of the actual network request represented
   // by the innerMost URL.
   nsCOMPtr<nsIURI> innerContentLocation = NS_GetInnermostURI(aContentLocation);
   if (!innerContentLocation) {
@@ -672,43 +699,45 @@ nsMixedContentBlocker::ShouldLoad(bool a
   // http: and ws: (for websockets). Websockets are not subject to mixed content
   // blocking since insecure websockets are not allowed within secure pages. Hence,
   // we only have to check against http: here. Skip mixed content blocking if the
   // subresource load uses http: and the CSP directive 'upgrade-insecure-requests'
   // is present on the page.
   bool isHttpScheme = false;
   rv = innerContentLocation->SchemeIs("http", &isHttpScheme);
   NS_ENSURE_SUCCESS(rv, rv);
-  if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests(isPreload)) {
+  nsIDocument* document = docShell->GetDocument();
+  MOZ_ASSERT(document, "Expected a document");
+  if (isHttpScheme && document->GetUpgradeInsecureRequests(isPreload)) {
     *aDecision = ACCEPT;
     return NS_OK;
   }
 
   // The page might have set the CSP directive 'block-all-mixed-content' which
   // should block not only active mixed content loads but in fact all mixed content
   // loads, see https://www.w3.org/TR/mixed-content/#strict-checking
   // Block all non secure loads in case the CSP directive is present. Please note
   // that at this point we already know, based on |schemeSecure| that the load is
   // not secure, so we can bail out early at this point.
-  if (docShell->GetDocument()->GetBlockAllMixedContent(isPreload)) {
+  if (document->GetBlockAllMixedContent(isPreload)) {
     // log a message to the console before returning.
     nsAutoCString spec;
     rv = aContentLocation->GetSpec(spec);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ConvertUTF8toUTF16 reportSpec(spec);
 
     const char16_t* params[] = { reportSpec.get()};
     CSP_LogLocalizedStr(u"blockAllMixedContent",
                         params, ArrayLength(params),
                         EmptyString(), // aSourceFile
                         EmptyString(), // aScriptSample
                         0, // aLineNumber
                         0, // aColumnNumber
                         nsIScriptError::errorFlag, "CSP",
-                        docShell->GetDocument()->InnerWindowID());
+                        document->InnerWindowID());
     *aDecision = REJECT_REQUEST;
     return NS_OK;
   }
 
   // Determine if the rootDoc is https and if the user decided to allow Mixed Content
   bool rootHasSecureConnection = false;
   bool allowMixedContent = false;
   bool isRootDocShell = false;
@@ -791,39 +820,67 @@ nsMixedContentBlocker::ShouldLoad(bool a
   // If there is no securityUI, document doesn't have a security state.
   // Allow load and return early.
   if (!securityUI) {
     *aDecision = nsIContentPolicy::ACCEPT;
     return NS_OK;
   }
   nsresult stateRV = securityUI->GetState(&state);
 
+  bool doHSTSPriming = false;
+  if (isHttpScheme) {
+    bool hsts = false;
+    bool cached = false;
+    nsCOMPtr<nsISiteSecurityService> sss =
+      do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aContentLocation,
+        0, &cached, &hsts);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (hsts && sUseHSTS) {
+      // assume we will be upgraded later
+      *aDecision = ACCEPT;
+      return NS_OK;
+    }
+
+    // Send a priming request if the result is not already cached and priming
+    // requests are allowed
+    if (!cached && sSendHSTSPriming) {
+      // add this URI as a priming location
+      doHSTSPriming = true;
+      document->AddHSTSPrimingLocation(innerContentLocation,
+          HSTSPrimingState::eHSTS_PRIMING_ALLOW);
+      *aDecision = ACCEPT;
+    }
+  }
+
   // At this point we know that the request is mixed content, and the only
   // question is whether we block it.  Record telemetry at this point as to
   // whether HSTS would have fixed things by making the content location
   // into an HTTPS URL.
   //
   // Note that we count this for redirects as well as primary requests. This
   // will cause some degree of double-counting, especially when mixed content
   // is not blocked (e.g., for images).  For more detail, see:
   //   https://bugzilla.mozilla.org/show_bug.cgi?id=1198572#c19
   //
   // We do not count requests aHadInsecureImageRedirect=true, since these are
   // just an artifact of the image caching system.
   bool active = (classification == eMixedScript);
   if (!aHadInsecureImageRedirect) {
     if (XRE_IsParentProcess()) {
-      AccumulateMixedContentHSTS(innerContentLocation, active);
+      AccumulateMixedContentHSTS(innerContentLocation, active, doHSTSPriming);
     } else {
       // Ask the parent process to do the same call
       mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
       if (cc) {
         mozilla::ipc::URIParams uri;
         SerializeURI(innerContentLocation, uri);
-        cc->SendAccumulateMixedContentHSTS(uri, active);
+        cc->SendAccumulateMixedContentHSTS(uri, active, doHSTSPriming);
       }
     }
   }
 
   // set hasMixedContentObjectSubrequest on this object if necessary
   if (aContentType == TYPE_OBJECT_SUBREQUEST) {
     rootDoc->SetHasMixedContentObjectSubrequest(true);
   }
@@ -856,17 +913,23 @@ nsMixedContentBlocker::ShouldLoad(bool a
       } else {
         // User has overriden the pref and the root is not https;
         // mixed display content was allowed on an https subframe.
         if (NS_SUCCEEDED(stateRV)) {
           eventSink->OnSecurityChange(aRequestingContext, (state | nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
         }
       }
     } else {
-      *aDecision = nsIContentPolicy::REJECT_REQUEST;
+      if (doHSTSPriming) {
+        document->AddHSTSPrimingLocation(innerContentLocation,
+            HSTSPrimingState::eHSTS_PRIMING_BLOCK);
+        *aDecision = nsIContentPolicy::ACCEPT;
+      } else {
+        *aDecision = nsIContentPolicy::REJECT_REQUEST;
+      }
       LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
       if (!rootDoc->GetHasMixedDisplayContentBlocked() && NS_SUCCEEDED(stateRV)) {
         rootDoc->SetHasMixedDisplayContentBlocked(true);
         eventSink->OnSecurityChange(aRequestingContext, (state | nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT));
       }
     }
     return NS_OK;
 
@@ -902,32 +965,37 @@ nsMixedContentBlocker::ShouldLoad(bool a
         // mixed active content was allowed on an https subframe.
         if (NS_SUCCEEDED(stateRV)) {
           eventSink->OnSecurityChange(aRequestingContext, (state | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
         }
         return NS_OK;
       }
     } else {
       //User has not overriden the pref by Disabling protection. Reject the request and update the security state.
-      *aDecision = nsIContentPolicy::REJECT_REQUEST;
+      if (doHSTSPriming) {
+        document->AddHSTSPrimingLocation(innerContentLocation,
+            HSTSPrimingState::eHSTS_PRIMING_BLOCK);
+        *aDecision = nsIContentPolicy::ACCEPT;
+      } else {
+        *aDecision = nsIContentPolicy::REJECT_REQUEST;
+      }
       LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
       // See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
       if (rootDoc->GetHasMixedActiveContentBlocked()) {
         return NS_OK;
       }
       rootDoc->SetHasMixedActiveContentBlocked(true);
 
       // The user has not overriden the pref, so make sure they still have an option by calling eventSink
       // which will invoke the doorhanger
       if (NS_SUCCEEDED(stateRV)) {
          eventSink->OnSecurityChange(aRequestingContext, (state | nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT));
       }
       return NS_OK;
     }
-
   } else {
     // The content is not blocked by the mixed content prefs.
 
     // Log a message that we are loading mixed content.
     LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
 
     // Fire the event from a script runner as it is unsafe to run script
     // from within ShouldLoad
@@ -968,51 +1036,150 @@ nsMixedContentBlocker::ShouldProcess(uin
 
 enum MixedContentHSTSState {
   MCB_HSTS_PASSIVE_NO_HSTS   = 0,
   MCB_HSTS_PASSIVE_WITH_HSTS = 1,
   MCB_HSTS_ACTIVE_NO_HSTS    = 2,
   MCB_HSTS_ACTIVE_WITH_HSTS  = 3
 };
 
+// Similar to the existing mixed-content HSTS, except MCB_HSTS_*_NO_HSTS is
+// broken into two distinct states, indicating whether we plan to send a priming
+// request or not. If we decided not go send a priming request, it could be
+// because it is a type we do not support, or because we cached a previous
+// negative response.
+enum MixedContentHSTSPrimingState {
+  eMCB_HSTS_PASSIVE_WITH_HSTS  = 0,
+  eMCB_HSTS_ACTIVE_WITH_HSTS   = 1,
+  eMCB_HSTS_PASSIVE_NO_PRIMING = 2,
+  eMCB_HSTS_PASSIVE_DO_PRIMING = 3,
+  eMCB_HSTS_ACTIVE_NO_PRIMING  = 4,
+  eMCB_HSTS_ACTIVE_DO_PRIMING  = 5
+};
+
 // Record information on when HSTS would have made mixed content not mixed
 // content (regardless of whether it was actually blocked)
 void
-nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive)
+nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive, bool aHasHSTSPriming)
 {
   // This method must only be called in the parent, because
   // nsSiteSecurityService is only available in the parent
   if (!XRE_IsParentProcess()) {
     MOZ_ASSERT(false);
     return;
   }
 
   bool hsts;
   nsresult rv;
   nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     return;
   }
-  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, &hsts);
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, nullptr, &hsts);
   if (NS_FAILED(rv)) {
     return;
   }
 
+  // states: would upgrade, would prime, hsts info cached
+  // active, passive
+  //
   if (!aActive) {
     if (!hsts) {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_PASSIVE_NO_HSTS);
+      if (aHasHSTSPriming) {
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
+                              eMCB_HSTS_PASSIVE_DO_PRIMING);
+      } else {
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
+                              eMCB_HSTS_PASSIVE_NO_PRIMING);
+      }
     }
     else {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_PASSIVE_WITH_HSTS);
+      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
+                            eMCB_HSTS_PASSIVE_WITH_HSTS);
     }
   } else {
     if (!hsts) {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_ACTIVE_NO_HSTS);
+      if (aHasHSTSPriming) {
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
+                              eMCB_HSTS_ACTIVE_DO_PRIMING);
+      } else {
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
+                              eMCB_HSTS_ACTIVE_NO_PRIMING);
+      }
     }
     else {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_ACTIVE_WITH_HSTS);
+      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
+                            eMCB_HSTS_ACTIVE_WITH_HSTS);
     }
   }
 }
+
+//static
+nsresult
+nsMixedContentBlocker::MarkLoadInfoForPriming(nsIURI* aURI,
+                                              nsISupports* aRequestingContext,
+                                              nsILoadInfo* aLoadInfo)
+{
+  nsresult rv;
+  bool sendPriming = false;
+  bool mixedContentWouldBlock = false;
+  rv = GetHSTSPrimingFromRequestingContext(aURI,
+                                           aRequestingContext,
+                                           &sendPriming,
+                                           &mixedContentWouldBlock);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (sendPriming) {
+    aLoadInfo->SetHSTSPriming(mixedContentWouldBlock);
+  }
+
+  return NS_OK;
+}
+
+//static
+nsresult
+nsMixedContentBlocker::GetHSTSPrimingFromRequestingContext(nsIURI* aURI,
+    nsISupports* aRequestingContext,
+    bool* aSendPrimingRequest,
+    bool* aMixedContentWouldBlock)
+{
+  *aSendPrimingRequest = false;
+  *aMixedContentWouldBlock = false;
+  // If we marked for priming, we used the innermost URI, so get that
+  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
+  if (!innerURI) {
+    NS_ERROR("Can't get innerURI from aContentLocation");
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
+  bool isHttp = false;
+  innerURI->SchemeIs("http", &isHttp);
+  if (!isHttp) {
+    // there is nothign to do
+    return NS_OK;
+  }
+
+  // If the DocShell was marked for HSTS priming, propagate that to the LoadInfo
+  nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
+  if (!docShell) {
+    return NS_OK;
+  }
+  nsCOMPtr<nsIDocument> document = docShell->GetDocument();
+  if (!document) {
+    return NS_OK;
+  }
+
+  HSTSPrimingState status = document->GetHSTSPrimingStateForLocation(innerURI);
+  if (status != HSTSPrimingState::eNO_HSTS_PRIMING) {
+    *aSendPrimingRequest = (status != HSTSPrimingState::eNO_HSTS_PRIMING);
+    *aMixedContentWouldBlock = (status == HSTSPrimingState::eHSTS_PRIMING_BLOCK);
+  }
+
+  return NS_OK;
+}
--- a/dom/security/nsMixedContentBlocker.h
+++ b/dom/security/nsMixedContentBlocker.h
@@ -23,16 +23,18 @@ enum MixedContentTypes {
   eMixedDisplay
 };
 
 #include "nsIContentPolicy.h"
 #include "nsIChannel.h"
 #include "nsIChannelEventSink.h"
 #include "imgRequest.h"
 
+class nsILoadInfo; // forward declaration
+
 class nsMixedContentBlocker : public nsIContentPolicy,
                               public nsIChannelEventSink
 {
 private:
   virtual ~nsMixedContentBlocker();
 
 public:
   NS_DECL_ISUPPORTS
@@ -54,14 +56,46 @@ public:
                              uint32_t aContentType,
                              nsIURI* aContentLocation,
                              nsIURI* aRequestingLocation,
                              nsISupports* aRequestingContext,
                              const nsACString& aMimeGuess,
                              nsISupports* aExtra,
                              nsIPrincipal* aRequestPrincipal,
                              int16_t* aDecision);
-  static void AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive);
+  static void AccumulateMixedContentHSTS(nsIURI* aURI,
+                                         bool aActive,
+                                         bool aHasHSTSPriming);
+  /* If the document associated with aRequestingContext requires priming for
+   * aURI, propagate that to the LoadInfo so the HttpChannel will find out about
+   * it.
+   *
+   * @param aURI The URI associated with the load
+   * @param aRequestingContext the requesting context passed to ShouldLoad
+   * @param aLoadInfo the LoadInfo for the load
+   */
+  static nsresult MarkLoadInfoForPriming(nsIURI* aURI,
+                                         nsISupports* aRequestingContext,
+                                         nsILoadInfo* aLoadInfo);
+
+  /* Given a context, return whether HSTS was marked on the document associated
+   * with the load for the given URI. This is used by MarkLoadInfoForPriming and
+   * directly by the image loader to determine whether to allow a load to occur
+   * from the cache.
+   *
+   * @param aURI The URI associated with the load
+   * @param aRequestingContext the requesting context passed to ShouldLoad
+   * @param aSendPrimingRequest out true if priming is required on the channel
+   * @param aMixedContentWouldBlock out true if mixed content would block
+   */
+  static nsresult GetHSTSPrimingFromRequestingContext(nsIURI* aURI,
+                                                      nsISupports* aRequestingContext,
+                                                      bool* aSendPrimingRequest,
+                                                      bool* aMixedContentWouldBlock);
+
+
   static bool sBlockMixedScript;
   static bool sBlockMixedDisplay;
+  static bool sUseHSTS;
+  static bool sSendHSTSPriming;
 };
 
 #endif /* nsMixedContentBlocker_h___ */
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/browser.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+support-files =
+  file_priming-top.html
+  file_testserver.sjs
+  file_1x1.png
+  file_priming.js
+  file_stylesheet.css
+
+[browser_hsts-priming_main.js]
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/browser_hsts-priming_main.js
@@ -0,0 +1,296 @@
+/*
+ * Description of the test:
+ *   Check that HSTS priming occurs correctly with mixed content
+ *
+ *   This test uses three hostnames, each of which treats an HSTS priming
+ *   request differently.
+ *   * no-ssl never returns an ssl response
+ *   * reject-upgrade returns an ssl response, but with no STS header
+ *   * prime-hsts returns an ssl response with the appropriate STS header
+ *
+ *   For each server, test that it response appropriately when the we allow
+ *   or block active or display content, as well as when we send an hsts priming
+ *   request, but do not change the order of mixed-content and HSTS.
+ *
+ *   This test uses http-on-examine-response, so must be run in browser context.
+ */
+'use strict';
+
+var TOP_URI = "https://example.com/browser/dom/security/test/hsts/file_priming-top.html";
+
+var test_servers = {
+  // a test server that does not support TLS
+  'no-ssl': {
+    host: 'example.co.jp',
+    response: false,
+    id: 'no-ssl',
+  },
+  // a test server which does not support STS upgrade
+  'reject-upgrade': {
+    host: 'example.org',
+    response: true,
+    id: 'reject-upgrade',
+  },
+  // a test server when sends an STS header when priming
+  'prime-hsts': {
+    host: 'test1.example.com',
+    response: true,
+    id: 'prime-hsts'
+  },
+};
+// The number of priming responses we expect to see
+var priming_count = 2;
+
+var test_settings = {
+  // mixed active content is allowed, priming will upgrade
+  allow_active: {
+    block_active: false,
+    block_display: false,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'script',
+    result: {
+      'no-ssl': 'insecure',
+      'reject-upgrade': 'insecure',
+      'prime-hsts': 'secure',
+    },
+  },
+  // mixed active content is blocked, priming will upgrade
+  block_active: {
+    block_active: true,
+    block_display: false,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'script',
+    result: {
+      'no-ssl': 'blocked',
+      'reject-upgrade': 'blocked',
+      'prime-hsts': 'secure',
+    },
+  },
+  // keep the original order of mixed-content and HSTS, but send
+  // priming requests
+  hsts_after_mixed: {
+    block_active: true,
+    block_display: false,
+    use_hsts: false,
+    send_hsts_priming: true,
+    type: 'script',
+    result: {
+      'no-ssl': 'blocked',
+      'reject-upgrade': 'blocked',
+      'prime-hsts': 'blocked',
+    },
+  },
+  // mixed display content is allowed, priming will upgrade
+  allow_display: {
+    block_active: true,
+    block_display: false,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'img',
+    result: {
+      'no-ssl': 'insecure',
+      'reject-upgrade': 'insecure',
+      'prime-hsts': 'secure',
+    },
+  },
+  // mixed display content is blocked, priming will upgrade
+  block_display: {
+    block_active: true,
+    block_display: true,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'img',
+    result: {
+      'no-ssl': 'blocked',
+      'reject-upgrade': 'blocked',
+      'prime-hsts': 'secure',
+    },
+  },
+  // mixed active content is blocked, priming will upgrade (css)
+  block_active_css: {
+    block_active: true,
+    block_display: false,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'css',
+    result: {
+      'no-ssl': 'blocked',
+      'reject-upgrade': 'blocked',
+      'prime-hsts': 'secure',
+    },
+  },
+  // mixed active content is blocked, priming will upgrade
+  // redirect to the same host
+  block_active_with_redir_same: {
+    block_active: true,
+    block_display: false,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'script',
+    redir: 'same',
+    result: {
+      'no-ssl': 'blocked',
+      'reject-upgrade': 'blocked',
+      'prime-hsts': 'secure',
+    },
+  },
+}
+// track which test we are on
+var which_test = "";
+
+const Observer = {
+  observe: function (subject, topic, data) {
+    switch (topic) {
+      case 'console-api-log-event':
+        return Observer.console_api_log_event(subject, topic, data);
+      case 'http-on-examine-response':
+        return Observer.http_on_examine_response(subject, topic, data);
+    }
+    throw "Can't handle topic "+topic;
+  },
+  // When a load is blocked which results in an error event within a page, the
+  // test logs to the console.
+  console_api_log_event: function (subject, topic, data) {
+    var message = subject.wrappedJSObject.arguments[0];
+    // when we are blocked, this will match the message we sent to the console,
+    // ignore everything else.
+    var re = RegExp(/^HSTS_PRIMING: Blocked ([-\w]+).*$/);
+    if (!re.test(message)) {
+      return;
+    }
+
+    let id = message.replace(re, '$1');
+    let curTest =test_servers[id];
+
+    if (!curTest) {
+      ok(false, "HSTS priming got a console message blocked, "+
+          "but doesn't match expectations "+id+" (msg="+message);
+      return;
+    }
+
+    is("blocked", test_settings[which_test].result[curTest.id], "HSTS priming "+
+        which_test+":"+curTest.id+" expected "+
+        test_settings[which_test].result[curTest.id]+", got blocked");
+    test_settings[which_test].finished[curTest.id] = "blocked";
+  },
+  // When we see a response come back, peek at the response and test it is secure
+  // or insecure as needed. Addtionally, watch the response for priming requests.
+  http_on_examine_response: function (subject, topic, data) {
+    let curTest = null;
+    let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+    for (let item in test_servers) {
+      let re = RegExp('https?://'+test_servers[item].host);
+      if (re.test(channel.URI.asciiSpec)) {
+        curTest = test_servers[item];
+        break;
+      }
+    }
+
+    if (!curTest) {
+      return;
+    }
+
+    let result = (channel.URI.asciiSpec.startsWith('https:')) ? "secure" : "insecure";
+
+    // This is a priming request, go ahead and validate we were supposed to see
+    // a response from the server
+    if (channel.requestMethod == 'HEAD') {
+      is(true, curTest.response, "HSTS priming response found " + curTest.id);
+      test_settings[which_test].priming[curTest.id] = true;
+      return;
+    }
+
+    // This is the response to our query, make sure it matches
+    is(result, test_settings[which_test].result[curTest.id],
+        "HSTS priming result " + which_test + ":" + curTest.id);
+    test_settings[which_test].finished[curTest.id] = result;
+  },
+};
+
+// opens `uri' in a new tab and focuses it.
+// returns the newly opened tab
+function openTab(uri) {
+  let tab = gBrowser.addTab(uri);
+
+  // select tab and make sure its browser is focused
+  gBrowser.selectedTab = tab;
+  tab.ownerDocument.defaultView.focus();
+
+  return tab;
+}
+
+function clear_sts_data() {
+  for (let test in test_servers) {
+    SpecialPowers.cleanUpSTSData('http://'+test_servers[test].host);
+  }
+}
+
+function do_cleanup() {
+  clear_sts_data();
+
+  Services.obs.removeObserver(Observer, "console-api-log-event");
+  Services.obs.removeObserver(Observer, "http-on-examine-response");
+}
+
+function SetupPrefTestEnvironment(which) {
+  which_test = which;
+  clear_sts_data();
+
+  var settings = test_settings[which];
+  // priming counts how many priming requests we saw
+  settings.priming = {};
+  // priming counts how many tests were finished
+  settings.finished= {};
+
+  SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.block_active_content",
+                                      settings.block_active],
+                                     ["security.mixed_content.block_display_content",
+                                      settings.block_display],
+                                     ["security.mixed_content.use_hsts",
+                                      settings.use_hsts],
+                                     ["security.mixed_content.send_hsts_priming",
+                                      settings.send_hsts_priming]]});
+}
+
+// make the top-level test uri
+function build_test_uri(base_uri, host, test_id, type) {
+  return base_uri +
+          "?host=" + escape(host) +
+          "&id=" + escape(test_id) +
+          "&type=" + escape(type);
+}
+
+// open a new tab, load the test, and wait for it to finish
+function execute_test(test, mimetype) {
+  var src = build_test_uri(TOP_URI, test_servers[test].host,
+      test, test_settings[which_test].type);
+
+  let tab = openTab(src);
+  test_servers[test]['tab'] = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  yield BrowserTestUtils.browserLoaded(browser);
+
+  yield BrowserTestUtils.removeTab(tab);
+}
+
+//jscs:disable
+add_task(function*() {
+  //jscs:enable
+  Services.obs.addObserver(Observer, "console-api-log-event", false);
+  Services.obs.addObserver(Observer, "http-on-examine-response", false);
+  registerCleanupFunction(do_cleanup);
+  requestLongerTimeout(4);
+
+  for (let which of Object.keys(test_settings)) {
+    SetupPrefTestEnvironment(which);
+
+    for (let server of Object.keys(test_servers)) {
+      yield execute_test(server, test_settings[which].mimetype);
+    }
+
+    SpecialPowers.popPrefEnv();
+  }
+});
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1ba31ba1a62313908f41f844a9fb2e74663a4cd2
GIT binary patch
literal 17811
zc%1E<cT`i^x5p2?D5xkXWh4d_P*NxfNrWH}qzI@q6GR~-7l@Jsk_e%rG72K%fQq7G
zd4pg<aR57D0THEIU_d|_3quhEM7sQf=!k-|T<iVbKX2W$*3He`=Y01kcb~ma&dpkh
zTkB}8Ag?A508p^Cp*V@oV&jLbwCGh+xhPI_k_)h*@d21Icl;0osYe$8Ab*QxX}NZ-
zA6LNT`*8yhww9KN03O$e<qrWMtj{{=>*8Fuuz0M$>Al73*y#OLE1V?7Wn&zHRI8WP
z;{7XQ^%rOUsT?R-vVFI#n_#x&?MuL5cdXR26VzK|^M&$l1nO+%1O3~qg}pVyJvE_Y
zd7ak_^J<C19sI5og_U8qQtXN|rC08ypyL(0eYKY^$%(UD31sGB#a0v`*0;@9Ru%);
z?vKOaZPJq9#RXH(Wy*KQ@TqrlJ;Z>L6gYFo!(0*Y<N-_B2I2vGMQ}R)wG$DzNdtSD
zx03;IlL2LW0yz@Er;YGj0-V;vlK@Z$i0XlGnl$Ls0@=Nisyv`J7icW8_)RieMHY~^
z+ZW7^b^{=YNSyI2$bAXC4h(V0s!_f6t|2{xs>>D@&H!MaxYac${V3g$LT&5whX{8i
zf#2ajs{DYL7~*N&jJvLSw#Sr-w~>o(N%}6cc)66iPko=sZHq{+0m<cmyc}722y>)i
zc~Y;pHuW;r{WWGz<?gkE8Qm^N530{Iyxn@rt4XrO_uf+bfHa-R8p#%)l9)9Y<kq$t
zSmiF`U)Q5<Ejijy>M#EB6|JZ2&#Kayac52L<laIYK*u>}r92pQO>+u-!i)@zwW}<T
zU-$OFLvPnm6*IlfkF@RjA`r8;BgB!>3V|<XcD|5A&z485*?^P*vQ(Xo%jQDN2X&E7
zX9x-9$+8+9e^%^u<bXKa(vEJ=k!CRjh|ac2uIKnhpO6O>!kNG{@h7$*_qsMNM-dFk
zu56dtW^vH?LNfsGR*G%)+KyhZU6;Del(0ixC^mmPVkUBtN|F~@7BQE%QaYYaJipCC
zXJ=OS+y`_sjqRHW(%L8FD(*;K6*qo?Z`f6GA|_I(VEImN)f~x1NI}fDzmcnAiQe%9
zEsY`>ISb@Izr}L4<_5FnPOUts)xOXBcS&7qMI`S2#rvwS#CZy>77LO2_Ypk{2X}kx
zC_tyAGo?rhuTMn!5!B)<EDfuy{K)RnoK+92>~a;^6wC?Zs^Ltfhy+DO^g4YNpFMR9
z4LuNFlypg8zcZ_7cec}crE?|j*@_+L(?v~Qo&k~?5+(QQUfv8id6jS!T#>z^bVY9c
z-gEbGf1#T@{|XJXys9ZAZPMh%_ZRiPiyN3Z;vK%IV4ml%W(kFR3KP3ZqL8y?^|mj$
zeQdU!4U#$M;2iv%4@zpX>=?9#CjF4j;x;9ATvL$^^0<z+ic;|0_SlxV;Mmck%Eik{
zV_(_JFI|$n`1icuogS@oTHdPIx`eg=yg6PwEJ>@>qQ|L6rH9U&F{pCwxQSi$?^LIo
zx|jCrJy5e#O;6(;?uqHyW|yA2)-*Hc46<$WX4O7I-?F@vp<hp1<(!nNdh=*rZh5X&
zF23HfUWRmxW8U&8xs^BM6RI$Z99137QL`*JPsmv6vLW5=WKCv}_1i2Gt<j@#O+-Ox
zLFkzw+rABLT%-GHDr#bC;Ry%Sl+}EVLXCFfR8t*Oe@i8%9x+PXyy>w<6>>ApPl_d%
zC!edx+W4f6;Wg8F6|lTTEg_U$E&JP7>Ci#@g@*C8GLw59Ohwif)|%SAwVO_DJQ?A*
zq4W+_MQ`Eividuu+igA($Gow{T)X=H3C?X94TlX*8M^K|mwej!_s1vro-OCl8;os?
zHv}KyBzHQS9!*PV^3N|09e$5)&p-U&XdBKIo9EXScP8=ux(M}Azfovt*L!Z;EcFFy
zF$-)Ig48{XgpB(Juhe{0JF)&a4I}RbgA3yJ1T8pb99mrCGkmGI!{Eb`5Bn|^1ZG~k
zGjJj>qdPM$-S%jyd$M$L#_4&^ds)|86(0vZUSz11bJ*u$`R4M4hm*^RZw|k?QMRJY
zT2Bw9q=%;((PmQHs6BeUs4b}D)atD8EESrodt=U0D*t>=R=@l6%jRqkwgG#YKd0{0
zWzJ>fv;4~&gM=$)t%%#0zA@3Xys460Sx{3@yY2Pt=Iol2rOj`Ra#*F0FFUj!`f#`U
z>ADW#pWT;|4>})u?4F^L(O-eD5O0xh2}27~yi#1z<>;={&m7krDc}xCtl!ygU#oE8
z?S<!!4UJ4rA7@9WPp58YSVI`W-f^Dq+?KO4O?RI&4wTRmF=?DMUgg}hsF1oaDD0O$
zwL^5G7W-baYDCl0rtq#EO?H}>*X*to(@ej33G@8QqkdxT{^hUS0zHRl!_eT<!Ti49
z_bG$NKWNImn@OEhr4lQ(Q&L4LNSY;8EOkJ}bOv6oLiU2fLis=in#v=U-Ln*CHLBF#
zHGCl_#N9lJ?ax-Gr`%yR>o>n{uGI1uRS?Rs`Y_$_N@cjg!|;PlH|NEa9^@5ka>5^b
z+~@T@^S{%PS*M)iNm*fqN$iZJ7wN?k)p~Vn%z{>Tyd<0>Sb2oq3>|40NFDes=2lFS
zB=lEqk#d}I()%QeZFy<YtAST%Uo{iW`9T$}$J<F)0yzC94?|YJ*?8olv8TycgLt3R
zh?KVTJ6$<lYv+P)t-%8$%`ThT(w;0bkM>G=k+*Mo!y*m)UdQFOVTU`9ZAv2VYd&_#
zl!1M0oMY6RptI5i9h#z?nrF6U@d|@sn-7Nw<_-HSAJ~=>wW^bttI;SUkE=|2$`dzt
z9anUZM=rm5pPq-?f%sPy57`F|Upoyt{CdDU|CDj1_C;h@?_UGO+9`hM-}J6sd*ai2
zFCEjnqc@7SbHh?<O+kZjF!go*@)0);kGS*p8|w-l2wZQU{rGgzxpTE^YnT@YBeGuB
zC*^6@E;+wN7pp_vSapTWj9{O1KY2decSr5cQM2YqrO_wXs-c&i31+)vtZL(biC-OG
z$X4>d{xRoqC1jS!c6{D&t(g6=AS)&-DXZ~W_!ZX_zk{z*-m{Ni%MX+Zv##EoxMF_C
zO*c}$U<~~LU5tik6k0DQr*T7Y)bdKbLeFN;>TK(%%6q0-VZVlTb-e66_nezuC>*Pm
zI3+Plai@m=`P@uBQwm{!@ZZJF19yKZ42V2)=Fz!j7ltA!JPPfXjS*+=<)40&`LP<6
z=a+RVD4WA+e9PEYlG^^ZeHK1jZFl0`z~b)pg{MdABakDMVcUw*A?G(4ACCGQMQ^64
zrQj8D5MK94a_WtWm}4w%_h#bgk-J>$3bo@|gp3Hz>gDNqC$@Hke;jPavz{H9p*nx4
zetxc5!69LHQ+izr3A4+yAau#VgJQ+Py}j%6FQ(<c33*$#wW9B|I>%Uzd%ekI^hSGE
z#)?LgI``W1%>{1*Z=`QowZ8qA=PTxSN;l>65`(+$jnevWTz`38^L^Rdb>!LP1wx(3
zfzEYJ|5IIZ?)Z!2^Gu%#-G}VQXs<PEqKtGJ_qT*fgmKA<As?@<sp=onyf!va<N0p;
z$5Zdqs~@I{wQS4TaeK!V&+?F`W9~zt?;V<tr$%*#Z0Y;(#IvE0qqsz|uP`}ZJ*=>G
zN9Qgr&5S62&An=oA9PzD|7}z4+gSP3li*1zSQ;Kdygs1by`e6+y$fY_C(1<ip{jav
z4-^i-EdU(W$Oxk(qthgBT~%1QPQB|s0MUE;L!-MDd!C2fw3YzT>MKnFg(v3m3^?+{
z%ASG0*<hVVG!=aUjXvArnS7-4FOyCyw)m}-y$KOE0O2kX-leLp&Q?<&-Xs-mD(*LI
z)Ko48jM{+Weu8uirNMoyrERR^{+ML<YdM*-gfv?KNNAP|RX}yHCo#BeG@Z%yhR{NG
z02ps3X2JkEV+$lectgG{jw!P1Mj;ZxVwxh?;~cOK0hW*-%O;cuIfpvBFhaL5h)kpz
zS>8lQ5;<T)0y;v-_UG_PLQ~`?za-K7aWe*q_%uYY#T02i-hrSxtVLLIc@P4J#-kYe
z`uYfCB3d6uFf_pFAq=qkI1HAE(Z`~&`XqfU$pDM^+>m5>(W?oM=|gg&ton=-U6~^N
z1cCq(1``|{j1D$Lb9ufPeIk*F!5Ux;3{avGD1Hb>Ko_Doe60y5U;I!YK7+>!5U{u$
z#P~Jco4ZwDibTpICbiG^#SZuf#NmIAohXVJAw2-2kH%ttAaZc{cNv>Kt&%UW3KIOg
zlJ61{0AZXUK6fjR0a*n>9D&w!u9%E}`~+;}`G1NJlYxQ!A+|`u7x~hk_9Fy*dE}Y?
zWBk+o!@C!-e0-+Yj`#df1_@a|kd60D$jD!HCZZsdEO`)Jz~#Acx&GvdEc^PvCVE~Q
z&nkqD1D(O*j2m@LFyD)&^9NBx2U(=Wqp(IOEY3wAPr~9!1~?Sfn1sbnaxyXUJ0A|B
z>}S#i^q=wa&Dih#aG5Nhke~AMb>z1`92`it9KL|gVL-MNvdDmDv6v)?Kp@hYI6BG*
zkHw>m4C&q|f;SzD^7i&-;vlTP4}r<}<oH|p6xS3kW9xV-iTWl=pUGv2-2amxB)m6W
zU*FgWhcXnEJ4*DHh$1rSL=gxFG4+`^L&%W+1vJUo6wn$TOSCf4{U?nXzZa$m=7YuI
zaX!WdC??UHi83-WGDLafm_{g^D6DiWUW7C-{DPRq%@mXki!Vxz5b`(q`Dx8?h62B}
ze(CUMeOf~T=sZ3&UYe%JFSUuBA{f_vDsd8>F~0hc8K2UKX@dF2`ePYu>U92G2&Tw?
z%n0^_IRBP%lScj637_jD2&VHOb6-)Uf37yC6HbXZW+LSO2UEeP2mS9R;^*q>|H(vr
z1u*>R9AAh@#(WWeG5p-zO<2FJt}hikwHi&B43ZC*$EFL&EH>R2!US-9O)y`LlSY1B
zhb+1NT%Kr=gvg>on9e+{%GT0y?ZoeWWD1KP;7<>kES}UmNj?4rH@?n@B1Zp|K>8+_
zDYoy&Q^%9kf9t0{V*{+HiMB!5@d=*N{k@d-?^4>oNWXTua##Yg!Dq>L=1HpYZ{dlU
zIg2)o5E+ld8RASZ-<!WztYrxye=3C~T5<WGBQmXhS{>~NI@%Q7L>f)n*iGyjF`u`M
zq8%&dpDpWj$^74MFa(Cc5EueOU<eF>Aut4nzz`S$LtqFDfgvyihQJUQ0z+U341pmq
z1cty67y?6J2n>NCFa(Cc5EueOU<eF>Aut4nzz`S$Ltw~%86yAnPoNNoX^IR+nvwhS
zcIf~B5DXh92LL$Q0PrsYF_|0yLb3o@qXfj{AONs`05Ip?20l$+G<L2n#oR?$?>#U!
hW+oxJ9vhPYvLoUjAE$4nkN?%w*2<A`!NP0%e*nP=bK(F1
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/file_priming-top.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1246540</title>
+  <meta http-equiv='content-type' content="text/html;charset=utf-8" />
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="visibility: hidden">
+  </div>
+
+<script type="text/javascript">
+/*
+ * Description of the test:
+ * Attempt to load an insecure resource. If the resource responds to HSTS
+ * priming with an STS header, the load should continue securely.
+ * If it does not, the load should continue be blocked or continue insecurely.
+ */
+
+function parse_query_string() {
+  var q = {};
+  document.location.search.substr(1).
+    split('&').forEach(function (item, idx, ar) {
+      let [k, v] = item.split('=');
+      q[k] = unescape(v);
+    });
+  return q;
+}
+
+var args = parse_query_string();
+
+var subresources = {
+  css: { mimetype: 'text/css', file: 'file_stylesheet.css' },
+  img: { mimetype: 'image/png', file: 'file_1x1.png' },
+  script: { mimetype: 'text/javascript', file: 'file_priming.js' },
+};
+
+function handler(ev) {
+  console.log("HSTS_PRIMING: Blocked "+args.id);
+}
+
+function loadCss(src) {
+  let head = document.getElementsByTagName("head")[0];
+  let link = document.createElement("link");
+  link.setAttribute("rel", "stylesheet");
+  link.setAttribute("type", subresources[args.type].mimetype);
+  link.setAttribute("href", src);
+  head.appendChild(link);
+}
+
+function loadResource(src) {
+  let content = document.getElementById("content");
+  let testElem = document.createElement(args.type);
+  testElem.setAttribute("id", args.id);
+  testElem.setAttribute("charset", "UTF-8");
+  testElem.onerror = handler;
+  content.appendChild(testElem);
+  testElem.src = src;
+}
+
+function loadTest() {
+  let subresource = subresources[args.type];
+
+  let src = "http://"
+    + args.host
+    + "/browser/dom/security/test/hsts/file_testserver.sjs"
+    + "?file=" +escape("browser/dom/security/test/hsts/" + subresource.file)
+    + "&primer=" + escape(args.id)
+    + "&mimetype=" + escape(subresource.mimetype)
+    ;
+  if (args.type == 'css') {
+    loadCss(src);
+    return;
+  }
+
+  loadResource(src);
+}
+
+// start running the tests
+loadTest();
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/file_priming.js
@@ -0,0 +1,4 @@
+function completed() {
+  return;
+}
+completed();
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/file_testserver.sjs
@@ -0,0 +1,66 @@
+// SJS file for HSTS mochitests
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+function loadFromFile(path) {
+  // Load the HTML to return in the response from file.
+  // Since it's relative to the cwd of the test runner, we start there and
+  // append to get to the actual path of the file.
+  var testFile =
+    Components.classes["@mozilla.org/file/directory_service;1"].
+    getService(Components.interfaces.nsIProperties).
+    get("CurWorkD", Components.interfaces.nsILocalFile);
+  var dirs = path.split("/");
+  for (var i = 0; i < dirs.length; i++) {
+    testFile.append(dirs[i]);
+  }
+  var testFileStream =
+    Components.classes["@mozilla.org/network/file-input-stream;1"].
+    createInstance(Components.interfaces.nsIFileInputStream);
+  testFileStream.init(testFile, -1, 0, 0);
+  var test = NetUtil.readInputStreamToString(testFileStream, testFileStream.available());
+  return test;
+}
+
+function handleRequest(request, response)
+{
+  const query = new URLSearchParams(request.queryString);
+
+  redir = query.get('redir');
+  if (redir == 'same') {
+    query.delete("redir");
+    response.setStatus(302);
+    let newURI = request.uri;
+    newURI.queryString = query.serialize();
+    response.setHeader("Location", newURI.spec)
+  }
+
+  // avoid confusing cache behaviors
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  // if we have a priming header, check for required behavior
+  // and set header appropriately
+  if (request.hasHeader('Upgrade-Insecure-Requests')) {
+    var expected = query.get('primer');
+    if (expected == 'prime-hsts') {
+      // set it for 5 minutes
+      response.setHeader("Strict-Transport-Security", "max-age="+(60*5), false);
+    } else if (expected == 'reject-upgrade') {
+      response.setHeader("Strict-Transport-Security", "max-age=0", false);
+    }
+    response.write('');
+    return;
+  }
+
+  var file = query.get('file');
+  if (file) {
+    var mimetype = unescape(query.get('mimetype'));
+    response.setHeader("Content-Type", mimetype, false);
+    response.write(loadFromFile(unescape(file)));
+    return;
+  }
+
+  response.setHeader("Content-Type", "application/json", false);
+  response.write('{}');
+}
--- a/dom/security/test/mixedcontentblocker/test_main.html
+++ b/dom/security/test/mixedcontentblocker/test_main.html
@@ -157,16 +157,19 @@ https://bugzilla.mozilla.org/show_bug.cg
         testsToRun["imageLeavePicture"] = true;
         break;
 
     }
     checkTestsCompleted();
   }
 
   function startTest() {
+    // Set prefs to use mixed-content before HSTS
+    SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.use_hsts", false],
+                                       ["security.mixed_content.send_hsts_priming", false]]});
     //Set the first set of mixed content settings and increment the counter.
     //Enable <picture> and <img srcset> for the test.
     changePrefs([[ "dom.image.srcset.enabled", true ], [ "dom.image.picture.enabled", true ]],
       function() {
         //listen for a messages from the mixed content test harness
         window.addEventListener("message", receiveMessage, false);
 
         //Kick off test
--- a/dom/security/test/moz.build
+++ b/dom/security/test/moz.build
@@ -22,9 +22,10 @@ MOCHITEST_MANIFESTS += [
 
 MOCHITEST_CHROME_MANIFESTS += [
     'csp/chrome.ini',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'contentverifier/browser.ini',
     'csp/browser.ini',
+    'hsts/browser.ini',
 ]
deleted file mode 100644
--- a/dom/tests/mochitest/bugs/bug918719.sjs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Keep track of one in-flight XHR by allowing secondary ones to
-// tell us when the client has received a Progress event and wants
-// more data or to stop the in-flight XHR.
-
-const STATE_NAME = "bug918719_loading_event_test";
-const CHUNK_DATA = "chunk";
-
-function setReq(req) {
-  setObjectState(STATE_NAME, req);
-}
-
-function getReq() {
-  let req;
-  getObjectState(STATE_NAME, function(v) {
-    req = v;
-  });
-  return req;
-}
-
-function handleRequest(request, response)
-{
-  var pairs = request.queryString.split("&");
-  var command = pairs.shift();
-
-  response.setHeader("Content-Type", "text/plain");
-  response.setHeader("Cache-Control", "no-cache", false);
-
-  switch(command) {
-    case "more":
-      getReq().write(CHUNK_DATA);
-      break;
-
-    case "done":
-      getReq().finish();
-      setReq(null);
-      break;
-
-    default:
-      response.processAsync();
-      response.write(CHUNK_DATA);
-      setReq(response);
-      return;
-  }
-
-  response.setHeader("Content-Length", "2", false);
-  response.write("ok");
-}
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -2,17 +2,16 @@
 support-files =
   bug289714.sjs
   bug346659-echoer.html
   bug346659-opener-echoer.html
   bug346659-opener.html
   bug346659-parent-echoer.html
   bug346659-parent.html
   bug458091_child.html
-  bug918719.sjs
   child_bug260264.html
   devicemotion_inner.html
   devicemotion_outer.html
   file_bug291653.html
   file_bug406375.html
   file_bug504862.html
   file_bug593174_1.html
   file_bug593174_2.html
@@ -151,17 +150,16 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug809290.html]
 [test_bug817476.html]
 [test_bug823173.html]
 [test_bug848088.html]
 [test_bug850517.html]
 [test_bug857555.html]
 [test_bug862540.html]
 [test_bug876098.html]
-[test_bug918719.html]
 [test_bug927901.html]
 [test_devicemotion_multiple_listeners.html]
 skip-if = toolkit == 'android' #bug 775227
 [test_domparser_after_blank.html]
 [test_errorReporting.html]
 [test_onerror_message.html]
 [test_protochains.html]
 [test_resize_move_windows.html]
deleted file mode 100644
--- a/dom/tests/mochitest/bugs/test_bug918719.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=918719
--->
-<head>
-  <title>Test for Bug 918719</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=918719">Mozilla Bug 918719</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-SimpleTest.waitForExplicitFinish();
-
-const SERVER_URL = "bug918719.sjs";
-
-function sendCommand(cmd) {
-  let xhr = new XMLHttpRequest();
-  xhr.open("get", SERVER_URL + "?" + cmd);
-  xhr.send();
-}
-
-function runTest() {
-  // Manipulate one in-flight XHR using secondary command XHRs, to guarantee
-  // that multiple OnDataAvailable events are triggered (which are where
-  // LOADING readystatechanges are triggered). We return a promise that will
-  // resolve with a count of the number of LOADING events that were detected.
-
-  return new Promise((resolve, reject) => {
-    let xhr = new XMLHttpRequest();
-    let numProgressEvents = 0;
-    let numLoadingEvents = 0;
-
-    xhr.onreadystatechange = e => {
-      if (xhr.readyState === xhr.LOADING) {
-        ++numLoadingEvents;
-      }
-    };
-
-    xhr.onprogress = e => {
-      if (++numProgressEvents < 2) {
-        sendCommand("more");
-      } else {
-        sendCommand("done");
-      }
-    };
-
-    xhr.onerror = e => {
-      reject(e);
-    };
-
-    xhr.onloadend = e => {
-      resolve(numLoadingEvents);
-    };
-
-    xhr.open("GET", SERVER_URL);
-    xhr.send();
-  });
-}
-
-function prefChangePromise(args) {
-  return new Promise(function(resolve) {
-    SpecialPowers.pushPrefEnv(args, resolve);
-  });
-}
-
-runTest().then(function(count) {
-  ok(count === 1, "Only one loading readystatechange event should have been fired with the pref off.");
-}).then(function() {
-  return prefChangePromise({"set": [["dom.fire_extra_xhr_loading_readystatechanges", true]]});
-}).then(function() {
-  return runTest();
-}).then(function(count) {
-  ok(count > 1, "Multiple loading readystatechange events should have been fired with the pref on.");
-  SimpleTest.finish();
-});
-
-</script>
-</pre>
-</body>
-</html>
-
--- a/dom/workers/test/serviceworkers/create_another_sharedWorker.html
+++ b/dom/workers/test/serviceworkers/create_another_sharedWorker.html
@@ -1,6 +1,6 @@
 <!DOCTYPE HTML>
 <title>Shared workers: create antoehr sharedworekr client</title>
 <pre id=log>Hello World</pre>
 <script>
   var worker = new SharedWorker('sharedWorker_fetch.js');
-</script>
\ No newline at end of file
+</script>
--- a/dom/workers/test/serviceworkers/fetch.js
+++ b/dom/workers/test/serviceworkers/fetch.js
@@ -1,13 +1,11 @@
 addEventListener('fetch', function(event) {
   if (event.request.url.indexOf("fail.html") !== -1) {
-    event.respondWith(fetch("serviceworker.html", {"integrity": "abc"}));
+    event.respondWith(fetch("hello.html", {"integrity": "abc"}));
   } else if (event.request.url.indexOf("fake.html") !== -1) {
-    event.respondWith(fetch("serviceworker.html"));
-  } else {
-    event.respondWith(new Response("Hello world"));
+    event.respondWith(fetch("hello.html"));
   }
 });
 
 addEventListener("activate", function(event) {
   event.waitUntil(clients.claim());
 });
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/hello.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+  </head>
+  <body>
+    Hello.
+  </body>
+<html>
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -205,17 +205,17 @@ support-files =
   !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
   !/dom/tests/mochitest/notification/MockServices.js
   !/dom/tests/mochitest/notification/NotificationTest.js
   blocking_install_event_worker.js
   sw_bad_mime_type.js
   sw_bad_mime_type.js^headers^
   error_reporting_helpers.js
   fetch.js
-  serviceworker.html
+  hello.html
   create_another_sharedWorker.html
   sharedWorker_fetch.js
 
 [test_bug1151916.html]
 [test_bug1240436.html]
 [test_claim.html]
 [test_claim_fetch.html]
 [test_claim_oninstall.html]
--- a/dom/workers/test/serviceworkers/sharedWorker_fetch.js
+++ b/dom/workers/test/serviceworkers/sharedWorker_fetch.js
@@ -22,10 +22,8 @@ onconnect = function(e) {
         fetch("SharedWorker_SRIFailed.html", {"integrity": "abc"}).then(
             function () {
                 clients[0].postMessage('SRI_failed');
             });
       }
     }
   }
 }
-
-
--- a/dom/workers/test/serviceworkers/test_fetch_integrity.html
+++ b/dom/workers/test/serviceworkers/test_fetch_integrity.html
@@ -170,9 +170,9 @@ add_task(function* test_integrity_shared
   yield wait_for_expected_message(expectedMessage);
 
   yield wait_for_expected_message(expectedMessage2);
   client_win.close();
 });
 
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -164,17 +164,16 @@ XMLHttpRequestMainThread::XMLHttpRequest
   : mResponseBodyDecodedPos(0),
     mResponseType(XMLHttpRequestResponseType::_empty),
     mRequestObserver(nullptr),
     mState(State::unsent),
     mFlagSynchronous(false), mFlagAborted(false), mFlagParseBody(false),
     mFlagSyncLooping(false), mFlagBackgroundRequest(false),
     mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false),
     mFlagTimedOut(false), mFlagDeleted(false), mFlagSend(false),
-    mSendExtraLoadingEvents(Preferences::GetBool("dom.fire_extra_xhr_loading_readystatechanges", true)),
     mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
     mProgressSinceLastProgressEvent(false),
     mRequestSentTime(0), mTimeoutMilliseconds(0),
     mErrorLoad(false), mErrorParsingXML(false),
     mWaitingForOnStopRequest(false),
     mProgressTimerIsActive(false),
     mIsHtml(false),
     mWarnAboutSyncHtml(false),
@@ -1710,19 +1709,17 @@ XMLHttpRequestMainThread::OnDataAvailabl
     }
 
     ChangeState(State::loading);
     return request->Cancel(NS_OK);
   }
 
   mDataAvailable += totalRead;
 
-  if (mState == State::headers_received || mSendExtraLoadingEvents) {
-    ChangeState(State::loading);
-  }
+  ChangeState(State::loading);
 
   if (!mFlagSynchronous && !mProgressTimerIsActive) {
     StartProgressEventTimer();
   }
 
   return NS_OK;
 }
 
@@ -2409,16 +2406,37 @@ XMLHttpRequestMainThread::CreateChannel(
     secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
                nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
   if (mIsAnon) {
     secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
   }
 
+  nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(mPrincipal);
+  if (ep) {
+    // If we have an expanded principal, instead of using that, select the
+    // principal in the whitelist which can load our URL, and use that instead.
+    nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist = nullptr;
+    ep->GetWhiteList(&whitelist);
+    if (!whitelist) {
+      return NS_ERROR_FAILURE;
+    }
+    MOZ_ASSERT(!(secFlags & nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS));
+    bool dataInherits = (secFlags &
+      (nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
+       nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) != 0;
+    for (const auto& principal : *whitelist) {
+      if (NS_SUCCEEDED(principal->CheckMayLoad(mRequestURL, false, dataInherits))) {
+        mPrincipal = principal;
+        break;
+      }
+    }
+  }
+
   // Use the responsibleDocument if we have it, except for dedicated workers
   // where it will be the parent document, which is not the one we want to use.
   nsresult rv;
   nsCOMPtr<nsIDocument> responsibleDocument = GetDocumentIfCurrent();
   if (responsibleDocument && responsibleDocument->NodePrincipal() == mPrincipal) {
     rv = NS_NewChannel(getter_AddRefs(mChannel),
                        mRequestURL,
                        responsibleDocument,
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -681,24 +681,16 @@ protected:
   bool mFlagDeleted;
 
   // The XHR2 spec's send() flag. Set when the XHR begins uploading, until it
   // finishes downloading (or an error/abort has occurred during either phase).
   // Used to guard against the user trying to alter headers/etc when it's too
   // late, and ensure the XHR only handles one in-flight request at once.
   bool mFlagSend;
 
-  // Before ProgressEvents were a thing, multiple readystatechange events were
-  // fired during the loading state to give sites a way to monitor XHR progress.
-  // The XHR spec now has proper progress events and dictates that only one
-  // "loading" readystatechange should be fired per send. However, it's possible
-  // that some content still relies on this old behavior, so we're keeping it
-  // (behind a preference) for now. See bug 918719.
-  bool mSendExtraLoadingEvents;
-
   RefPtr<XMLHttpRequestUpload> mUpload;
   int64_t mUploadTransferred;
   int64_t mUploadTotal;
   bool mUploadComplete;
   bool mProgressSinceLastProgressEvent;
 
   // Timeout support
   PRTime mRequestSentTime;
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-52342
+52343
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -13742,16 +13742,17 @@ admonishment/MS
 admonition/MS
 admonitory
 ado/M
 adobe/MS
 adolescence/SM
 adolescent/SM
 adopt/AGVDS
 adoptable
+adoptee/MS
 adopter/MS
 adoption/SM
 adorableness/M
 adorably
 adoration/M
 adore/BZGDRS
 adorer/M
 adoring/Y
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -818,17 +818,17 @@ GLContextGLX::CreateGLContext(CreateCont
             printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
         }
     }
 
     GLXContext context;
     RefPtr<GLContextGLX> glContext;
     bool error;
 
-    ScopedXErrorHandler xErrorHandler;
+    OffMainThreadScopedXErrorHandler xErrorHandler;
 
     do {
         error = false;
 
         GLXContext glxContext = shareContext ? shareContext->mContext : nullptr;
         if (glx.HasCreateContextAttribs()) {
             AutoTArray<int, 11> attrib_list;
             if (glx.HasRobustness()) {
@@ -1306,17 +1306,17 @@ CreateOffscreenPixmapContext(CreateConte
         NS_WARNING("Failed to find a compatible config.");
         return nullptr;
     }
 
     Visual* visual;
     int depth;
     FindVisualAndDepth(display, visid, &visual, &depth);
 
-    ScopedXErrorHandler xErrorHandler;
+    OffMainThreadScopedXErrorHandler xErrorHandler;
     bool error = false;
 
     Drawable drawable;
     GLXPixmap pixmap = 0;
 
     gfx::IntSize dummySize(16, 16);
     RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
                                                             visual,
--- a/gfx/gl/SurfaceTypes.cpp
+++ b/gfx/gl/SurfaceTypes.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* 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 "SurfaceTypes.h"
 
-#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/TextureForwarder.h"
 
 namespace mozilla {
 namespace gl {
 
 SurfaceCaps::SurfaceCaps()
 {
     Clear();
 }
--- a/gfx/gl/SurfaceTypes.h
+++ b/gfx/gl/SurfaceTypes.h
@@ -7,34 +7,34 @@
 #define SURFACE_TYPES_H_
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/Attributes.h"
 #include <stdint.h>
 
 namespace mozilla {
 namespace layers {
-class ISurfaceAllocator;
+class LayersIPCChannel;
 } // namespace layers
 
 namespace gl {
 
 struct SurfaceCaps final
 {
     bool any;
     bool color, alpha;
     bool bpp16;
     bool depth, stencil;
     bool antialias;
     bool premultAlpha;
     bool preserve;
 
     // The surface allocator that we want to create this
     // for.  May be null.
-    RefPtr<layers::ISurfaceAllocator> surfaceAllocator;
+    RefPtr<layers::LayersIPCChannel> surfaceAllocator;
 
     SurfaceCaps();
     SurfaceCaps(const SurfaceCaps& other);
     ~SurfaceCaps();
 
     void Clear();
 
     SurfaceCaps& operator=(const SurfaceCaps& other);
--- a/gfx/layers/GrallocImages.cpp
+++ b/gfx/layers/GrallocImages.cpp
@@ -68,17 +68,17 @@ GrallocImage::SetData(const Data& aData)
   mData = aData;
   mSize = aData.mPicSize;
 
   if (gfxPlatform::GetPlatform()->IsInGonkEmulator()) {
     // Emulator does not support HAL_PIXEL_FORMAT_YV12.
     return false;
   }
 
-  RefPtr<ClientIPCAllocator> allocator = ImageBridgeChild::GetSingleton();
+  RefPtr<LayersIPCChannel> allocator = ImageBridgeChild::GetSingleton();
   GrallocTextureData* texData = GrallocTextureData::Create(mData.mYSize, HAL_PIXEL_FORMAT_YV12,
                                                            gfx::BackendType::NONE,
                                                            GraphicBuffer::USAGE_SW_READ_OFTEN |
                                                              GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                                                              GraphicBuffer::USAGE_HW_TEXTURE,
                                                            allocator
   );
 
@@ -464,15 +464,15 @@ GrallocImage::GetNativeBuffer()
   android::sp<android::GraphicBuffer> graphicBuffer = GetGraphicBuffer();
   if (!graphicBuffer.get()) {
     return nullptr;
   }
   return graphicBuffer->getNativeBuffer();
 }
 
 TextureClient*
-GrallocImage::GetTextureClient(TextureForwarder* aForwarder)
+GrallocImage::GetTextureClient(KnowsCompositor* aForwarder)
 {
   return mTextureClient;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -88,17 +88,17 @@ public:
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
 
   android::sp<android::GraphicBuffer> GetGraphicBuffer() const;
 
   void* GetNativeBuffer();
 
   virtual bool IsValid() { return !!mTextureClient; }
 
-  virtual TextureClient* GetTextureClient(TextureForwarder* aForwarder) override;
+  virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
 
   virtual GrallocImage* AsGrallocImage() override
   {
     return this;
   }
 
   virtual uint8_t* GetBuffer()
   {
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -299,22 +299,27 @@ ClientLayerManager::EndTransactionIntern
   // properties.
   GetRoot()->ApplyPendingUpdatesToSubtree();
 
   mPaintedLayerCallback = aCallback;
   mPaintedLayerCallbackData = aCallbackData;
 
   GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
 
-  if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
-    TimeStamp start = TimeStamp::Now();
-    root->RenderLayer();
-    mLastPaintTime = TimeStamp::Now() - start;
+  // Skip the painting if the device is in device-reset status.
+  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+    if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
+      TimeStamp start = TimeStamp::Now();
+      root->RenderLayer();
+      mLastPaintTime = TimeStamp::Now() - start;
+    } else {
+      root->RenderLayer();
+    }
   } else {
-    root->RenderLayer();
+    gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer().";
   }
 
   if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
     GetRoot()->Mutated();
   }
 
   if (!mIsRepeatTransaction) {
     mAnimationReadyTime = TimeStamp::Now();
@@ -621,18 +626,22 @@ ClientLayerManager::StopFrameTimeRecordi
   }
 }
 
 void
 ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
 {
   TimeStamp start = TimeStamp::Now();
 
-  if (mForwarder->GetSyncObject()) {
-    mForwarder->GetSyncObject()->FinalizeFrame();
+  // Skip the synchronization for buffer since we also skip the painting during
+  // device-reset status.
+  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+    if (mForwarder->GetSyncObject()) {
+      mForwarder->GetSyncObject()->FinalizeFrame();
+    }
   }
 
   mPhase = PHASE_FORWARD;
 
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
   TimeStamp transactionStart;
   if (!mTransactionIdAllocator->GetTransactionStart().IsNull()) {
     transactionStart = mTransactionIdAllocator->GetTransactionStart();
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -19,35 +19,24 @@
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/Preferences.h"
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "gfx2DGlue.h"
 #include "ReadbackProcessor.h"
 
-#ifdef XP_WIN
-#include "gfxWindowsPlatform.h"
-#endif
-
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 void
 ClientPaintedLayer::PaintThebes()
 {
-#ifdef XP_WIN
-  if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) {
-    // If our rendering device has reset simply avoid rendering completely.
-    return;
-  }
-#endif
-
   PROFILER_LABEL("ClientPaintedLayer", "PaintThebes",
     js::ProfileEntry::Category::GRAPHICS);
 
   NS_ASSERTION(ClientManager()->InDrawing(),
                "Can only draw in drawing phase");
   
   uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -1127,17 +1127,17 @@ TextureClient::CreateForDrawing(TextureF
       gl::sGLXLibrary.UseTextureFromPixmap())
   {
     data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
   }
 #endif
 #endif
 
 #ifdef MOZ_WIDGET_GONK
-  if (!data) {
+  if (!data && aSize.width <= aMaxTextureSize && aSize.height <= aMaxTextureSize) {
     data = GrallocTextureData::CreateForDrawing(aSize, aFormat, moz2DBackend,
                                                 aAllocator);
   }
 #endif
 
 #ifdef XP_MACOSX
   if (!data && gfxPrefs::UseIOSurfaceTextures()) {
     data = MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -16,16 +16,17 @@
 #include "mozilla/RefPtr.h"             // for RefPtr, RefCounted
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/layers/FenceUtils.h"  // for FenceHandle
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
+#include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "mozilla/gfx/CriticalSection.h"
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for TextureImage::AddRef, etc
 #include "GfxTexturesReporter.h"
 #include "pratom.h"
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -330,19 +330,19 @@ ImageBridgeChild::NotifyNotUsedToNonRecy
 
   MOZ_ASSERT(aTextureId == client->GetSerial());
   client->ClearWaitFenceHandleOnImageBridge(mWaitingFenceHandleMutex);
   mTexturesWaitingFenceHandle.Remove(aTextureId);
 
   // Release TextureClient on allocator's message loop.
   RefPtr<TextureClientReleaseTask> task =
     MakeAndAddRef<TextureClientReleaseTask>(client);
-  RefPtr<ClientIPCAllocator> allocator = client->GetAllocator();
+  RefPtr<LayersIPCChannel> allocator = client->GetAllocator();
   client = nullptr;
-  allocator->AsClientAllocator()->GetMessageLoop()->PostTask(task.forget());
+  allocator->GetMessageLoop()->PostTask(task.forget());
 #else
   NS_RUNTIMEABORT("not reached");
 #endif
 }
 
 void
 ImageBridgeChild::CancelWaitFenceHandle(TextureClient* aClient)
 {
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_WIDGET_GONK
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
 #include "mozilla/layers/GrallocTextureClient.h"
-#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/TextureForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h" // for gfxPrefs
 #include "SharedSurfaceGralloc.h"
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
@@ -290,20 +290,16 @@ GrallocTextureData::UpdateFromSurface(gf
 GrallocTextureData*
 GrallocTextureData::Create(gfx::IntSize aSize, AndroidFormat aAndroidFormat,
                            gfx::BackendType aMoz2dBackend, uint32_t aUsage,
                            LayersIPCChannel* aAllocator)
 {
   if (!aAllocator || !aAllocator->IPCOpen()) {
     return nullptr;
   }
-  int32_t maxSize = aAllocator->AsClientAllocator()->GetMaxTextureSize();
-  if (aSize.width > maxSize || aSize.height > maxSize) {
-    return nullptr;
-  }
   gfx::SurfaceFormat format;
   switch (aAndroidFormat) {
   case android::PIXEL_FORMAT_RGBA_8888:
     format = gfx::SurfaceFormat::B8G8R8A8;
     break;
   case android::PIXEL_FORMAT_BGRA_8888:
     format = gfx::SurfaceFormat::B8G8R8A8;
     break;
@@ -442,16 +438,17 @@ GrallocTextureData::TextureClientFromSha
                   (uint32_t)required);
     MOZ_CRASH("Flag requirement mismatch.");
   }
   return ret.forget();
 }
 
 TextureData*
 GrallocTextureData::CreateSimilar(LayersIPCChannel* aAllocator,
+                                  LayersBackend aLayersBackend,
                                   TextureFlags aFlags,
                                   TextureAllocationFlags aAllocFlags) const
 {
   if (mFormat == gfx::SurfaceFormat::YUV) {
     return GrallocTextureData::CreateForYCbCr(mSize, mSize*2, aAllocator);
   } else {
     return GrallocTextureData::CreateForDrawing(mSize, mFormat, mMoz2DBackend, aAllocator);
   }
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -70,16 +70,17 @@ public:
                                     LayersIPCChannel* aAllocator);
 
 
   static already_AddRefed<TextureClient>
   TextureClientFromSharedSurface(gl::SharedSurface* abstractSurf, TextureFlags flags);
 
   virtual TextureData*
   CreateSimilar(LayersIPCChannel* aAllocator,
+                LayersBackend aLayersBackend,
                 TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
 
   // use TextureClient's default implementation
   virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
 
   /// Hold android::MediaBuffer.
   /// MediaBuffer needs to be add refed to keep MediaBuffer alive while the texture
--- a/gfx/src/X11Util.cpp
+++ b/gfx/src/X11Util.cpp
@@ -52,23 +52,25 @@ ScopedXErrorHandler::ErrorHandler(Displa
 {
     // only record the error if no error was previously recorded.
     // this means that in case of multiple errors, it's the first error that we report.
     if (!sXErrorPtr->mError.error_code)
       sXErrorPtr->mError = *ev;
     return 0;
 }
 
-ScopedXErrorHandler::ScopedXErrorHandler()
+ScopedXErrorHandler::ScopedXErrorHandler(bool aAllowOffMainThread)
 {
-    // Off main thread usage is not safe in general, but OMTC GL layers uses this
-    // with the main thread blocked, which makes it safe.
-    NS_WARNING_ASSERTION(
+    if (!aAllowOffMainThread) {
+      // Off main thread usage is not safe in general, but OMTC GL layers uses this
+      // with the main thread blocked, which makes it safe.
+      NS_WARNING_ASSERTION(
         NS_IsMainThread(),
         "ScopedXErrorHandler being called off main thread, may cause issues");
+    }
     // let sXErrorPtr point to this object's mXError object, but don't reset this mXError object!
     // think of the case of nested ScopedXErrorHandler's.
     mOldXErrorPtr = sXErrorPtr;
     sXErrorPtr = &mXError;
     mOldErrorHandler = XSetErrorHandler(ErrorHandler);
 }
 
 ScopedXErrorHandler::~ScopedXErrorHandler()
--- a/gfx/src/X11Util.h
+++ b/gfx/src/X11Util.h
@@ -113,24 +113,36 @@ private:
     // what to restore the error handler to on destruction
     int (*mOldErrorHandler)(Display *, XErrorEvent *);
 
 public:
 
     static int
     ErrorHandler(Display *, XErrorEvent *ev);
 
-    ScopedXErrorHandler();
+    /**
+     * @param aAllowOffMainThread whether to warn if used off main thread
+     */
+    explicit ScopedXErrorHandler(bool aAllowOffMainThread = false);
 
     ~ScopedXErrorHandler();
 
     /** \returns true if a X error occurred since the last time this method was called on this ScopedXErrorHandler object,
      *           or since the creation of this ScopedXErrorHandler object if this method was never called on it.
      *
      * \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred,
      *           the first one will be returned.
      */
     bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr);
 };
 
+class OffMainThreadScopedXErrorHandler : public ScopedXErrorHandler
+{
+public:
+  OffMainThreadScopedXErrorHandler()
+    : ScopedXErrorHandler(true)
+  {
+  }
+};
+
 } // namespace mozilla
 
 #endif  // mozilla_X11Util_h
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -166,17 +166,17 @@ gfxASurface::Wrap (cairo_surface_t *csur
     }
 #endif
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
     else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
         result = new gfxQuartzSurface(csurf, aSize);
     }
 #endif
     else {
-        MOZ_CRASH("Unknown cairo surface type");
+        result = new gfxUnknownSurface(csurf, aSize);
     }
 
     // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result);
 
     return result.forget();
 }
 
 void
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -178,9 +178,27 @@ private:
 
     int32_t mFloatingRefs;
     int32_t mBytesRecorded;
 
 protected:
     bool mSurfaceValid;
 };
 
+/**
+ * An Unknown surface; used to wrap unknown cairo_surface_t returns from cairo
+ */
+class gfxUnknownSurface : public gfxASurface {
+public:
+    gfxUnknownSurface(cairo_surface_t *surf, const mozilla::gfx::IntSize& aSize)
+        : mSize(aSize)
+    {
+        Init(surf, true);
+    }
+
+    virtual ~gfxUnknownSurface() { }
+    virtual const mozilla::gfx::IntSize GetSize() const override { return mSize; }
+
+private:
+    mozilla::gfx::IntSize mSize;
+};
+
 #endif /* GFX_ASURFACE_H */
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2093,23 +2093,25 @@ static mozilla::Atomic<bool> sLayersSupp
 static bool sLayersHardwareVideoDecodingFailed = false;
 static bool sBufferRotationCheckPref = true;
 
 static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
 
 void VideoDecodingFailedChangedCallback(const char* aPref, void*)
 {
   sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false);
-  gfxPlatform::GetPlatform()->UpdateCanUseHardareVideoDecoding();
+  gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding();
 }
 
 void
-gfxPlatform::UpdateCanUseHardareVideoDecoding()
+gfxPlatform::UpdateCanUseHardwareVideoDecoding()
 {
-  gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
+  if (XRE_IsParentProcess()) {
+    gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
+  }
 }
 
 void
 gfxPlatform::InitAcceleration()
 {
   if (sLayersAccelerationPrefsInitialized) {
     return;
   }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -451,17 +451,17 @@ public:
         // platform-specific override, by default do nothing
     }
 
     // Are we in safe mode?
     static bool InSafeMode();
 
     static bool OffMainThreadCompositingEnabled();
 
-    void UpdateCanUseHardareVideoDecoding();
+    void UpdateCanUseHardwareVideoDecoding();
 
     // Returns a prioritized list of all available compositor backends.
     void GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends);
 
     /**
      * Is it possible to use buffer rotation.  Note that these
      * check the preference, but also allow for the override to
      * disable it using DisableBufferRotation.
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -360,16 +360,20 @@ gfxWindowsPlatform::InitAcceleration()
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
 
   DeviceManagerDx::Init();
   DeviceManagerD3D9::Init();
 
+  // CanUseHardwareVideoDecoding depends on DeviceManagerDx state,
+  // so update the cached value now.
+  UpdateCanUseHardwareVideoDecoding();
+
   InitializeConfig();
   InitializeDevices();
   UpdateANGLEConfig();
   UpdateRenderMode();
 
   // If we have Skia and we didn't init dwrite already, do it now.
   if (!mDWriteFactory && GetDefaultContentBackend() == BackendType::SKIA) {
     InitDWriteSupport();
@@ -2025,17 +2029,17 @@ gfxWindowsPlatform::ImportGPUDeviceData(
         FeatureStatus::Unavailable,
         "Direct2D requires Direct3D 11 compositing",
         NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
     }
   }
 
   // CanUseHardwareVideoDecoding depends on d3d11 state, so update
   // the cached value now.
-  UpdateCanUseHardareVideoDecoding();
+  UpdateCanUseHardwareVideoDecoding();
 
   // For completeness (and messaging in about:support). Content recomputes this
   // on its own, and we won't use ANGLE in the UI process if we're using a GPU
   // process.
   UpdateANGLEConfig();
 }
 
 void
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -602,16 +602,29 @@ ShouldLoadCachedImage(imgRequest* aImgRe
                                              aLoadingPrincipal,
                                              &decision);
       if (NS_FAILED(rv) || !NS_CP_ACCEPTED(decision)) {
         return false;
       }
     }
   }
 
+  bool sendPriming = false;
+  bool mixedContentWouldBlock = false;
+  rv = nsMixedContentBlocker::GetHSTSPrimingFromRequestingContext(contentLocation,
+      aLoadingContext, &sendPriming, &mixedContentWouldBlock);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  if (sendPriming && mixedContentWouldBlock) {
+    // if either of the securty checks above would cause a priming request, we
+    // can't load this image from the cache, so go ahead and return false here
+    return false;
+  }
+
   return true;
 }
 
 // Returns true if this request is compatible with the given CORS mode on the
 // given loading principal, and false if the request may not be reused due
 // to CORS.  Also checks the Referrer Policy, since requests with different
 // referrers/policies may generate different responses.
 static bool
@@ -711,20 +724,16 @@ NewImageChannel(nsIChannel** aResult,
     : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
   if (aCORSMode == imgIRequest::CORS_ANONYMOUS) {
     securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
   } else if (aCORSMode == imgIRequest::CORS_USE_CREDENTIALS) {
     securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
   }
   securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
 
-  if (aRespectPrivacy) {
-    securityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING;
-  }
-
   // Note we are calling NS_NewChannelWithTriggeringPrincipal() here with a
   // node and a principal. This is for things like background images that are
   // specified by user stylesheets, where the document is being styled, but
   // the principal is that of the user stylesheet.
   if (requestingNode && aLoadingPrincipal) {
     rv = NS_NewChannelWithTriggeringPrincipal(aResult,
                                               aURI,
                                               requestingNode,
@@ -745,16 +754,32 @@ NewImageChannel(nsIChannel** aResult,
     rv = NS_NewChannel(aResult,
                        aURI,
                        nsContentUtils::GetSystemPrincipal(),
                        securityFlags,
                        aPolicyType,
                        nullptr,   // loadGroup
                        callbacks,
                        aLoadFlags);
+
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    // Use the OriginAttributes from the loading principal, if one is available,
+    // and adjust the private browsing ID based on what kind of load the caller
+    // has asked us to perform.
+    NeckoOriginAttributes neckoAttrs;
+    if (aLoadingPrincipal) {
+      neckoAttrs.InheritFromDocToNecko(BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef());
+    }
+    neckoAttrs.mPrivateBrowsingId = aRespectPrivacy ? 1 : 0;
+
+    nsCOMPtr<nsILoadInfo> loadInfo = (*aResult)->GetLoadInfo();
+    rv = loadInfo->SetOriginAttributes(neckoAttrs);
   }
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // only inherit if we have a principal
   *aForcePrincipalCheckForCacheEntry =
--- a/image/imgLoader.h
+++ b/image/imgLoader.h
@@ -250,19 +250,16 @@ public:
    * Get the normal image loader instance that is used by gecko code, creating
    * it if necessary.
    */
   static imgLoader* NormalLoader();
 
   /**
    * Get the Private Browsing image loader instance that is used by gecko code,
    * creating it if necessary.
-   *
-   * The nsIChannel objects that this instance creates are created with the
-   * nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING flag.
    */
   static imgLoader* PrivateBrowsingLoader();
 
   /**
    * Gecko code should use NormalLoader() or PrivateBrowsingLoader() to get the
    * appropriate image loader.
    *
    * This constructor is public because the XPCOM module code that creates
--- a/image/test/unit/test_private_channel.js
+++ b/image/test/unit/test_private_channel.js
@@ -28,44 +28,47 @@ function imageHandler(metadata, response
   var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
   response.bodyOutputStream.write(body, body.length);
 }
 
 var requests = [];
 var listeners = [];
 
 function NotificationCallbacks(isPrivate) {
+  this.originAttributes.privateBrowsingId = isPrivate ? 1 : 0;
   this.usePrivateBrowsing = isPrivate;
 }
 
 NotificationCallbacks.prototype = {
   QueryInterface: function (iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsILoadContext))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
   getInterface: function(iid) {
     if (iid.equals(Ci.nsILoadContext))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
-  originAttributes: {}
+  originAttributes: {
+    privateBrowsingId: 0
+  }
 };
 
 var gImgPath = 'http://localhost:' + server.identity.primaryPort + '/image.png';
 
 function setup_chan(path, isPrivate, callback) {
   var uri = NetUtil.newURI(gImgPath);
   var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
-  if (isPrivate) {
-    securityFlags |= Ci.nsILoadInfo.SEC_FORCE_PRIVATE_BROWSING;
-  }
-  var chan =  NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true,
-                                  securityFlags: securityFlags});
+  var principal = Services.scriptSecurityManager
+                          .createCodebasePrincipal(uri, {privateBrowsingId: isPrivate ? 1 : 0});
+  var chan =  NetUtil.newChannel({uri: uri, loadingPrincipal: principal,
+                                  securityFlags: securityFlags,
+                                  contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE});
   chan.notificationCallbacks = new NotificationCallbacks(isPrivate);
   var channelListener = new ChannelListener();
   chan.asyncOpen2(channelListener);
 
   var listener = new ImageListener(null, callback);
   var outlistener = {};
   var loader = isPrivate ? gPrivateLoader : gPublicLoader;
   var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -261,17 +261,19 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
       aLoadInfo->GetEnforceSecurity(),
       aLoadInfo->GetInitialSecurityCheckDone(),
       aLoadInfo->GetIsInThirdPartyContext(),
       aLoadInfo->GetOriginAttributes(),
       redirectChainIncludingInternalRedirects,
       redirectChain,
       aLoadInfo->CorsUnsafeHeaders(),
       aLoadInfo->GetForcePreflight(),
-      aLoadInfo->GetIsPreflight());
+      aLoadInfo->GetIsPreflight(),
+      aLoadInfo->GetForceHSTSPriming(),
+      aLoadInfo->GetMixedContentWouldBlock());
 
   return NS_OK;
 }
 
 nsresult
 LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
                        nsILoadInfo** outLoadInfo)
 {
@@ -333,16 +335,19 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
                           loadInfoArgs.enforceSecurity(),
                           loadInfoArgs.initialSecurityCheckDone(),
                           loadInfoArgs.isInThirdPartyContext(),
                           loadInfoArgs.originAttributes(),
                           redirectChainIncludingInternalRedirects,
                           redirectChain,
                           loadInfoArgs.corsUnsafeHeaders(),
                           loadInfoArgs.forcePreflight(),
-                          loadInfoArgs.isPreflight());
+                          loadInfoArgs.isPreflight(),
+                          loadInfoArgs.forceHSTSPriming(),
+                          loadInfoArgs.mixedContentWouldBlock()
+                          );
 
    loadInfo.forget(outLoadInfo);
    return NS_OK;
 }
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -479,27 +479,27 @@ MessageChannel::MessageChannel(MessageLi
     mInTimeoutSecondHalf(false),
     mNextSeqno(0),
     mLastSendError(SyncSendError::SendSuccess),
     mDispatchingAsyncMessage(false),
     mDispatchingAsyncMessagePriority(0),
     mTransactionStack(nullptr),
     mTimedOutMessageSeqno(0),
     mTimedOutMessagePriority(0),
+#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN)
+    mPending(AnnotateAllocator<Message>(*this)),
+#endif
     mRemoteStackDepthGuess(false),
     mSawInterruptOutMsg(false),
     mIsWaitingForIncoming(false),
     mAbortOnError(false),
     mNotifiedChannelDone(false),
     mFlags(REQUIRE_DEFAULT),
     mPeerPidSet(false),
     mPeerPid(-1)
-#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN)
-    , mPending(AnnotateAllocator<Message>(*this))
-#endif
 {
     MOZ_COUNT_CTOR(ipc::MessageChannel);
 
 #ifdef OS_WIN
     mTopFrame = nullptr;
     mIsSyncWaitingOnNonMainThread = false;
 #endif
 
--- a/ipc/mscom/MainThreadInvoker.cpp
+++ b/ipc/mscom/MainThreadInvoker.cpp
@@ -9,18 +9,17 @@
 #include "GeckoProfiler.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/HangMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "private/prpriv.h" // For PR_GetThreadID
-
-#include <winternl.h> // For NTSTATUS and NTAPI
+#include "WinUtils.h"
 
 namespace {
 
 class SyncRunnable : public mozilla::Runnable
 {
 public:
   SyncRunnable(HANDLE aEvent, already_AddRefed<nsIRunnable>&& aRunnable)
     : mDoneEvent(aEvent)
@@ -37,60 +36,43 @@ public:
     return NS_OK;
   }
 
 private:
   HANDLE                mDoneEvent;
   nsCOMPtr<nsIRunnable> mRunnable;
 };
 
-typedef NTSTATUS (NTAPI* NtTestAlertPtr)(VOID);
-
 } // anonymous namespace
 
 namespace mozilla {
 namespace mscom {
 
 HANDLE MainThreadInvoker::sMainThread = nullptr;
-StaticRefPtr<nsIRunnable> MainThreadInvoker::sAlertRunnable;
 
 /* static */ bool
 MainThreadInvoker::InitStatics()
 {
   nsCOMPtr<nsIThread> mainThread;
   nsresult rv = ::NS_GetMainThread(getter_AddRefs(mainThread));
   if (NS_FAILED(rv)) {
     return false;
   }
   PRThread* mainPrThread = nullptr;
   rv = mainThread->GetPRThread(&mainPrThread);
   if (NS_FAILED(rv)) {
     return false;
   }
   PRUint32 tid = ::PR_GetThreadID(mainPrThread);
   sMainThread = ::OpenThread(SYNCHRONIZE | THREAD_SET_CONTEXT, FALSE, tid);
-  if (!sMainThread) {
-    return false;
-  }
-  NtTestAlertPtr NtTestAlert =
-    reinterpret_cast<NtTestAlertPtr>(
-        ::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtTestAlert"));
-  sAlertRunnable = ::NS_NewRunnableFunction([NtTestAlert]() -> void {
-    // We're using NtTestAlert() instead of SleepEx() so that the main thread
-    // never gives up its quantum if there are no APCs pending.
-    NtTestAlert();
-  }).take();
-  if (sAlertRunnable) {
-    ClearOnShutdown(&sAlertRunnable);
-  }
-  return !!sAlertRunnable;
+  return !!sMainThread;
 }
 
 MainThreadInvoker::MainThreadInvoker()
-  : mDoneEvent(::CreateEvent(nullptr, FALSE, FALSE, nullptr))
+  : mDoneEvent(::CreateEventW(nullptr, FALSE, FALSE, nullptr))
 {
   static const bool gotStatics = InitStatics();
   MOZ_ASSERT(gotStatics);
 }
 
 MainThreadInvoker::~MainThreadInvoker()
 {
   if (mDoneEvent) {
@@ -124,21 +106,21 @@ MainThreadInvoker::Invoke(already_AddRef
   // Make sure that wrappedRunnable remains valid while sitting in the APC queue
   wrappedRunnable->AddRef();
   if (!::QueueUserAPC(&MainThreadAPC, sMainThread,
                       reinterpret_cast<UINT_PTR>(wrappedRunnable.get()))) {
     // Enqueue failed so cancel the above AddRef
     wrappedRunnable->Release();
     return false;
   }
-  // We should enqueue a call to NtTestAlert() so that the main thread will
-  // check for APCs during event processing. If we omit this then the main
-  // thread will not check its APC queue until it is idle. Note that failing to
-  // dispatch this event is non-fatal, but it will delay execution of the APC.
-  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(sAlertRunnable)));
+  // We should ensure a call to NtTestAlert() is made on the main thread so
+  // that the main thread will check for APCs during event processing. If we
+  // omit this then the main thread will not check its APC queue until it is
+  // idle.
+  widget::WinUtils::SetAPCPending();
   return WaitForCompletion(aTimeout);
 }
 
 /* static */ VOID CALLBACK
 MainThreadInvoker::MainThreadAPC(ULONG_PTR aParam)
 {
   GeckoProfilerWakeRAII wakeProfiler;
   mozilla::HangMonitor::NotifyActivity(mozilla::HangMonitor::kGeneralActivity);
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -83,24 +83,27 @@ endif
 endif
 
 check-style::
 	(cd $(srcdir) && $(PYTHON) $(topsrcdir)/config/check_spidermonkey_style.py);
 
 check-masm::
 	(cd $(srcdir) && $(PYTHON) $(topsrcdir)/config/check_macroassembler_style.py);
 
+check-js-msg::
+	(cd $(topsrcdir) && $(PYTHON) $(topsrcdir)/config/check_js_msg_encoding.py);
+
 check-jit-test::
 	$(JITTEST_SANITIZER_ENV) $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
 	        --no-slow --no-progress --format=automation --jitflags=all \
 			$(JITTEST_VALGRIND_FLAG) \
 			$(JITTEST_EXTRA_ARGS) \
 	        $(DIST)/bin/$(JS_SHELL_NAME)$(BIN_SUFFIX) $(JITTEST_TEST_ARGS)
 
-check:: check-style check-masm
+check:: check-style check-masm check-js-msg
 
 check-jstests:
 	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/tests/jstests.py \
 		--no-progress --format=automation --timeout 300 \
 		$(JSTESTS_EXTRA_ARGS) \
 		$(DIST)/bin/$(JS_SHELL_NAME)$(BIN_SUFFIX)
 
 # FIXME:
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -1573,19 +1573,19 @@ WebAssembly_validate(JSContext* cx, unsi
     // If the reason for validation failure was OOM (signalled by null error
     // message), report out-of-memory so that validate's return is always
     // correct.
     if (!validated && !error) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    if (error) {
-        JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
-                                     JSMSG_WASM_COMPILE_ERROR, error.get());
+    if (error && !JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
+                                               JSMSG_WASM_COMPILE_ERROR, error.get())) {
+        return false;
     }
 
     callArgs.rval().setBoolean(validated);
     return true;
 }
 
 static const JSFunctionSpec WebAssembly_static_methods[] =
 {
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -249,17 +249,17 @@ class NodeBuilder
     RootedValue userv;                 /* user-specified builder object or null */
 
   public:
     NodeBuilder(JSContext* c, bool l, char const* s)
       : cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c), callbacks(cx),
           userv(c)
     {}
 
-    bool init(HandleObject userobj = nullptr) {
+    MOZ_MUST_USE bool init(HandleObject userobj = nullptr) {
         if (src) {
             if (!atomValue(src, &srcval))
                 return false;
         } else {
             srcval.setNull();
         }
 
         if (!userobj) {
@@ -300,99 +300,99 @@ class NodeBuilder
         return true;
     }
 
     void setTokenStream(TokenStream* ts) {
         tokenStream = ts;
     }
 
   private:
-    bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i,
-                        TokenPos* pos, MutableHandleValue dst)
+    MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i,
+                                     TokenPos* pos, MutableHandleValue dst)
     {
         // The end of the implementation of callback(). All arguments except
         // loc have already been stored in range [0, i).
         if (saveLoc) {
             if (!newNodeLoc(pos, args[i]))
                 return false;
         }
 
         return js::Call(cx, fun, userv, args, dst);
     }
 
     // Helper function for callback(). Note that all Arguments must be types
     // that convert to HandleValue, so this isn't as template-y as it seems,
     // just variadic.
     template <typename... Arguments>
-    bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i,
-                        HandleValue head, Arguments&&... tail)
+    MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i,
+                                     HandleValue head, Arguments&&... tail)
     {
         // Recursive loop to store the arguments into args. This eventually
         // bottoms out in a call to the non-template callbackHelper() above.
         args[i].set(head);
         return callbackHelper(fun, args, i + 1, Forward<Arguments>(tail)...);
     }
 
     // Invoke a user-defined callback. The actual signature is:
     //
     //     bool callback(HandleValue fun, HandleValue... args, TokenPos* pos,
     //                   MutableHandleValue dst);
     template <typename... Arguments>
-    bool callback(HandleValue fun, Arguments&&... args) {
+    MOZ_MUST_USE bool callback(HandleValue fun, Arguments&&... args) {
         InvokeArgs iargs(cx);
         if (!iargs.init(sizeof...(args) - 2 + size_t(saveLoc)))
             return false;
 
         return callbackHelper(fun, iargs, 0, Forward<Arguments>(args)...);
     }
 
     // WARNING: Returning a Handle is non-standard, but it works in this case
     // because both |v| and |UndefinedHandleValue| are definitely rooted on a
     // previous stack frame (i.e. we're just choosing between two
     // already-rooted values).
     HandleValue opt(HandleValue v) {
         MOZ_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
         return v.isMagic(JS_SERIALIZE_NO_NODE) ? JS::UndefinedHandleValue : v;
     }
 
-    bool atomValue(const char* s, MutableHandleValue dst) {
+    MOZ_MUST_USE bool atomValue(const char* s, MutableHandleValue dst) {
         /*
          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
          */
         RootedAtom atom(cx, Atomize(cx, s, strlen(s)));
         if (!atom)
             return false;
 
         dst.setString(atom);
         return true;
     }
 
-    bool newObject(MutableHandleObject dst) {
+    MOZ_MUST_USE bool newObject(MutableHandleObject dst) {
         RootedPlainObject nobj(cx, NewBuiltinClassInstance<PlainObject>(cx));
         if (!nobj)
             return false;
 
         dst.set(nobj);
         return true;
     }
 
-    bool newArray(NodeVector& elts, MutableHandleValue dst);
-
-    bool createNode(ASTType type, TokenPos* pos, MutableHandleObject dst);
-
-    bool newNodeHelper(HandleObject obj, MutableHandleValue dst) {
+    MOZ_MUST_USE bool newArray(NodeVector& elts, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool createNode(ASTType type, TokenPos* pos, MutableHandleObject dst);
+
+    MOZ_MUST_USE bool newNodeHelper(HandleObject obj, MutableHandleValue dst) {
         // The end of the implementation of newNode().
         MOZ_ASSERT(obj);
         dst.setObject(*obj);
         return true;
     }
 
     template <typename... Arguments>
-    bool newNodeHelper(HandleObject obj, const char *name, HandleValue value,
-                       Arguments&&... rest)
+    MOZ_MUST_USE bool newNodeHelper(HandleObject obj, const char *name, HandleValue value,
+                                    Arguments&&... rest)
     {
         // Recursive loop to define properties. Note that the newNodeHelper()
         // call below passes two fewer arguments than we received, as we omit
         // `name` and `value`. This eventually bottoms out in a call to the
         // non-template newNodeHelper() above.
         return defineProperty(obj, name, value)
                && newNodeHelper(obj, Forward<Arguments>(rest)...);
     }
@@ -400,237 +400,245 @@ class NodeBuilder
     // Create a node object with "type" and "loc" properties, as well as zero
     // or more properties passed in as arguments. The signature is really more
     // like:
     //
     //     bool newNode(ASTType type, TokenPos* pos,
     //                  {const char *name0, HandleValue value0,}...
     //                  MutableHandleValue dst);
     template <typename... Arguments>
-    bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) {
+    MOZ_MUST_USE bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) {
         RootedObject node(cx);
         return createNode(type, pos, &node) &&
                newNodeHelper(node, Forward<Arguments>(args)...);
     }
 
-    bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos,
-                  MutableHandleValue dst) {
+    MOZ_MUST_USE bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos,
+                               MutableHandleValue dst) {
         RootedValue array(cx);
         if (!newArray(elts, &array))
             return false;
 
         RootedValue cb(cx, callbacks[type]);
         if (!cb.isNull())
             return callback(cb, array, pos, dst);
 
         return newNode(type, pos, propName, array, dst);
     }
 
-    bool defineProperty(HandleObject obj, const char* name, HandleValue val) {
+    MOZ_MUST_USE bool defineProperty(HandleObject obj, const char* name, HandleValue val) {
         MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
 
         /*
          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
          */
         RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
         if (!atom)
             return false;
 
         /* Represent "no node" as null and ensure users are not exposed to magic values. */
         RootedValue optVal(cx, val.isMagic(JS_SERIALIZE_NO_NODE) ? NullValue() : val);
         return DefineProperty(cx, obj, atom->asPropertyName(), optVal);
     }
 
-    bool newNodeLoc(TokenPos* pos, MutableHandleValue dst);
-
-    bool setNodeLoc(HandleObject node, TokenPos* pos);
+    MOZ_MUST_USE bool newNodeLoc(TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool setNodeLoc(HandleObject node, TokenPos* pos);
 
   public:
     /*
      * All of the public builder methods take as their last two
      * arguments a nullable token position and a non-nullable, rooted
      * outparam.
      *
      * Any Value arguments representing optional subnodes may be a
      * JS_SERIALIZE_NO_NODE magic value.
      */
 
     /*
      * misc nodes
      */
 
-    bool program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool literal(HandleValue val, TokenPos* pos, MutableHandleValue dst);
-
-    bool identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst);
-
-    bool function(ASTType type, TokenPos* pos,
-                  HandleValue id, NodeVector& args, NodeVector& defaults,
-                  HandleValue body, HandleValue rest, GeneratorStyle generatorStyle,
-                  bool isExpression, MutableHandleValue dst);
-
-    bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
-                            MutableHandleValue dst);
-
-    bool switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos,
-                     MutableHandleValue dst);
-
-    bool prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst);
-    bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
-                             bool isMethod, TokenPos* pos, MutableHandleValue dst);
+    MOZ_MUST_USE bool program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool literal(HandleValue val, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool function(ASTType type, TokenPos* pos,
+                               HandleValue id, NodeVector& args, NodeVector& defaults,
+                               HandleValue body, HandleValue rest, GeneratorStyle generatorStyle,
+                               bool isExpression, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
+                                         MutableHandleValue dst);
+
+    MOZ_MUST_USE bool switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos,
+                                  MutableHandleValue dst);
+
+    MOZ_MUST_USE bool prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst);
+    MOZ_MUST_USE bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind,
+                                          bool isShorthand, bool isMethod, TokenPos* pos,
+                                          MutableHandleValue dst);
 
 
     /*
      * statements
      */
 
-    bool blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
-
-    bool emptyStatement(TokenPos* pos, MutableHandleValue dst);
-
-    bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
+    MOZ_MUST_USE bool blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool emptyStatement(TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
                      MutableHandleValue dst);
 
-    bool breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
-
-    bool continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
-
-    bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos,
+    MOZ_MUST_USE bool breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos,
                           MutableHandleValue dst);
 
-    bool throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
-
-    bool returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
-
-    bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
+    MOZ_MUST_USE bool throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
                       TokenPos* pos, MutableHandleValue dst);
 
-    bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
-                        bool isForEach, TokenPos* pos, MutableHandleValue dst);
-
-    bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos,
-                        MutableHandleValue dst);
-
-    bool withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
-
-    bool whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
-
-    bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos,
-                          MutableHandleValue dst);
-
-    bool switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos,
-                         MutableHandleValue dst);
-
-    bool tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded,
-                      HandleValue finally, TokenPos* pos, MutableHandleValue dst);
-
-    bool debuggerStatement(TokenPos* pos, MutableHandleValue dst);
-
-    bool importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst);
-
-    bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos, MutableHandleValue dst);
-
-    bool exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec,
-                           HandleValue isDefault, TokenPos* pos, MutableHandleValue dst);
-
-    bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos, MutableHandleValue dst);
-
-    bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst);
-
-    bool classDefinition(bool expr, HandleValue name, HandleValue heritage, HandleValue block, TokenPos* pos,
-                         MutableHandleValue dst);
-    bool classMethods(NodeVector& methods, MutableHandleValue dst);
-    bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic, TokenPos* pos, MutableHandleValue dst);
+    MOZ_MUST_USE bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
+                                     bool isForEach, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos,
+                                     MutableHandleValue dst);
+
+    MOZ_MUST_USE bool withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos,
+                                       MutableHandleValue dst);
+
+    MOZ_MUST_USE bool switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos,
+                                      MutableHandleValue dst);
+
+    MOZ_MUST_USE bool tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded,
+                                   HandleValue finally, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool debuggerStatement(TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec,
+                                        HandleValue isDefault, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool classDefinition(bool expr, HandleValue name, HandleValue heritage,
+                                      HandleValue block, TokenPos* pos, MutableHandleValue dst);
+    MOZ_MUST_USE bool classMethods(NodeVector& methods, MutableHandleValue dst);
+    MOZ_MUST_USE bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic,
+                                  TokenPos* pos, MutableHandleValue dst);
 
     /*
      * expressions
      */
 
-    bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos* pos,
-                          MutableHandleValue dst);
-
-    bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos* pos, MutableHandleValue dst);
-
-    bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
-                              TokenPos* pos, MutableHandleValue dst);
-
-    bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
-                          MutableHandleValue dst);
-
-    bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
-                           MutableHandleValue dst);
-
-    bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
-                               MutableHandleValue dst);
-
-    bool sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool newExpression(HandleValue callee, NodeVector& args, TokenPos* pos, MutableHandleValue dst);
-
-    bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
-                        MutableHandleValue dst);
-
-    bool memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos* pos,
-                          MutableHandleValue dst);
-
-    bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos,
-                        MutableHandleValue dst);
-
-    bool callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos, MutableHandleValue dst);
-
-    bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
-
-    bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst);
-
-    bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool thisExpression(TokenPos* pos, MutableHandleValue dst);
-
-    bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos, MutableHandleValue dst);
-
-    bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos* pos,
-                            MutableHandleValue dst);
-    bool comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst);
-
-    bool comprehensionExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
-                                 bool isLegacy, TokenPos* pos, MutableHandleValue dst);
-
-    bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
-                             bool isLegacy, TokenPos* pos, MutableHandleValue dst);
-
-    bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst);
-
-    bool super(TokenPos* pos, MutableHandleValue dst);
+    MOZ_MUST_USE bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right,
+                                       TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos* pos,
+                                      MutableHandleValue dst);
+
+    MOZ_MUST_USE bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
+                                           TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
+                                       MutableHandleValue dst);
+
+    MOZ_MUST_USE bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
+                                        MutableHandleValue dst);
+
+    MOZ_MUST_USE bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
+                                            TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool newExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
+                                    MutableHandleValue dst);
+
+    MOZ_MUST_USE bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
+                                     MutableHandleValue dst);
+
+    MOZ_MUST_USE bool memberExpression(bool computed, HandleValue expr, HandleValue member,
+                                       TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos,
+                                     MutableHandleValue dst);
+
+    MOZ_MUST_USE bool callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos,
+                                  MutableHandleValue dst);
+
+    MOZ_MUST_USE bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool thisExpression(TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos,
+                                      MutableHandleValue dst);
+
+    MOZ_MUST_USE bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach,
+                                         bool isForOf, TokenPos* pos, MutableHandleValue dst);
+    MOZ_MUST_USE bool comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool comprehensionExpression(HandleValue body, NodeVector& blocks,
+                                              HandleValue filter, bool isLegacy, TokenPos* pos,
+                                              MutableHandleValue dst);
+
+    MOZ_MUST_USE bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
+                                          bool isLegacy, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos,
+                                   MutableHandleValue dst);
+
+    MOZ_MUST_USE bool super(TokenPos* pos, MutableHandleValue dst);
 
     /*
      * declarations
      */
 
-    bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
-                             MutableHandleValue dst);
+    MOZ_MUST_USE bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
+                                          MutableHandleValue dst);
 
     /*
      * patterns
      */
 
-    bool arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
-
-    bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos* pos,
-                         MutableHandleValue dst);
+    MOZ_MUST_USE bool arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
+
+    MOZ_MUST_USE bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand,
+                                      TokenPos* pos, MutableHandleValue dst);
 };
 
 } /* anonymous namespace */
 
 bool
 NodeBuilder::createNode(ASTType type, TokenPos* pos, MutableHandleObject dst)
 {
     MOZ_ASSERT(type > AST_ERROR && type < AST_LIMIT);
@@ -729,18 +737,17 @@ NodeBuilder::newNodeLoc(TokenPos* pos, M
     return true;
 }
 
 bool
 NodeBuilder::setNodeLoc(HandleObject node, TokenPos* pos)
 {
     if (!saveLoc) {
         RootedValue nullVal(cx, NullValue());
-        defineProperty(node, "loc", nullVal);
-        return true;
+        return defineProperty(node, "loc", nullVal);
     }
 
     RootedValue loc(cx);
     return newNodeLoc(pos, &loc) &&
            defineProperty(node, "loc", loc);
 }
 
 bool
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1305220.js
@@ -0,0 +1,23 @@
+// |jit-test| allow-oom
+if (!('oomAfterAllocations' in this))
+    quit();
+s = newGlobal();
+evalcx("\
+    gczeal(10, 2);\
+    k = {\
+        [Symbol]() {}\
+    };\
+", s);
+gczeal(0);
+evalcx("\
+    var g = newGlobal();\
+    b = new Debugger;\
+    g.h = function() {\
+        g.oomAfterAllocations(1);\
+    };\
+    g.eval(\"\" + function f() g());\
+    g.eval(\"\" + function g() h());\
+    g.eval(\"(\" + function() {\
+        f();\
+    } + \")()\");\
+", s);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1296667.js
@@ -0,0 +1,11 @@
+args = ""
+for (i = 0; i < 2000; i++) {
+    args += "arg" + i;
+    if (i != 1999) args += ",";
+}
+MyFunc = MyObject = Function(args, "for (var i = 0; i < MyFunc.length; i++ )   break; eval('this.arg'+i +'=arg'+i) ");
+new function TestCase() {
+    if (inIon())
+        return;
+    TestCase(eval("var EXP_1 = new MyObject; var EXP_2 = new MyObject; EXP_1 - EXP_2"));
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1298354.js
@@ -0,0 +1,17 @@
+// |jit-test| error: ReferenceError
+
+new Function(`
+  while (true) {
+    try {
+        var buf = new Uint8ClampedArray(a);
+    } catch (e) {
+        break;
+    }
+  }
+  var caughtInvalidArguments = false;
+  while (true) {
+    var a = inIon() ? -true.get : 0;
+    while (x > 7 & 0) {}
+  }
+`)();
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1299007.js
@@ -0,0 +1,41 @@
+
+evalInFrame = function(global) {
+   dbgGlobal = newGlobal()
+   dbg = new dbgGlobal.Debugger
+   return function(upCount, code) {
+       dbg.addDebuggee(global)
+       var frame = dbg.getNewestFrame().older
+       for (var i = 0; i < upCount; i++)
+           if (!frame) frame = older
+       completion = frame.eval(code)
+   }
+}(this);
+function h() {
+    evalInFrame(0, "")
+    evalInFrame(0, "i")
+    evalInFrame(0, "a.push")
+    evalInFrame(1, "a.pushy")
+}
+function g() h()
+function f() g()
+f()
+evaluate(`
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+g()
+h()
+`);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/validate.js
@@ -0,0 +1,33 @@
+// |jit-test| test-also-wasm-baseline
+load(libdir + "wasm.js");
+
+const { validate } = WebAssembly;
+
+assertErrorMessage(() => validate(), Error, /requires more than 0 arguments/);
+
+const argError = /first argument must be an ArrayBuffer or typed array object/;
+assertErrorMessage(() => validate(null), Error, argError);
+assertErrorMessage(() => validate(true), Error, argError);
+assertErrorMessage(() => validate(42), Error, argError);
+assertErrorMessage(() => validate(NaN), Error, argError);
+assertErrorMessage(() => validate('yo'), Error, argError);
+assertErrorMessage(() => validate([]), Error, argError);
+assertErrorMessage(() => validate({}), Error, argError);
+assertErrorMessage(() => validate(Symbol.iterator), Error, argError);
+assertErrorMessage(() => validate({ valueOf: () => new ArrayBuffer(65536) }), Error, argError);
+
+assertEq(validate(wasmTextToBinary(`(module)`)), true);
+
+assertEq(validate(wasmTextToBinary(`(module (export "run" 0))`)), false);
+assertEq(validate(wasmTextToBinary(`(module (func) (export "run" 0))`)), true);
+
+// Feature-testing proof-of-concept.
+assertEq(validate(wasmTextToBinary(`(module (memory 1) (func (result i32) (current_memory)))`)), true);
+assertEq(validate(wasmTextToBinary(`(module (memory 1) (func (result i32) (grow_memory (i32.const 42))))`)), true);
+
+// Enable warning as errors.
+options("werror");
+assertErrorMessage(() => validate(wasmTextToBinary(`(module (func) (func) (export "a" 2))`)),
+                  WebAssembly.CompileError,
+                  /exported function index out of bounds/);
+options("werror");
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -818,17 +818,18 @@ IonBuilder::build()
     } else {
         JitSpew(JitSpew_IonScripts, "%sompiling script %s:%" PRIuSIZE " (%p) (warmup-counter=%" PRIu32 ", level=%s)",
                 (script()->hasIonScript() ? "Rec" : "C"),
                 script()->filename(), script()->lineno(), (void*)script(),
                 script()->getWarmUpCount(), OptimizationLevelString(optimizationInfo().level()));
     }
 #endif
 
-    initParameters();
+    if (!initParameters())
+        return false;
     initLocals();
 
     // Initialize something for the env chain. We can bail out before the
     // start instruction, but the snapshot is encoded *at* the start
     // instruction, which means generating any code that could load into
     // registers is illegal.
     MInstruction* env = MConstant::New(alloc(), UndefinedValue());
     current->add(env);
@@ -857,17 +858,18 @@ IonBuilder::build()
     current->add(check);
     MResumePoint* entryRpCopy = MResumePoint::Copy(alloc(), current->entryResumePoint());
     if (!entryRpCopy)
         return false;
     check->setResumePoint(entryRpCopy);
 
     // Parameters have been checked to correspond to the typeset, now we unbox
     // what we can in an infallible manner.
-    rewriteParameters();
+    if (!rewriteParameters())
+        return false;
 
     // Check for redeclaration errors for global scripts.
     if (!info().funMaybeLazy() && !info().module() &&
         script()->bodyScope()->is<GlobalScope>() &&
         script()->bodyScope()->as<GlobalScope>().hasBindings())
     {
         MGlobalNameConflictsCheck* redeclCheck = MGlobalNameConflictsCheck::New(alloc());
         current->add(redeclCheck);
@@ -1131,35 +1133,39 @@ IonBuilder::rewriteParameter(uint32_t sl
     // As usual, it would be invalid for v1 to be captured in the initial
     // resume point, rather than v0.
     current->rewriteSlot(slotIdx, actual);
 }
 
 // Apply Type Inference information to parameters early on, unboxing them if
 // they have a definitive type. The actual guards will be emitted by the code
 // generator, explicitly, as part of the function prologue.
-void
+bool
 IonBuilder::rewriteParameters()
 {
     MOZ_ASSERT(info().environmentChainSlot() == 0);
 
     if (!info().funMaybeLazy())
-        return;
+        return true;
 
     for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) {
+        if (!alloc().ensureBallast())
+            return false;
         MDefinition* param = current->getSlot(i);
         rewriteParameter(i, param, param->toParameter()->index());
     }
-}
-
-void
+
+    return true;
+}
+
+bool
 IonBuilder::initParameters()
 {
     if (!info().funMaybeLazy())
-        return;
+        return true;
 
     // If we are doing OSR on a frame which initially executed in the
     // interpreter and didn't accumulate type information, try to use that OSR
     // frame to determine possible initial types for 'this' and parameters.
 
     if (thisTypes->empty() && baselineFrame_) {
         TypeSet::Type type = baselineFrame_->thisType;
         if (type.isSingletonUnchecked())
@@ -1177,20 +1183,24 @@ IonBuilder::initParameters()
             !script_->baselineScript()->modifiesArguments())
         {
             TypeSet::Type type = baselineFrame_->argTypes[i];
             if (type.isSingletonUnchecked())
                 checkNurseryObject(type.singleton());
             types->addType(type, alloc_->lifoAlloc());
         }
 
-        param = MParameter::New(alloc(), i, types);
+        param = MParameter::New(alloc().fallible(), i, types);
+        if (!param)
+            return false;
         current->add(param);
         current->initSlot(info().argSlotUnchecked(i), param);
     }
+
+    return true;
 }
 
 void
 IonBuilder::initLocals()
 {
     // Initialize all frame slots to undefined. Lexical bindings are temporal
     // dead zoned in bytecode.
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -331,20 +331,20 @@ class IonBuilder
     // IonBuilder.cpp, near the definition for this function.
     MOZ_MUST_USE bool resume(MInstruction* ins, jsbytecode* pc, MResumePoint::Mode mode);
     MOZ_MUST_USE bool resumeAt(MInstruction* ins, jsbytecode* pc);
     MOZ_MUST_USE bool resumeAfter(MInstruction* ins);
     MOZ_MUST_USE bool maybeInsertResume();
 
     void insertRecompileCheck();
 
-    void initParameters();
+    MOZ_MUST_USE bool initParameters();
     void initLocals();
     void rewriteParameter(uint32_t slotIdx, MDefinition* param, int32_t argIndex);
-    void rewriteParameters();
+    MOZ_MUST_USE bool rewriteParameters();
     MOZ_MUST_USE bool initEnvironmentChain(MDefinition* callee = nullptr);
     MOZ_MUST_USE bool initArgumentsObject();
     void pushConstant(const Value& v);
 
     MConstant* constant(const Value& v);
     MConstant* constantInt(int32_t i);
     MInstruction* initializedLength(MDefinition* obj, MDefinition* elements,
                                     JSValueType unboxedType);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1862,21 +1862,20 @@ MAtomicIsLockFree::foldsTo(TempAllocator
     MDefinition* input = getOperand(0);
     if (!input->isConstant() || input->type() != MIRType::Int32)
         return this;
 
     int32_t i = input->toConstant()->toInt32();
     return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfree(i)));
 }
 
-MParameter*
-MParameter::New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types)
-{
-    return new(alloc) MParameter(index, types);
-}
+// Define |THIS_SLOT| as part of this translation unit, as it is used to
+// specialized the parameterized |New| function calls introduced by
+// TRIVIAL_NEW_WRAPPERS.
+const int32_t MParameter::THIS_SLOT;
 
 void
 MParameter::printOpcode(GenericPrinter& out) const
 {
     PrintOpcodeName(out, op());
     if (index() == THIS_SLOT)
         out.printf(" THIS_SLOT");
     else
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2660,30 +2660,28 @@ class MCloneLiteral
     INSTRUCTION_HEADER(CloneLiteral)
     TRIVIAL_NEW_WRAPPERS
 };
 
 class MParameter : public MNullaryInstruction
 {
     int32_t index_;
 
-  public:
-    static const int32_t THIS_SLOT = -1;
-
     MParameter(int32_t index, TemporaryTypeSet* types)
       : index_(index)
     {
         setResultType(MIRType::Value);
         setResultTypeSet(types);
     }
 
   public:
     INSTRUCTION_HEADER(Parameter)
-    static MParameter* New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types);
-
+    TRIVIAL_NEW_WRAPPERS
+
+    static const int32_t THIS_SLOT = -1;
     int32_t index() const {
         return index_;
     }
     void printOpcode(GenericPrinter& out) const override;
 
     HashNumber valueHash() const override;
     bool congruentTo(const MDefinition* ins) const override;
 };
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2341,16 +2341,20 @@ RangeAnalysis::addRangeAssertions()
 
     // Check the computed range for this instruction, if the option is set. Note
     // that this code is quite invasive; it adds numerous additional
     // instructions for each MInstruction with a computed range, and it uses
     // registers, so it also affects register allocation.
     for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) {
         MBasicBlock* block = *iter;
 
+        // Do not add assertions in unreachable blocks.
+        if (block->unreachable())
+            continue;
+
         for (MDefinitionIterator iter(block); iter; iter++) {
             MDefinition* ins = *iter;
 
             // Perform range checking for all numeric and numeric-like types.
             if (!IsNumberType(ins->type()) &&
                 ins->type() != MIRType::Boolean &&
                 ins->type() != MIRType::Value)
             {
@@ -3486,23 +3490,24 @@ RangeAnalysis::prepareForUCE(bool* shoul
         if (!cond->isTest())
             continue;
 
         // Replace the condition of the test control instruction by a constant
         // chosen based which of the successors has the unreachable flag which is
         // added by MBeta::computeRange on its own block.
         MTest* test = cond->toTest();
         MDefinition* condition = test->input();
-        MConstant* constant = nullptr;
-        if (block == test->ifTrue()) {
-            constant = MConstant::New(alloc(), BooleanValue(false));
-        } else {
-            MOZ_ASSERT(block == test->ifFalse());
-            constant = MConstant::New(alloc(), BooleanValue(true));
-        }
+
+        // If the false-branch is unreachable, then the test condition must be true.
+        // If the true-branch is unreachable, then the test condition must be false.
+        MOZ_ASSERT(block == test->ifTrue() || block == test->ifFalse());
+        bool value = block == test->ifFalse();
+        MConstant* constant = MConstant::New(alloc().fallible(), BooleanValue(value));
+        if (!constant)
+            return false;
 
         if (DeadIfUnused(condition))
             condition->setGuardRangeBailoutsUnchecked();
 
         test->block()->insertBefore(test, constant);
 
         test->replaceOperand(0, constant);
         JitSpew(JitSpew_Range, "Update condition of %d to reflect unreachable branches.",
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -7,16 +7,17 @@
 /*
  * JS bytecode descriptors, disassemblers, and (expression) decompilers.
  */
 
 #include "jsopcodeinlines.h"
 
 #define __STDC_FORMAT_MACROS
 
+#include "mozilla/Attributes.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/Sprintf.h"
 
 #include <algorithm>
 #include <ctype.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
@@ -142,91 +143,115 @@ js::StackDefs(JSScript* script, jsbyteco
     JSOp op = (JSOp) *pc;
     const JSCodeSpec& cs = CodeSpec[op];
     MOZ_ASSERT(cs.ndefs >= 0);
     return cs.ndefs;
 }
 
 const char * PCCounts::numExecName = "interp";
 
-void
-js::DumpIonScriptCounts(Sprinter* sp, HandleScript script,
-        jit::IonScriptCounts* ionCounts)
+static MOZ_MUST_USE bool
+DumpIonScriptCounts(Sprinter* sp, HandleScript script, jit::IonScriptCounts* ionCounts)
 {
-    Sprint(sp, "IonScript [%lu blocks]:\n", ionCounts->numBlocks());
+    if (!sp->jsprintf("IonScript [%lu blocks]:\n", ionCounts->numBlocks()))
+        return false;
+
     for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
         const jit::IonBlockCounts& block = ionCounts->block(i);
         unsigned lineNumber = 0, columnNumber = 0;
         lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()), &columnNumber);
-        Sprint(sp, "BB #%lu [%05u,%u,%u]", block.id(), block.offset(),
-               lineNumber, columnNumber);
-        if (block.description())
-            Sprint(sp, " [inlined %s]", block.description());
-        for (size_t j = 0; j < block.numSuccessors(); j++)
-            Sprint(sp, " -> #%lu", block.successor(j));
-        Sprint(sp, " :: %llu hits\n", block.hitCount());
-        Sprint(sp, "%s\n", block.code());
+        if (!sp->jsprintf("BB #%lu [%05u,%u,%u]",
+                          block.id(), block.offset(), lineNumber, columnNumber))
+        {
+            return false;
+        }
+        if (block.description()) {
+            if (!sp->jsprintf(" [inlined %s]", block.description()))
+                return false;
+        }
+        for (size_t j = 0; j < block.numSuccessors(); j++) {
+            if (!sp->jsprintf(" -> #%lu", block.successor(j)))
+                return false;
+        }
+        if (!sp->jsprintf(" :: %llu hits\n", block.hitCount()))
+            return false;
+        if (!sp->jsprintf("%s\n", block.code()))
+            return false;
     }
+
+    return true;
 }
 
-void
-js::DumpPCCounts(JSContext* cx, HandleScript script, Sprinter* sp)
+static MOZ_MUST_USE bool
+DumpPCCounts(JSContext* cx, HandleScript script, Sprinter* sp)
 {
     MOZ_ASSERT(script->hasScriptCounts());
 
 #ifdef DEBUG
     jsbytecode* pc = script->code();
     while (pc < script->codeEnd()) {
         jsbytecode* next = GetNextPc(pc);
 
         if (!Disassemble1(cx, script, pc, script->pcToOffset(pc), true, sp))
-            return;
+            return false;
 
-        Sprint(sp, "                  {");
+        if (sp->put("                  {") < 0)
+            return false;
+
         PCCounts* counts = script->maybeGetPCCounts(pc);
-        double val = counts ? counts->numExec() : 0.0;
-        if (val)
-            Sprint(sp, "\"%s\": %.0f", PCCounts::numExecName, val);
-        Sprint(sp, "}\n");
+        if (double val = counts ? counts->numExec() : 0.0) {
+            if (!sp->jsprintf("\"%s\": %.0f", PCCounts::numExecName, val))
+                return false;
+        }
+        if (sp->put("}\n") < 0)
+            return false;
 
         pc = next;
     }
 #endif
 
     jit::IonScriptCounts* ionCounts = script->getIonCounts();
+    while (ionCounts) {
+        if (!DumpIonScriptCounts(sp, script, ionCounts))
+            return false;
 
-    while (ionCounts) {
-        DumpIonScriptCounts(sp, script, ionCounts);
         ionCounts = ionCounts->previous();
     }
+
+    return true;
 }
 
-void
+bool
 js::DumpCompartmentPCCounts(JSContext* cx)
 {
     Rooted<GCVector<JSScript*>> scripts(cx, GCVector<JSScript*>(cx));
     for (auto iter = cx->zone()->cellIter<JSScript>(); !iter.done(); iter.next()) {
         JSScript* script = iter;
         if (script->compartment() != cx->compartment())
             continue;
-        if (script->hasScriptCounts() && !scripts.append(script))
-            return;
+        if (script->hasScriptCounts()) {
+            if (!scripts.append(script))
+                return false;
+        }
     }
 
     for (uint32_t i = 0; i < scripts.length(); i++) {
         HandleScript script = scripts[i];
         Sprinter sprinter(cx);
         if (!sprinter.init())
-            return;
+            return false;
 
         fprintf(stdout, "--- SCRIPT %s:%" PRIuSIZE " ---\n", script->filename(), script->lineno());
-        DumpPCCounts(cx, script, &sprinter);
+        if (!DumpPCCounts(cx, script, &sprinter))
+            return false;
         fputs(sprinter.string(), stdout);
         fprintf(stdout, "--- END SCRIPT %s:%" PRIuSIZE " ---\n", script->filename(), script->lineno());
     }
+
+    return true;
 }
 
 /////////////////////////////////////////////////////////////////////
 // Bytecode Parser
 /////////////////////////////////////////////////////////////////////
 
 namespace {
 
@@ -637,82 +662,108 @@ js::ReconstructStackDepth(JSContext* cx,
     return true;
 }
 
 /*
  * If pc != nullptr, include a prefix indicating whether the PC is at the
  * current line. If showAll is true, include the source note type and the
  * entry stack depth.
  */
-static bool
+static MOZ_MUST_USE bool
 DisassembleAtPC(JSContext* cx, JSScript* scriptArg, bool lines,
                 jsbytecode* pc, bool showAll, Sprinter* sp)
 {
     RootedScript script(cx, scriptArg);
     BytecodeParser parser(cx, script);
 
-    if (showAll && !parser.parse())
+    if (showAll) {
+        if (!parser.parse())
+            return false;
+
+        if (!sp->jsprintf("%s:%u\n", script->filename(), unsigned(script->lineno())))
+            return false;
+    }
+
+    if (pc != nullptr) {
+        if (sp->put("    ") < 0)
+            return false;
+    }
+    if (showAll) {
+        if (sp->put("sn stack ") < 0)
+            return false;
+    }
+    if (sp->put("loc   ") < 0)
+        return false;
+    if (lines) {
+        if (sp->put("line") < 0)
+            return false;
+    }
+    if (sp->put("  op\n") < 0)
         return false;
 
-    if (showAll)
-        Sprint(sp, "%s:%" PRIuSIZE "\n", script->filename(), script->lineno());
-
-    if (pc != nullptr)
-        sp->put("    ");
-    if (showAll)
-        sp->put("sn stack ");
-    sp->put("loc   ");
-    if (lines)
-        sp->put("line");
-    sp->put("  op\n");
-
-    if (pc != nullptr)
-        sp->put("    ");
-    if (showAll)
-        sp->put("-- ----- ");
-    sp->put("----- ");
-    if (lines)
-        sp->put("----");
-    sp->put("  --\n");
+    if (pc != nullptr) {
+        if (sp->put("    ") < 0)
+            return false;
+    }
+    if (showAll) {
+        if (sp->put("-- ----- ") < 0)
+            return false;
+    }
+    if (sp->put("----- ") < 0)
+        return false;
+    if (lines) {
+        if (sp->put("----") < 0)
+            return false;
+    }
+    if (sp->put("  --\n") < 0)
+        return false;
 
     jsbytecode* next = script->code();
     jsbytecode* end = script->codeEnd();
     while (next < end) {
-        if (next == script->main())
-            sp->put("main:\n");
+        if (next == script->main()) {
+            if (sp->put("main:\n") < 0)
+                return false;
+        }
         if (pc != nullptr) {
-            if (pc == next)
-                sp->put("--> ");
-            else
-                sp->put("    ");
+            if (sp->put(pc == next ? "--> " : "    ") < 0)
+                return false;
         }
         if (showAll) {
             jssrcnote* sn = GetSrcNote(cx, script, next);
             if (sn) {
                 MOZ_ASSERT(!SN_IS_TERMINATOR(sn));
                 jssrcnote* next = SN_NEXT(sn);
                 while (!SN_IS_TERMINATOR(next) && SN_DELTA(next) == 0) {
-                    Sprint(sp, "%02u\n    ", SN_TYPE(sn));
+                    if (!sp->jsprintf("%02u\n    ", SN_TYPE(sn)))
+                        return false;
                     sn = next;
                     next = SN_NEXT(sn);
                 }
-                Sprint(sp, "%02u ", SN_TYPE(sn));
+                if (!sp->jsprintf("%02u ", SN_TYPE(sn)))
+                    return false;
+            } else {
+                if (sp->put("   ") < 0)
+                    return false;
             }
-            else
-                sp->put("   ");
-            if (parser.isReachable(next))
-                Sprint(sp, "%05u ", parser.stackDepthAtPC(next));
-            else
-                Sprint(sp, "      ");
+            if (parser.isReachable(next)) {
+                if (!sp->jsprintf("%05u ", parser.stackDepthAtPC(next)))
+                    return false;
+            } else {
+                if (sp->put("      ") < 0)
+                    return false;
+            }
         }
         unsigned len = Disassemble1(cx, script, next, script->pcToOffset(next), lines, sp);
         if (!len)
             return false;
+
         next += len;
     }
+
     return true;
 }
 
 bool
 js::Disassemble(JSContext* cx, HandleScript script, bool lines, Sprinter* sp)
 {
     return DisassembleAtPC(cx, script, lines, nullptr, false, sp);
 }
@@ -881,162 +932,164 @@ js::Disassemble1(JSContext* cx, HandleSc
         SprintfLiteral(numBuf1, "%d", op);
         SprintfLiteral(numBuf2, "%d", JSOP_LIMIT);
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2);
         return 0;
     }
     const JSCodeSpec* cs = &CodeSpec[op];
     ptrdiff_t len = (ptrdiff_t) cs->length;
-    if (Sprint(sp, "%05u:", loc) == -1)
+    if (!sp->jsprintf("%05u:", loc))
         return 0;
-    if (lines && Sprint(sp, "%4u", PCToLineNumber(script, pc)) == -1)
-        return 0;
-    if (Sprint(sp, "  %s", CodeName[op]) == -1)
+    if (lines) {
+        if (!sp->jsprintf("%4u", PCToLineNumber(script, pc)))
+            return 0;
+    }
+    if (!sp->jsprintf("  %s", CodeName[op]))
         return 0;
 
     int i;
     switch (JOF_TYPE(cs->format)) {
       case JOF_BYTE:
           // Scan the trynotes to find the associated catch block
           // and make the try opcode look like a jump instruction
           // with an offset. This simplifies code coverage analysis
           // based on this disassembled output.
           if (op == JSOP_TRY) {
               TryNoteArray* trynotes = script->trynotes();
               uint32_t i;
               for(i = 0; i < trynotes->length; i++) {
                   JSTryNote note = trynotes->vector[i];
                   if (note.kind == JSTRY_CATCH && note.start == loc + 1) {
-                      if (Sprint(sp, " %u (%+d)",
-                                 (unsigned int) (loc+note.length+1),
-                                 (int) (note.length+1)) == -1)
+                      if (!sp->jsprintf(" %u (%+d)",
+                                        unsigned(loc + note.length + 1),
+                                        int(note.length + 1)))
                       {
                           return 0;
                       }
                       break;
                   }
               }
           }
         break;
 
       case JOF_JUMP: {
         ptrdiff_t off = GET_JUMP_OFFSET(pc);
-        if (Sprint(sp, " %u (%+d)", loc + (int) off, (int) off) == -1)
+        if (!sp->jsprintf(" %u (%+d)", unsigned(loc + int(off)), int(off)))
             return 0;
         break;
       }
 
       case JOF_SCOPE: {
         RootedScope scope(cx, script->getScope(GET_UINT32_INDEX(pc)));
         JSAutoByteString bytes;
         if (!ToDisassemblySource(cx, scope, &bytes))
             return 0;
-        if (Sprint(sp, " %s", bytes.ptr()) == -1)
+        if (!sp->jsprintf(" %s", bytes.ptr()))
             return 0;
         break;
       }
 
       case JOF_ENVCOORD: {
         RootedValue v(cx,
             StringValue(EnvironmentCoordinateName(cx->caches.envCoordinateNameCache, script, pc)));
         JSAutoByteString bytes;
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
         EnvironmentCoordinate ec(pc);
-        if (Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), ec.hops(), ec.slot()) == -1)
+        if (!sp->jsprintf(" %s (hops = %u, slot = %u)", bytes.ptr(), ec.hops(), ec.slot()))
             return 0;
         break;
       }
 
       case JOF_ATOM: {
         RootedValue v(cx, StringValue(script->getAtom(GET_UINT32_INDEX(pc))));
         JSAutoByteString bytes;
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
-        if (Sprint(sp, " %s", bytes.ptr()) == -1)
+        if (!sp->jsprintf(" %s", bytes.ptr()))
             return 0;
         break;
       }
 
       case JOF_DOUBLE: {
         RootedValue v(cx, script->getConst(GET_UINT32_INDEX(pc)));
         JSAutoByteString bytes;
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
-        if (Sprint(sp, " %s", bytes.ptr()) == -1)
+        if (!sp->jsprintf(" %s", bytes.ptr()))
             return 0;
         break;
       }
 
       case JOF_OBJECT: {
         /* Don't call obj.toSource if analysis/inference is active. */
         if (script->zone()->types.activeAnalysis) {
-            if (Sprint(sp, " object") == -1)
+            if (!sp->jsprintf(" object"))
                 return 0;
             break;
         }
 
         JSObject* obj = script->getObject(GET_UINT32_INDEX(pc));
         {
             JSAutoByteString bytes;
             RootedValue v(cx, ObjectValue(*obj));
             if (!ToDisassemblySource(cx, v, &bytes))
                 return 0;
-            if (Sprint(sp, " %s", bytes.ptr()) == -1)
+            if (!sp->jsprintf(" %s", bytes.ptr()))
                 return 0;
         }
         break;
       }
 
       case JOF_REGEXP: {
         js::RegExpObject* obj = script->getRegExp(pc);
         JSAutoByteString bytes;
         RootedValue v(cx, ObjectValue(*obj));
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
-        if (Sprint(sp, " %s", bytes.ptr()) == -1)
+        if (!sp->jsprintf(" %s", bytes.ptr()))
             return 0;
         break;
       }
 
       case JOF_TABLESWITCH:
       {
         int32_t i, low, high;
 
         ptrdiff_t off = GET_JUMP_OFFSET(pc);
         jsbytecode* pc2 = pc + JUMP_OFFSET_LEN;
         low = GET_JUMP_OFFSET(pc2);
         pc2 += JUMP_OFFSET_LEN;
         high = GET_JUMP_OFFSET(pc2);
         pc2 += JUMP_OFFSET_LEN;
-        if (Sprint(sp, " defaultOffset %d low %d high %d", int(off), low, high) == -1)
+        if (!sp->jsprintf(" defaultOffset %d low %d high %d", int(off), low, high))
             return 0;
         for (i = low; i <= high; i++) {
             off = GET_JUMP_OFFSET(pc2);
-            if (Sprint(sp, "\n\t%d: %d", i, int(off)) == -1)
+            if (!sp->jsprintf("\n\t%d: %d", i, int(off)))
                 return 0;
             pc2 += JUMP_OFFSET_LEN;
         }
         len = 1 + pc2 - pc;
         break;
       }
 
       case JOF_QARG:
-        if (Sprint(sp, " %u", GET_ARGNO(pc)) == -1)
+        if (!sp->jsprintf(" %u", GET_ARGNO(pc)))
             return 0;
         break;
 
       case JOF_LOCAL:
-        if (Sprint(sp, " %u", GET_LOCALNO(pc)) == -1)
+        if (!sp->jsprintf(" %u", GET_LOCALNO(pc)))
             return 0;
         break;
 
       case JOF_UINT32:
-        if (Sprint(sp, " %u", GET_UINT32(pc)) == -1)
+        if (!sp->jsprintf(" %u", GET_UINT32(pc)))
             return 0;
         break;
 
       case JOF_UINT16:
         i = (int)GET_UINT16(pc);
         goto print_int;
 
       case JOF_UINT24:
@@ -1051,17 +1104,17 @@ js::Disassemble1(JSContext* cx, HandleSc
       case JOF_INT8:
         i = GET_INT8(pc);
         goto print_int;
 
       case JOF_INT32:
         MOZ_ASSERT(op == JSOP_INT32);
         i = GET_INT32(pc);
       print_int:
-        if (Sprint(sp, " %d", i) == -1)
+        if (!sp->jsprintf(" %d", i))
             return 0;
         break;
 
       default: {
         char numBuf[12];
         SprintfLiteral(numBuf, "%x", cs->format);
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_UNKNOWN_FORMAT, numBuf);
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -6,16 +6,18 @@
 
 #ifndef jsopcode_h
 #define jsopcode_h
 
 /*
  * JS bytecode definitions.
  */
 
+#include "mozilla/Attributes.h"
+
 #include "jsbytecode.h"
 #include "jstypes.h"
 #include "NamespaceImports.h"
 
 #include "frontend/SourceNotes.h"
 #include "js/UniquePtr.h"
 #include "vm/Opcodes.h"
 #include "vm/Printer.h"
@@ -842,30 +844,23 @@ GetNextPc(jsbytecode* pc)
 {
     return pc + GetBytecodeLength(pc);
 }
 
 #if defined(DEBUG)
 /*
  * Disassemblers, for debugging only.
  */
-bool
+extern MOZ_MUST_USE bool
 Disassemble(JSContext* cx, JS::Handle<JSScript*> script, bool lines, Sprinter* sp);
 
 unsigned
 Disassemble1(JSContext* cx, JS::Handle<JSScript*> script, jsbytecode* pc, unsigned loc,
              bool lines, Sprinter* sp);
 
 #endif
 
-void
-DumpPCCounts(JSContext* cx, JS::Handle<JSScript*> script, Sprinter* sp);
+extern MOZ_MUST_USE bool
+DumpCompartmentPCCounts(JSContext* cx);
 
-namespace jit { struct IonScriptCounts; }
-void
-DumpIonScriptCounts(js::Sprinter* sp, HandleScript script,
-                    jit::IonScriptCounts* ionCounts);
-
-void
-DumpCompartmentPCCounts(JSContext* cx);
 } // namespace js
 
 #endif /* jsopcode_h */
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1211,37 +1211,45 @@ fi
 
 dnl Checks for library functions.
 dnl ========================================================
 AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
 AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r pthread_getname_np])
 
 dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
-AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
-               ac_cv_clock_monotonic,
-               [for libs in "" -lrt; do
-                    _SAVE_LIBS="$LIBS"
-                    LIBS="$LIBS $libs"
-                    AC_TRY_LINK([#include <time.h>],
-                                 [ struct timespec ts;
-                                   clock_gettime(CLOCK_MONOTONIC, &ts); ],
-                                 ac_cv_clock_monotonic=$libs
-                                 LIBS="$_SAVE_LIBS"
-                                 break,
-                                 ac_cv_clock_monotonic=no)
-                    LIBS="$_SAVE_LIBS"
-                done])
-if test "$ac_cv_clock_monotonic" != "no"; then
-    HAVE_CLOCK_MONOTONIC=1
-    REALTIME_LIBS=$ac_cv_clock_monotonic
-    AC_DEFINE(HAVE_CLOCK_MONOTONIC)
-    AC_SUBST(HAVE_CLOCK_MONOTONIC)
-    AC_SUBST_LIST(REALTIME_LIBS)
-fi
+dnl avoid this on Darwin, since depending on your system config, we may think
+dnl it exists but it really doesn't
+case "$OS_TARGET" in
+Darwin)
+  ;;
+*)
+  AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
+                 ac_cv_clock_monotonic,
+                 [for libs in "" -lrt; do
+                      _SAVE_LIBS="$LIBS"
+                      LIBS="$LIBS $libs"
+                      AC_TRY_LINK([#include <time.h>],
+                                   [ struct timespec ts;
+                                     clock_gettime(CLOCK_MONOTONIC, &ts); ],
+                                   ac_cv_clock_monotonic=$libs
+                                   LIBS="$_SAVE_LIBS"
+                                   break,
+                                   ac_cv_clock_monotonic=no)
+                      LIBS="$_SAVE_LIBS"
+                  done])
+  if test "$ac_cv_clock_monotonic" != "no"; then
+      HAVE_CLOCK_MONOTONIC=1
+      REALTIME_LIBS=$ac_cv_clock_monotonic
+      AC_DEFINE(HAVE_CLOCK_MONOTONIC)
+      AC_SUBST(HAVE_CLOCK_MONOTONIC)
+      AC_SUBST_LIST(REALTIME_LIBS)
+  fi
+  ;;
+esac
 
 dnl Checks for math functions.
 dnl ========================================================
 AC_CHECK_LIB(m, sin)
 AC_CHECK_LIB(m, __sincos, AC_DEFINE(HAVE_SINCOS))
 
 
 dnl check for wcrtomb/mbrtowc
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3,21 +3,23 @@
  * 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/. */
 
 /* JS shell. */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/PodOperations.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/TimeStamp.h"
 
 #ifdef XP_WIN
 # include <direct.h>
 # include <process.h>
 #endif
@@ -103,16 +105,17 @@
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::cli;
 using namespace js::shell;
 
 using mozilla::ArrayLength;
 using mozilla::Atomic;
+using mozilla::MakeScopeExit;
 using mozilla::Maybe;
 using mozilla::Nothing;
 using mozilla::NumberEqualsInt32;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 
@@ -2327,237 +2330,300 @@ UpdateSwitchTableBounds(JSContext* cx, H
         MOZ_ASSERT(op == JSOP_CONDSWITCH);
         return;
     }
 
     *start = script->pcToOffset(pc);
     *end = *start + (unsigned)(n * jmplen);
 }
 
-static void
+static MOZ_MUST_USE bool
 SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp)
 {
-    Sprint(sp, "\nSource notes:\n");
-    Sprint(sp, "%4s %4s %5s %6s %-8s %s\n",
-           "ofs", "line", "pc", "delta", "desc", "args");
-    Sprint(sp, "---- ---- ----- ------ -------- ------\n");
+    if (sp->put("\nSource notes:\n") < 0 ||
+        !sp->jsprintf("%4s %4s %5s %6s %-8s %s\n",
+                      "ofs", "line", "pc", "delta", "desc", "args") ||
+        sp->put("---- ---- ----- ------ -------- ------\n") < 0)
+    {
+        return false;
+    }
+
     unsigned offset = 0;
     unsigned colspan = 0;
     unsigned lineno = script->lineno();
     jssrcnote* notes = script->notes();
     unsigned switchTableEnd = 0, switchTableStart = 0;
     for (jssrcnote* sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
         unsigned delta = SN_DELTA(sn);
         offset += delta;
         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
         const char* name = js_SrcNoteSpec[type].name;
-        Sprint(sp, "%3u: %4u %5u [%4u] %-8s", unsigned(sn - notes), lineno, offset, delta, name);
+        if (!sp->jsprintf("%3u: %4u %5u [%4u] %-8s",
+                          unsigned(sn - notes), lineno, offset, delta, name))
+        {
+            return false;
+        }
+
         switch (type) {
           case SRC_NULL:
           case SRC_IF:
           case SRC_CONTINUE:
           case SRC_BREAK:
           case SRC_BREAK2LABEL:
           case SRC_SWITCHBREAK:
           case SRC_ASSIGNOP:
           case SRC_XDELTA:
             break;
 
           case SRC_COLSPAN:
             colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
-            Sprint(sp, "%d", colspan);
+            if (!sp->jsprintf("%d", colspan))
+                return false;
             break;
 
           case SRC_SETLINE:
             lineno = GetSrcNoteOffset(sn, 0);
-            Sprint(sp, " lineno %u", lineno);
+            if (!sp->jsprintf(" lineno %u", lineno))
+                return false;
             break;
 
           case SRC_NEWLINE:
             ++lineno;
             break;
 
           case SRC_FOR:
-            Sprint(sp, " cond %u update %u tail %u",
-                   unsigned(GetSrcNoteOffset(sn, 0)),
-                   unsigned(GetSrcNoteOffset(sn, 1)),
-                   unsigned(GetSrcNoteOffset(sn, 2)));
+            if (!sp->jsprintf(" cond %u update %u tail %u",
+                              unsigned(GetSrcNoteOffset(sn, 0)),
+                              unsigned(GetSrcNoteOffset(sn, 1)),
+                              unsigned(GetSrcNoteOffset(sn, 2))))
+            {
+                return false;
+            }
             break;
 
           case SRC_IF_ELSE:
-            Sprint(sp, " else %u", unsigned(GetSrcNoteOffset(sn, 0)));
+            if (!sp->jsprintf(" else %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                return false;
             break;
 
           case SRC_FOR_IN:
           case SRC_FOR_OF:
-            Sprint(sp, " closingjump %u", unsigned(GetSrcNoteOffset(sn, 0)));
+            if (!sp->jsprintf(" closingjump %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                return false;
             break;
 
           case SRC_COND:
           case SRC_WHILE:
           case SRC_NEXTCASE:
-            Sprint(sp, " offset %u", unsigned(GetSrcNoteOffset(sn, 0)));
+            if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                return false;
             break;
 
           case SRC_TABLESWITCH: {
             JSOp op = JSOp(script->code()[offset]);
             MOZ_ASSERT(op == JSOP_TABLESWITCH);
-            Sprint(sp, " length %u", unsigned(GetSrcNoteOffset(sn, 0)));
+            if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                return false;
             UpdateSwitchTableBounds(cx, script, offset,
                                     &switchTableStart, &switchTableEnd);
             break;
           }
           case SRC_CONDSWITCH: {
             JSOp op = JSOp(script->code()[offset]);
             MOZ_ASSERT(op == JSOP_CONDSWITCH);
-            Sprint(sp, " length %u", unsigned(GetSrcNoteOffset(sn, 0)));
-            unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1);
-            if (caseOff)
-                Sprint(sp, " first case offset %u", caseOff);
+            if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                return false;
+            if (unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1)) {
+                if (!sp->jsprintf(" first case offset %u", caseOff))
+                    return false;
+            }
             UpdateSwitchTableBounds(cx, script, offset,
                                     &switchTableStart, &switchTableEnd);
             break;
           }
 
           case SRC_TRY:
             MOZ_ASSERT(JSOp(script->code()[offset]) == JSOP_TRY);
-            Sprint(sp, " offset to jump %u", unsigned(GetSrcNoteOffset(sn, 0)));
+            if (!sp->jsprintf(" offset to jump %u", unsigned(GetSrcNoteOffset(sn, 0))))
+                return false;
             break;
 
           default:
-            MOZ_ASSERT(0);
-            break;
+            MOZ_ASSERT_UNREACHABLE("unrecognized srcnote");
         }
-        Sprint(sp, "\n");
-    }
+        if (sp->put("\n") < 0)
+            return false;
+    }
+
+    return true;
 }
 
 static bool
 Notes(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Sprinter sprinter(cx);
     if (!sprinter.init())
         return false;
 
     for (unsigned i = 0; i < args.length(); i++) {
         RootedScript script (cx, ValueToScript(cx, args[i]));
         if (!script)
             return false;
 
-        SrcNotes(cx, script, &sprinter);
+        if (!SrcNotes(cx, script, &sprinter))
+            return false;
     }
 
     JSString* str = JS_NewStringCopyZ(cx, sprinter.string());
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
 JS_STATIC_ASSERT(JSTRY_CATCH == 0);
 JS_STATIC_ASSERT(JSTRY_FINALLY == 1);
 JS_STATIC_ASSERT(JSTRY_FOR_IN == 2);
 
 static const char* const TryNoteNames[] = { "catch", "finally", "for-in", "for-of", "loop" };
 
-static bool
+static MOZ_MUST_USE bool
 TryNotes(JSContext* cx, HandleScript script, Sprinter* sp)
 {
     if (!script->hasTrynotes())
         return true;
 
+    if (sp->put("\nException table:\nkind      stack    start      end\n") < 0)
+        return false;
+
     JSTryNote* tn = script->trynotes()->vector;
     JSTryNote* tnlimit = tn + script->trynotes()->length;
-    Sprint(sp, "\nException table:\nkind      stack    start      end\n");
     do {
         MOZ_ASSERT(tn->kind < ArrayLength(TryNoteNames));
         uint8_t startOff = script->pcToOffset(script->main()) + tn->start;
-        Sprint(sp, " %-7s %6u %8u %8u\n",
-               TryNoteNames[tn->kind], tn->stackDepth,
-               startOff, startOff + tn->length);
+        if (!sp->jsprintf(" %-7s %6u %8u %8u\n",
+                          TryNoteNames[tn->kind], tn->stackDepth,
+                          startOff, startOff + tn->length))
+        {
+            return false;
+        }
     } while (++tn != tnlimit);
     return true;
 }
 
-static bool
+static MOZ_MUST_USE bool
 ScopeNotes(JSContext* cx, HandleScript script, Sprinter* sp)
 {
     if (!script->hasScopeNotes())
         return true;
 
-    Sprint(sp, "\nScope notes:\n   index   parent    start      end\n");
+    if (sp->put("\nScope notes:\n   index   parent    start      end\n") < 0)
+        return false;
 
     ScopeNoteArray* notes = script->scopeNotes();
     for (uint32_t i = 0; i < notes->length; i++) {
         const ScopeNote* note = &notes->vector[i];
-        if (note->index == ScopeNote::NoScopeIndex)
-            Sprint(sp, "%8s ", "(none)");
-        else
-            Sprint(sp, "%8u ", note->index);
-        if (note->parent == ScopeNote::NoScopeIndex)
-            Sprint(sp, "%8s ", "(none)");
-        else
-            Sprint(sp, "%8u ", note->parent);
-        Sprint(sp, "%8u %8u\n", note->start, note->start + note->length);
+        if (note->index == ScopeNote::NoScopeIndex) {
+            if (!sp->jsprintf("%8s ", "(none)"))
+                return false;
+        } else {
+            if (!sp->jsprintf("%8u ", note->index))
+                return false;
+        }
+        if (note->parent == ScopeNote::NoScopeIndex) {
+            if (!sp->jsprintf("%8s ", "(none)"))
+                return false;
+        } else {
+            if (!sp->jsprintf("%8u ", note->parent))
+                return false;
+        }
+        if (!sp->jsprintf("%8u %8u\n", note->start, note->start + note->length))
+            return false;
     }
     return true;
 }
 
-static bool
+static MOZ_MUST_USE bool
 DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun,
                   bool lines, bool recursive, bool sourceNotes, Sprinter* sp)
 {
     if (fun) {
-        Sprint(sp, "flags:");
-        if (fun->isLambda())
-            Sprint(sp, " LAMBDA");
-        if (fun->needsCallObject())
-            Sprint(sp, " NEEDS_CALLOBJECT");
-        if (fun->needsExtraBodyVarEnvironment())
-            Sprint(sp, " NEEDS_EXTRABODYVARENV");
-        if (fun->needsNamedLambdaEnvironment())
-            Sprint(sp, " NEEDS_NAMEDLAMBDAENV");
-        if (fun->isConstructor())
-            Sprint(sp, " CONSTRUCTOR");
-        if (fun->isExprBody())
-            Sprint(sp, " EXPRESSION_CLOSURE");
-        if (fun->isSelfHostedBuiltin())
-            Sprint(sp, " SELF_HOSTED");
-        if (fun->isArrow())
-            Sprint(sp, " ARROW");
-        Sprint(sp, "\n");
+        if (sp->put("flags:") < 0)
+            return false;
+        if (fun->isLambda()) {
+            if (sp->put(" LAMBDA") < 0)
+                return false;
+        }
+        if (fun->needsCallObject()) {
+            if (sp->put(" NEEDS_CALLOBJECT") < 0)
+                return false;
+        }
+        if (fun->needsExtraBodyVarEnvironment()) {
+            if (sp->put(" NEEDS_EXTRABODYVARENV") < 0)
+                return false;
+        }
+        if (fun->needsNamedLambdaEnvironment()) {
+            if (sp->put(" NEEDS_NAMEDLAMBDAENV") < 0)
+                return false;
+        }
+        if (fun->isConstructor()) {
+            if (sp->put(" CONSTRUCTOR") < 0)
+                return false;
+        }
+        if (fun->isExprBody()) {
+            if (sp->put(" EXPRESSION_CLOSURE") < 0)
+                return false;
+        }
+        if (fun->isSelfHostedBuiltin()) {
+            if (sp->put(" SELF_HOSTED") < 0)
+                return false;
+        }
+        if (fun->isArrow()) {
+            if (sp->put(" ARROW") < 0)
+                return false;
+        }
+        if (sp->put("\n") < 0)
+            return false;
     }
 
     if (!Disassemble(cx, script, lines, sp))
         return false;
-    if (sourceNotes)
-        SrcNotes(cx, script, sp);
-    TryNotes(cx, script, sp);
-    ScopeNotes(cx, script, sp);
+    if (sourceNotes) {
+        if (!SrcNotes(cx, script, sp))
+            return false;
+    }
+    if (!TryNotes(cx, script, sp))
+        return false;
+    if (!ScopeNotes(cx, script, sp))
+        return false;
 
     if (recursive && script->hasObjects()) {
         ObjectArray* objects = script->objects();
         for (unsigned i = 0; i != objects->length; ++i) {
             JSObject* obj = objects->vector[i];
             if (obj->is<JSFunction>()) {
-                Sprint(sp, "\n");
+                if (sp->put("\n") < 0)
+                    return false;
+
                 RootedFunction fun(cx, &obj->as<JSFunction>());
                 if (fun->isInterpreted()) {
                     RootedScript script(cx, fun->getOrCreateScript(cx));
                     if (script) {
                         if (!DisassembleScript(cx, script, fun, lines, recursive, sourceNotes, sp))
                             return false;
                     }
                 } else {
-                    Sprint(sp, "[native code]\n");
+                    if (sp->put("[native code]\n") < 0)
+                        return false;
                 }
             }
         }
     }
+
     return true;
 }
 
 namespace {
 
 struct DisassembleOptionParser {
     unsigned argc;
     Value* argv;
@@ -2601,19 +2667,22 @@ DisassembleToSprinter(JSContext* cx, uns
 
     if (p.argc == 0) {
         /* Without arguments, disassemble the current script. */
         RootedScript script(cx, GetTopScript(cx));
         if (script) {
             JSAutoCompartment ac(cx, script);
             if (!Disassemble(cx, script, p.lines, sprinter))
                 return false;
-            SrcNotes(cx, script, sprinter);
-            TryNotes(cx, script, sprinter);
-            ScopeNotes(cx, script, sprinter);
+            if (!SrcNotes(cx, script, sprinter))
+                return false;
+            if (!TryNotes(cx, script, sprinter))
+                return false;
+            if (!ScopeNotes(cx, script, sprinter))
+                return false;
         }
     } else {
         for (unsigned i = 0; i < p.argc; i++) {
             RootedFunction fun(cx);
             RootedScript script(cx);
             RootedValue value(cx, p.argv[i]);
             if (value.isObject() && value.toObject().is<ModuleObject>())
                 script = value.toObject().as<ModuleObject>().script();
@@ -2728,111 +2797,98 @@ DisassWithSrc(JSContext* cx, unsigned ar
 
     if (!gOutFile->isOpen()) {
         JS_ReportError(cx, "output file is closed");
         return false;
     }
 
     const size_t lineBufLen = 512;
     unsigned len, line1, line2, bupline;
-    FILE* file;
     char linebuf[lineBufLen];
     static const char sep[] = ";-------------------------";
 
-    bool ok = true;
     RootedScript script(cx);
-    for (unsigned i = 0; ok && i < args.length(); i++) {
+    for (unsigned i = 0; i < args.length(); i++) {
         script = ValueToScript(cx, args[i]);
         if (!script)
            return false;
 
         if (!script->filename()) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                  JSSMSG_FILE_SCRIPTS_ONLY);
             return false;
         }
 
-        file = fopen(script->filename(), "r");
+        FILE* file = fopen(script->filename(), "r");
         if (!file) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                  JSSMSG_CANT_OPEN, script->filename(),
                                  strerror(errno));
             return false;
         }
+        auto closeFile = MakeScopeExit([file]() { fclose(file); });
 
         jsbytecode* pc = script->code();
         jsbytecode* end = script->codeEnd();
 
         Sprinter sprinter(cx);
-        if (!sprinter.init()) {
-            ok = false;
-            goto bail;
-        }
+        if (!sprinter.init())
+            return false;
 
         /* burn the leading lines */
         line2 = PCToLineNumber(script, pc);
         for (line1 = 0; line1 < line2 - 1; line1++) {
             char* tmp = fgets(linebuf, lineBufLen, file);
             if (!tmp) {
                 JS_ReportError(cx, "failed to read %s fully", script->filename());
-                ok = false;
-                goto bail;
+                return false;
             }
         }
 
         bupline = 0;
         while (pc < end) {
             line2 = PCToLineNumber(script, pc);
 
             if (line2 < line1) {
                 if (bupline != line2) {
                     bupline = line2;
-                    if (Sprint(&sprinter, "%s %3u: BACKUP\n", sep, line2) == -1) {
-                        ok = false;
-                        goto bail;
-                    }
+                    if (!sprinter.jsprintf("%s %3u: BACKUP\n", sep, line2))
+                        return false;
                 }
             } else {
-                if (bupline && line1 == line2)
-                    if (Sprint(&sprinter, "%s %3u: RESTORE\n", sep, line2) == -1) {
-                        ok = false;
-                        goto bail;
-                    }
+                if (bupline && line1 == line2) {
+                    if (!sprinter.jsprintf("%s %3u: RESTORE\n", sep, line2))
+                        return false;
+                }
                 bupline = 0;
                 while (line1 < line2) {
                     if (!fgets(linebuf, lineBufLen, file)) {
                         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                              JSSMSG_UNEXPECTED_EOF,
                                              script->filename());
-                        ok = false;
-                        goto bail;
+                        return false;
                     }
                     line1++;
-                    if (Sprint(&sprinter, "%s %3u: %s", sep, line1, linebuf) == -1) {
-                        ok = false;
-                        goto bail;
-                    }
+                    if (!sprinter.jsprintf("%s %3u: %s", sep, line1, linebuf))
+                        return false;
                 }
             }
 
             len = Disassemble1(cx, script, pc, script->pcToOffset(pc), true, &sprinter);
-            if (!len) {
-                ok = false;
-                goto bail;
-            }
+            if (!len)
+                return false;
+
             pc += len;
         }
 
         fprintf(gOutFile->fp, "%s\n", sprinter.string());
-
-      bail:
-        fclose(file);
-    }
+    }
+
     args.rval().setUndefined();
-    return ok;
+    return true;
 }
 
 #endif /* DEBUG */
 
 /* Pretend we can always preserve wrappers for dummy DOM objects. */
 static bool
 DummyPreserveWrapperCallback(JSContext* cx, JSObject* obj)
 {
@@ -4905,71 +4961,120 @@ SetSharedArrayBuffer(JSContext* cx, unsi
     args.rval().setUndefined();
     return true;
 }
 
 class SprintOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeInfoOp
 {
     Sprinter* sp;
     bool startedTypes_;
+    bool hadError_;
 
   public:
     explicit SprintOptimizationTypeInfoOp(Sprinter* sp)
       : sp(sp),
-        startedTypes_(false)
+        startedTypes_(false),
+        hadError_(false)
     { }
 
     void readType(const char* keyedBy, const char* name,
                   const char* location, Maybe<unsigned> lineno) override
     {
-        if (!startedTypes_) {
-            startedTypes_ = true;
-            Sprint(sp, "{\"typeset\": [");
-        }
-        Sprint(sp, "{\"keyedBy\":\"%s\"", keyedBy);
-        if (name)
-            Sprint(sp, ",\"name\":\"%s\"", name);
-        if (location) {
-            char buf[512];
-            PutEscapedString(buf, mozilla::ArrayLength(buf), location, strlen(location), '"');
-            Sprint(sp, ",\"location\":%s", buf);
-        }
-        if (lineno.isSome())
-            Sprint(sp, ",\"line\":%u", *lineno);
-        Sprint(sp, "},");
+        if (hadError_)
+            return;
+
+        do {
+            if (!startedTypes_) {
+                startedTypes_ = true;
+                if (sp->put("{\"typeset\": [") < 0)
+                    break;
+            }
+
+            if (!sp->jsprintf("{\"keyedBy\":\"%s\"", keyedBy))
+                break;
+
+            if (name) {
+                if (!sp->jsprintf(",\"name\":\"%s\"", name))
+                    break;
+            }
+
+            if (location) {
+                char buf[512];
+                PutEscapedString(buf, mozilla::ArrayLength(buf), location, strlen(location), '"');
+                if (!sp->jsprintf(",\"location\":%s", buf))
+                    break;
+            }
+            if (lineno.isSome()) {
+                if (!sp->jsprintf(",\"line\":%u", *lineno))
+                    break;
+            }
+            if (sp->put("},") < 0)
+                break;
+
+            return;
+        } while (false);
+
+        hadError_ = true;
     }
 
     void operator()(JS::TrackedTypeSite site, const char* mirType) override {
-        if (startedTypes_) {
-            // Clear trailing ,
-            if ((*sp)[sp->getOffset() - 1] == ',')
-                (*sp)[sp->getOffset() - 1] = ' ';
-            Sprint(sp, "],");
-            startedTypes_ = false;
-        } else {
-            Sprint(sp, "{");
-        }
-
-        Sprint(sp, "\"site\":\"%s\",\"mirType\":\"%s\"},",
-               TrackedTypeSiteString(site), mirType);
+        if (hadError_)
+            return;
+
+        do {
+            if (startedTypes_) {
+                // Clear trailing ,
+                if ((*sp)[sp->getOffset() - 1] == ',')
+                    (*sp)[sp->getOffset() - 1] = ' ';
+                if (sp->put("],") < 0)
+                    break;
+
+                startedTypes_ = false;
+            } else {
+                if (sp->put("{") < 0)
+                    break;
+            }
+
+            if (!sp->jsprintf("\"site\":\"%s\",\"mirType\":\"%s\"},",
+                              TrackedTypeSiteString(site), mirType))
+            {
+                break;
+            }
+
+            return;
+        } while (false);
+
+        hadError_ = true;
+    }
+
+    bool hadError() const {
+        return hadError_;
     }
 };
 
 class SprintOptimizationAttemptsOp : public JS::ForEachTrackedOptimizationAttemptOp
 {
     Sprinter* sp;
+    bool hadError_;
 
   public:
     explicit SprintOptimizationAttemptsOp(Sprinter* sp)
-      : sp(sp)
+      : sp(sp), hadError_(false)
     { }
 
     void operator()(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) override {
-        Sprint(sp, "{\"strategy\":\"%s\",\"outcome\":\"%s\"},",
-               TrackedStrategyString(strategy), TrackedOutcomeString(outcome));
+        if (hadError_)
+            return;
+
+        hadError_ = !sp->jsprintf("{\"strategy\":\"%s\",\"outcome\":\"%s\"},",
+                                  TrackedStrategyString(strategy), TrackedOutcomeString(outcome));
+    }
+
+    bool hadError() const {
+        return hadError_;
     }
 };
 
 static bool
 ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject callee(cx, &args.callee());
@@ -5013,58 +5118,84 @@ ReflectTrackedOptimizations(JSContext* c
 
     Sprinter sp(cx);
     if (!sp.init())
         return false;
 
     const jit::IonTrackedOptimizationsRegionTable* regions =
         entry.ionEntry().trackedOptimizationsRegionTable();
 
-    Sprint(&sp, "{\"regions\": [");
+    if (sp.put("{\"regions\": [") < 0)
+        return false;
+
     for (uint32_t i = 0; i < regions->numEntries(); i++) {
         jit::IonTrackedOptimizationsRegion region = regions->entry(i);
         jit::IonTrackedOptimizationsRegion::RangeIterator iter = region.ranges();
         while (iter.more()) {
             uint32_t startOffset, endOffset;
             uint8_t index;
             iter.readNext(&startOffset, &endOffset, &index);
+
             JSScript* script;
             jsbytecode* pc;
             // Use endOffset, as startOffset may be associated with a
             // previous, adjacent region ending exactly at startOffset. That
             // is, suppose we have two regions [0, startOffset], [startOffset,
             // endOffset]. Since we are not querying a return address, we want
             // the second region and not the first.
             uint8_t* addr = ion->method()->raw() + endOffset;
             entry.youngestFrameLocationAtAddr(rt, addr, &script, &pc);
-            Sprint(&sp, "{\"location\":\"%s:%u\",\"offset\":%u,\"index\":%u}%s",
-                   script->filename(), script->lineno(), script->pcToOffset(pc), index,
-                   iter.more() ? "," : "");
+
+            if (!sp.jsprintf("{\"location\":\"%s:%u\",\"offset\":%u,\"index\":%u}%s",
+                             script->filename(), script->lineno(), script->pcToOffset(pc), index,
+                             iter.more() ? "," : ""))
+            {
+                return false;
+            }
         }
     }
-    Sprint(&sp, "],");
-
-    Sprint(&sp, "\"opts\": [");
+
+    if (sp.put("],") < 0)
+        return false;
+
+    if (sp.put("\"opts\": [") < 0)
+        return false;
+
     for (uint8_t i = 0; i < entry.ionEntry().numOptimizationAttempts(); i++) {
-        Sprint(&sp, "%s{\"typeinfo\":[", i == 0 ? "" : ",");
+        if (!sp.jsprintf("%s{\"typeinfo\":[", i == 0 ? "" : ","))
+            return false;
+
         SprintOptimizationTypeInfoOp top(&sp);
         jit::IonTrackedOptimizationsTypeInfo::ForEachOpAdapter adapter(top);
         entry.trackedOptimizationTypeInfo(i).forEach(adapter, entry.allTrackedTypes());
+        if (top.hadError())
+            return false;
+
         // Clear the trailing ,
         if (sp[sp.getOffset() - 1] == ',')
             sp[sp.getOffset() - 1] = ' ';
-        Sprint(&sp, "],\"attempts\":[");
+
+        if (sp.put("],\"attempts\":[") < 0)
+            return false;
+
         SprintOptimizationAttemptsOp aop(&sp);
         entry.trackedOptimizationAttempts(i).forEach(aop);
+        if (aop.hadError())
+            return false;
+
         // Clear the trailing ,
         if (sp[sp.getOffset() - 1] == ',')
             sp[sp.getOffset() - 1] = ' ';
-        Sprint(&sp, "]}");
-    }
-    Sprint(&sp, "]}");
+
+        if (sp.put("]}") < 0)
+            return false;
+    }
+
+    if (sp.put("]}") < 0)
+        return false;
 
     if (sp.hadOutOfMemory())
         return false;
 
     RootedString str(cx, JS_NewStringCopyZ(cx, sp.string()));
     if (!str)
         return false;
     RootedValue jsonVal(cx);
@@ -7287,18 +7418,21 @@ Shell(JSContext* cx, OptionParser* op, c
         AutoReportException are(cx);
         if (!ProcessArgs(cx, op) && !sc->quitting)
             result = EXITCODE_RUNTIME_ERROR;
     }
 
     if (sc->exitCode)
         result = sc->exitCode;
 
-    if (enableDisassemblyDumps)
-        js::DumpCompartmentPCCounts(cx);
+    if (enableDisassemblyDumps) {
+        AutoReportException are(cx);
+        if (!js::DumpCompartmentPCCounts(cx))
+            result = EXITCODE_OUT_OF_MEMORY;
+    }
 
     if (!op->getBoolOption("no-js-cache-per-process")) {
         if (jsCacheAsmJSPath) {
             unlink(jsCacheAsmJSPath);
             JS_free(cx, const_cast<char*>(jsCacheAsmJSPath));
         }
         if (jsCacheDir) {
             rmdir(jsCacheDir);
--- a/js/src/vm/Printer.cpp
+++ b/js/src/vm/Printer.cpp
@@ -1,26 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=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 "vm/Printer.h"
 
+#include "mozilla/PodOperations.h"
+
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include "jscntxt.h"
 #include "jsprf.h"
 #include "jsutil.h"
 
 #include "ds/LifoAlloc.h"
 
+using mozilla::PodCopy;
+
 namespace js {
 
 GenericPrinter::GenericPrinter()
   : hadOOM_(false)
 {
 }
 
 void
@@ -33,22 +37,16 @@ GenericPrinter::reportOutOfMemory()
 
 bool
 GenericPrinter::hadOutOfMemory() const
 {
     return hadOOM_;
 }
 
 int
-GenericPrinter::put(const char* s)
-{
-    return put(s, strlen(s));
-}
-
-int
 GenericPrinter::printf(const char* fmt, ...)
 {
     va_list va;
     va_start(va, fmt);
     int i = vprintf(fmt, va);
     va_end(va);
     return i;
 }
@@ -233,17 +231,17 @@ Sprinter::putString(JSString* s)
         return -1;
 
     JSLinearString* linear = s->ensureLinear(context);
     if (!linear)
         return -1;
 
     JS::AutoCheckCannotGC nogc;
     if (linear->hasLatin1Chars())
-        mozilla::PodCopy(reinterpret_cast<Latin1Char*>(buffer), linear->latin1Chars(nogc), length);
+        PodCopy(reinterpret_cast<Latin1Char*>(buffer), linear->latin1Chars(nogc), length);
     else
         DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size);
 
     buffer[size] = 0;
     return oldOffset;
 }
 
 ptrdiff_t
@@ -257,33 +255,30 @@ Sprinter::reportOutOfMemory()
 {
     if (hadOOM_)
         return;
     if (context && shouldReportOOM)
         ReportOutOfMemory(context);
     hadOOM_ = true;
 }
 
-ptrdiff_t
-Sprint(Sprinter* sp, const char* format, ...)
+bool
+Sprinter::jsprintf(const char* format, ...)
 {
     va_list ap;
-    char* bp;
-    ptrdiff_t offset;
+    va_start(ap, format);
 
-    va_start(ap, format);
-    bp = JS_vsmprintf(format, ap);      /* XXX vsaprintf */
+    UniquePtr<char, JS::FreePolicy> chars(JS_vsmprintf(format, ap));      /* XXX vsaprintf */
     va_end(ap);
-    if (!bp) {
-        sp->reportOutOfMemory();
-        return -1;
+    if (!chars) {
+        reportOutOfMemory();
+        return false;
     }
-    offset = sp->put(bp);
-    js_free(bp);
-    return offset;
+
+    return put(chars.get()) >= 0;
 }
 
 const char js_EscapeMap[] = {
     '\b', 'b',
     '\f', 'f',
     '\n', 'n',
     '\r', 'r',
     '\t', 't',
@@ -296,18 +291,20 @@ const char js_EscapeMap[] = {
 
 template <typename CharT>
 static char*
 QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote)
 {
     /* Sample off first for later return value pointer computation. */
     ptrdiff_t offset = sp->getOffset();
 
-    if (quote && Sprint(sp, "%c", char(quote)) < 0)
-        return nullptr;
+    if (quote) {
+        if (!sp->jsprintf("%c", char(quote)))
+            return nullptr;
+    }
 
     const CharT* end = s + length;
 
     /* Loop control variables: end points at end of string sentinel. */
     for (const CharT* t = s; t < end; s = ++t) {
         /* Move t forward from s past un-quote-worthy characters. */
         char16_t c = *t;
         while (c < 127 && isprint(c) && c != quote && c != '\\' && c != '\t') {
@@ -328,39 +325,43 @@ QuoteString(Sprinter* sp, const CharT* s
         }
 
         if (t == end)
             break;
 
         /* Use js_EscapeMap, \u, or \x only if necessary. */
         const char* escape;
         if (!(c >> 8) && c != 0 && (escape = strchr(js_EscapeMap, int(c))) != nullptr) {
-            if (Sprint(sp, "\\%c", escape[1]) < 0)
+            if (!sp->jsprintf("\\%c", escape[1]))
                 return nullptr;
         } else {
             /*
              * Use \x only if the high byte is 0 and we're in a quoted string,
              * because ECMA-262 allows only \u, not \x, in Unicode identifiers
              * (see bug 621814).
              */
-            if (Sprint(sp, (quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c) < 0)
+            if (!sp->jsprintf((quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c))
                 return nullptr;
         }
     }
 
     /* Sprint the closing quote and return the quoted string. */
-    if (quote && Sprint(sp, "%c", char(quote)) < 0)
-        return nullptr;
+    if (quote) {
+        if (!sp->jsprintf("%c", char(quote)))
+            return nullptr;
+    }
 
     /*
      * If we haven't Sprint'd anything yet, Sprint an empty string so that
      * the return below gives a valid result.
      */
-    if (offset == sp->getOffset() && Sprint(sp, "") < 0)
-        return nullptr;
+    if (offset == sp->getOffset()) {
+        if (sp->put("") < 0)
+            return nullptr;
+    }
 
     return sp->stringAt(offset);
 }
 
 char*
 QuoteString(Sprinter* sp, JSString* str, char16_t quote)
 {
     JSLinearString* linear = str->ensureLinear(sp->context);
@@ -437,28 +438,20 @@ Fprinter::finish()
     file_ = nullptr;
 }
 
 int
 Fprinter::put(const char* s, size_t len)
 {
     MOZ_ASSERT(file_);
     int i = fwrite(s, len, 1, file_);
-    if (i == -1 || i != int(len))
+    if (size_t(i) != len) {
         reportOutOfMemory();
-    return i;
-}
-
-int
-Fprinter::put(const char* s)
-{
-    MOZ_ASSERT(file_);
-    int i = fputs(s, file_);
-    if (i == -1)
-        reportOutOfMemory();
+        return -1;
+    }
     return i;
 }
 
 int
 Fprinter::printf(const char* fmt, ...)
 {
     MOZ_ASSERT(file_);
     va_list ap;
@@ -511,69 +504,78 @@ LSprinter::clear()
     tail_ = nullptr;
     unused_ = 0;
     hadOOM_ = false;
 }
 
 int
 LSprinter::put(const char* s, size_t len)
 {
-    size_t origLen = len;
+    // Compute how much data will fit in the current chunk.
+    size_t existingSpaceWrite = 0;
+    size_t overflow = len;
     if (unused_ > 0 && tail_) {
-        size_t minLen = unused_ < len ? unused_ : len;
-        js_memcpy(tail_->end() - unused_, s, minLen);
-        unused_ -= minLen;
-        len -= minLen;
-        s += minLen;
+        existingSpaceWrite = std::min(unused_, len);
+        overflow = len - existingSpaceWrite;
     }
 
-    if (len == 0)
-        return origLen;
+    // If necessary, allocate a new chunk for overflow data.
+    size_t allocLength = 0;
+    Chunk* last = nullptr;
+    if (overflow > 0) {
+        allocLength = AlignBytes(sizeof(Chunk) + overflow, js::detail::LIFO_ALLOC_ALIGN);
 
-    size_t allocLength = AlignBytes(sizeof(Chunk) + len, js::detail::LIFO_ALLOC_ALIGN);
-    Chunk* last = nullptr;
-    {
         LifoAlloc::AutoFallibleScope fallibleAllocator(alloc_);
         last = reinterpret_cast<Chunk*>(alloc_->alloc(allocLength));
-    }
-    if (!last) {
-        reportOutOfMemory();
-        return origLen - len;
+        if (!last) {
+            reportOutOfMemory();
+            return -1;
+        }
     }
 
-    if (tail_ && reinterpret_cast<char*>(last) == tail_->end()) {
-        // tail_ and last are next to each others in memory, knowing that the
-        // TempAlloctator has no meta data and is just a bump allocator, we
-        // append the new allocated space to the tail_.
-        unused_ = allocLength;
-        tail_->length += allocLength;
-    } else {
-        // Remove the size of the header from the allocated length.
-        allocLength -= sizeof(Chunk);
-        last->next = nullptr;
-        last->length = allocLength;
-        unused_ = allocLength;
-        if (!head_)
-            head_ = last;
-        else
-            tail_->next = last;
+    // All fallible operations complete: now fill up existing space, then
+    // overflow space in any new chunk.
+    MOZ_ASSERT(existingSpaceWrite + overflow == len);
 
-        tail_ = last;
+    if (existingSpaceWrite > 0) {
+        PodCopy(tail_->end() - unused_, s, existingSpaceWrite);
+        unused_ -= existingSpaceWrite;
+        s += existingSpaceWrite;
     }
 
-    MOZ_ASSERT(tail_->length >= unused_);
-    js_memcpy(tail_->end() - unused_, s, len);
-    unused_ -= len;
-    return origLen;
-}
+    if (overflow > 0) {
+        if (tail_ && reinterpret_cast<char*>(last) == tail_->end()) {
+            // tail_ and last are consecutive in memory.  LifoAlloc has no
+            // metadata and is just a bump allocator, so we can cheat by
+            // appending the newly-allocated space to tail_.
+            unused_ = allocLength;
+            tail_->length += allocLength;
+        } else {
+            // Remove the size of the header from the allocated length.
+            size_t availableSpace = allocLength - sizeof(Chunk);
+            last->next = nullptr;
+            last->length = availableSpace;
 
-int
-LSprinter::put(const char* s)
-{
-    return put(s, strlen(s));
+            unused_ = availableSpace;
+            if (!head_)
+                head_ = last;
+            else
+                tail_->next = last;
+
+            tail_ = last;
+        }
+
+        PodCopy(tail_->end() - unused_, s, overflow);
+
+        MOZ_ASSERT(unused_ >= overflow);
+        unused_ -= overflow;
+    }
+
+    MOZ_ASSERT(len <= INT_MAX);
+    return int(len);
 }
 
 int
 LSprinter::printf(const char* fmt, ...)
 {
     va_list va;
     va_start(va, fmt);
     int i = vprintf(fmt, va);
--- a/js/src/vm/Printer.h
+++ b/js/src/vm/Printer.h
@@ -7,16 +7,17 @@
 #ifndef vm_Printer_h
 #define vm_Printer_h
 
 #include "mozilla/Attributes.h"
 
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <string.h>
 
 class JSString;
 
 namespace js {
 
 class ExclusiveContext;
 class LifoAlloc;
 
@@ -31,17 +32,20 @@ class GenericPrinter
     bool                  hadOOM_;     // whether reportOutOfMemory() has been called.
 
     GenericPrinter();
 
   public:
     // Puts |len| characters from |s| at the current position and return an offset to
     // the beginning of this new data.
     virtual int put(const char* s, size_t len) = 0;
-    virtual int put(const char* s);
+
+    inline int put(const char* s) {
+        return put(s, strlen(s));
+    }
 
     // Prints a formatted string into the buffer.
     virtual int printf(const char* fmt, ...);
     virtual int vprintf(const char* fmt, va_list ap);
 
     // Report that a string operation failed to get the memory it requested. The
     // first call to this function calls JS_ReportOutOfMemory, and sets this
     // Sprinter's outOfMemory flag; subsequent calls do nothing.
@@ -100,18 +104,23 @@ class Sprinter final : public GenericPri
 
     // Attempt to reserve len + 1 space (for a trailing nullptr byte). If the
     // attempt succeeds, return a pointer to the start of that space and adjust the
     // internal content. The caller *must* completely fill this space on success.
     char* reserve(size_t len);
 
     // Puts |len| characters from |s| at the current position and return an offset to
     // the beginning of this new data.
-    using GenericPrinter::put;
     virtual int put(const char* s, size_t len) override;
+    using GenericPrinter::put; // pick up |inline int put(const char* s);|
+
+    // Format the given format/arguments as if by JS_vsmprintf, then put it.
+    // Return true on success, else return false and report an error (typically
+    // OOM).
+    MOZ_MUST_USE bool jsprintf(const char* fmt, ...);
 
     // Prints a formatted string into the buffer.
     virtual int vprintf(const char* fmt, va_list ap) override;
 
     int putString(JSString* str);
 
     ptrdiff_t getOffset() const;
 
@@ -140,17 +149,17 @@ class Fprinter final : public GenericPri
         return file_ != nullptr;
     }
     void flush();
     void finish();
 
     // Puts |len| characters from |s| at the current position and return an
     // offset to the beginning of this new data.
     virtual int put(const char* s, size_t len) override;
-    virtual int put(const char* s) override;
+    using GenericPrinter::put; // pick up |inline int put(const char* s);|
 
     // Prints a formatted string into the buffer.
     virtual int printf(const char* fmt, ...) override;
     virtual int vprintf(const char* fmt, va_list ap) override;
 };
 
 // LSprinter, is similar to Sprinter except that instead of using an
 // ExclusiveContext to allocate strings, it use a LifoAlloc as a backend for the
@@ -186,34 +195,31 @@ class LSprinter final : public GenericPr
     void exportInto(GenericPrinter& out) const;
 
     // Drop the current string, and let them be free with the LifoAlloc.
     void clear();
 
     // Puts |len| characters from |s| at the current position and return an
     // offset to the beginning of this new data.
     virtual int put(const char* s, size_t len) override;
-    virtual int put(const char* s) override;
+    using GenericPrinter::put; // pick up |inline int put(const char* s);|
 
     // Prints a formatted string into the buffer.
     virtual int printf(const char* fmt, ...) override;
     virtual int vprintf(const char* fmt, va_list ap) override;
 
     // Report that a string operation failed to get the memory it requested. The
     // first call to this function calls JS_ReportOutOfMemory, and sets this
     // Sprinter's outOfMemory flag; subsequent calls do nothing.
     virtual void reportOutOfMemory() override;
 
     // Return true if this Sprinter ran out of memory.
     virtual bool hadOutOfMemory() const override;
 };
 
-extern ptrdiff_t
-Sprint(Sprinter* sp, const char* format, ...);
-
 // Map escaped code to the letter/symbol escaped with a backslash.
 extern const char       js_EscapeMap[];
 
 // Return a GC'ed string containing the chars in str, with any non-printing
 // chars or quotes (' or " as specified by the quote argument) escaped, and
 // with the quote character at the beginning and end of the result string.
 extern JSString*
 QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote);
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4476,16 +4476,17 @@ TypeZone::clearAllNewScriptsOnOOM()
             group->maybeClearNewScriptOnOOM();
     }
 }
 
 AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM()
 {
     if (oom) {
         JSRuntime* rt = zone->runtimeFromMainThread();
+        js::CancelOffThreadIonCompile(rt);
         zone->setPreservingCode(false);
         zone->discardJitCode(rt->defaultFreeOp());
         zone->types.clearAllNewScriptsOnOOM();
     }
 }
 
 #ifdef DEBUG
 void
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -635,17 +635,16 @@ XPCConvert::JSData2Native(void* d, Handl
 
         return true;
     }
 
     case nsXPTType::T_CSTRING:
     {
         if (s.isNull() || s.isUndefined()) {
             nsACString* rs = *((nsACString**)d);
-            rs->Truncate();
             rs->SetIsVoid(true);
             return true;
         }
 
         // The JS val is neither null nor void...
         JSString* str = ToString(cx, s);
         if (!str) {
             return false;
--- a/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
+++ b/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
@@ -49,16 +49,21 @@ function run_test()
   httpserver2.registerPathHandler(negativetestpath, serverHandler);
   httpserver2.start(4445);
 
   // Test sync XHR sending
   cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
   var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
   do_check_true(checkResults(res));
 
+  var principal = res.responseXML.nodePrincipal;
+  do_check_true(principal.isCodebasePrincipal);
+  var requestURL = "http://localhost:4444/simple";
+  do_check_eq(principal.URI.spec, requestURL);
+
   // negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
   try {
     cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
     var res = cu.evalInSandbox('var sync = createXHR("4445/negative"); sync.send(null); sync', sb);
     do_check_false(true, "XHR created from sandbox should not have chrome caps");
   } catch (e) {
     do_check_true(true);
   }
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -3757,36 +3757,27 @@ nsDocumentViewer::Print(nsIPrintSettings
 #endif
                                   );
     if (NS_FAILED(rv)) {
       mPrintEngine->Destroy();
       mPrintEngine = nullptr;
       return rv;
     }
   }
-
+  if (mPrintEngine->HasPrintCallbackCanvas()) {
+    mBeforeAndAfterPrint = beforeAndAfterPrint;
+  }
   dom::Element* root = mDocument->GetRootElement();
   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
     mPrintEngine->SetDisallowSelectionPrint(true);
   }
   rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener);
   if (NS_FAILED(rv)) {
     OnDonePrinting();
-  } else if (GetIsPrinting()) {
-    if (mPrintEngine->HasPrintCallbackCanvas() ||
-        mPrintEngine->MayHavePluginFrames()) {
-      mBeforeAndAfterPrint = beforeAndAfterPrint;
-    } else {
-      // Since printing cloned the document and doesn't need plugin or canvas data
-      // from the original document, we can clear the print flag in the docshell
-      // tree early, before afterprint is dispatched.
-      SetIsPrinting(false);
-    }
   }
-
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings, 
                                mozIDOMWindowProxy* aChildDOMWin, 
                                nsIWebProgressListener* aWebProgressListener)
 {
@@ -3841,36 +3832,29 @@ nsDocumentViewer::PrintPreview(nsIPrintS
 #endif
                                   );
     if (NS_FAILED(rv)) {
       mPrintEngine->Destroy();
       mPrintEngine = nullptr;
       return rv;
     }
   }
-
+  if (mPrintEngine->HasPrintCallbackCanvas()) {
+    mBeforeAndAfterPrint = beforeAndAfterPrint;
+  }
   dom::Element* root = doc->GetRootElement();
   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) {
     PR_PL(("PrintPreview: found mozdisallowselectionprint"));
     mPrintEngine->SetDisallowSelectionPrint(true);
   }
   rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener);
   mPrintPreviewZoomed = false;
   if (NS_FAILED(rv)) {
     OnDonePrinting();
-  } else if (GetIsPrintPreview() &&
-             (mPrintEngine->HasPrintCallbackCanvas() ||
-              mPrintEngine->MayHavePluginFrames())) {
-    mBeforeAndAfterPrint = beforeAndAfterPrint;
   }
-
-  // Unlike in printing case we don't explicitly call SetIsPrintPreview(false);
-  // here, since this ContentViewer is for the cloned document, not for the
-  // original document.
-
   return rv;
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
 //----------------------------------------------------------------------
 NS_IMETHODIMP
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -103,16 +103,17 @@
 #include "ClientLayerManager.h"
 #include "nsRefreshDriver.h"
 #include "nsIContentViewer.h"
 #include "LayersLogging.h"
 #include "mozilla/Preferences.h"
 #include "nsFrameSelection.h"
 #include "FrameLayerBuilder.h"
 #include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/RuleNodeCacheConditions.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "RegionBuilder.h"
 
@@ -9287,20 +9288,21 @@ static void UpdateDisplayPortMarginsForP
   CSSPoint frameScrollOffset = CSSPoint::FromAppUnits(frame->GetScrollPosition());
   APZCCallbackHelper::AdjustDisplayPortForScrollDelta(aMetrics, frameScrollOffset);
 
   nsLayoutUtils::SetDisplayPortMargins(content, shell,
                                        aMetrics.GetDisplayPortMargins(), 0);
 }
 
 /* static */ void
-nsLayoutUtils::UpdateDisplayPortMarginsFromPendingMessages() {
+nsLayoutUtils::UpdateDisplayPortMarginsFromPendingMessages()
+{
   if (mozilla::dom::ContentChild::GetSingleton() &&
       mozilla::dom::ContentChild::GetSingleton()->GetIPCChannel()) {
-    mozilla::dom::ContentChild::GetSingleton()->GetIPCChannel()->PeekMessages(
+    CompositorBridgeChild::Get()->GetIPCChannel()->PeekMessages(
       [](const IPC::Message& aMsg) -> bool {
         if (aMsg.type() == mozilla::layers::PAPZ::Msg_RequestContentRepaint__ID) {
           PickleIterator iter(aMsg);
           FrameMetrics frame;
           if (!IPC::ReadParam(&aMsg, &iter, &frame)) {
             MOZ_ASSERT(false);
             return true;
           }
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1279814.html
@@ -0,0 +1,35 @@
+<!-- 128 LRI / RLI -->
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+<!-- 64 PDI -->
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;&#x2069;
+<!-- 64 LRI / RLI -->
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
+&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;&#x2066;&#x2067;
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -626,15 +626,16 @@ load text-overflow-bug713610.html
 load text-overflow-form-elements.html
 load text-overflow-iframe.html
 asserts-if(Android,2-4) asserts-if(!Android,4) load 1225005.html # bug 682647 and bug 448083
 load 1233191.html
 asserts(2) load 1272983-1.html # bug 586628
 asserts(2) load 1272983-2.html # bug 586628
 load 1275059.html
 load 1278007.html
+load 1279814.html
 load large-border-radius-dashed.html
 load large-border-radius-dashed2.html
 load large-border-radius-dotted.html
 load large-border-radius-dotted2.html
 load 1297427-non-equal-centers.html
 load 1278461-1.html
 load 1278461-2.html
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -39,16 +39,24 @@ typedef nsTHashtable< nsPtrHashKey<nsIFr
 // https://drafts.csswg.org/css-align-3/#baseline-sharing-group
 enum BaselineSharingGroup
 {
   // NOTE Used as an array index so must be 0 and 1.
   eFirst = 0,
   eLast = 1,
 };
 
+// https://drafts.csswg.org/css-sizing/#constraints
+enum class SizingConstraint
+{
+  eMinContent,  // sizing under min-content constraint
+  eMaxContent,  // sizing under max-content constraint
+  eNoConstraint // no constraint, used during Reflow
+};
+
 static void
 ReparentFrame(nsIFrame* aFrame, nsContainerFrame* aOldParent,
               nsContainerFrame* aNewParent)
 {
   NS_ASSERTION(aOldParent == aFrame->GetParent(),
                "Parent not consistent with expectations");
 
   aFrame->SetParent(aNewParent);
@@ -133,17 +141,17 @@ struct nsGridContainerFrame::TrackSize
   void Dump() const;
 #endif
   enum StateBits : uint16_t {
     eAutoMinSizing =           0x1,
     eMinContentMinSizing =     0x2,
     eMaxContentMinSizing =     0x4,
     eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
     eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
-    eFlexMinSizing =           0x8, // not really used ATM due to a spec change
+    // 0x8 is unused, feel free to take it!
     eAutoMaxSizing =          0x10,
     eMinContentMaxSizing =    0x20,
     eMaxContentMaxSizing =    0x40,
     eAutoOrMaxContentMaxSizing = eAutoMaxSizing | eMaxContentMaxSizing,
     eIntrinsicMaxSizing = eAutoOrMaxContentMaxSizing | eMinContentMaxSizing,
     eFlexMaxSizing =          0x80,
     eFrozen =                0x100,
     eSkipGrowUnlimited1 =    0x200,
@@ -1122,23 +1130,21 @@ struct nsGridContainerFrame::Tracks
                   const nsStyleCoord&         aGridGap,
                   uint32_t                    aNumTracks,
                   nscoord                     aContentBoxSize);
 
   /**
    * Return true if aRange spans at least one track with an intrinsic sizing
    * function and does not span any tracks with a <flex> max-sizing function.
    * @param aRange the span of tracks to check
-   * @param aConstraint if MIN_ISIZE, treat a <flex> min-sizing as 'min-content'
    * @param aState will be set to the union of the state bits of all the spanned
    *               tracks, unless a flex track is found - then it only contains
    *               the union of the tracks up to and including the flex track.
    */
   bool HasIntrinsicButNoFlexSizingInRange(const LineRange&      aRange,
-                                          IntrinsicISizeType    aConstraint,
                                           TrackSize::StateBits* aState) const;
 
   // Some data we collect for aligning baseline-aligned items.
   struct ItemBaselineData
   {
     uint32_t mBaselineTrack;
     nscoord mBaseline;
     nscoord mSize;
@@ -1173,27 +1179,27 @@ struct nsGridContainerFrame::Tracks
    * Resolve Intrinsic Track Sizes.
    * http://dev.w3.org/csswg/css-grid/#algo-content
    */
   void ResolveIntrinsicSize(GridReflowInput&            aState,
                             nsTArray<GridItemInfo>&     aGridItems,
                             const TrackSizingFunctions& aFunctions,
                             LineRange GridArea::*       aRange,
                             nscoord                     aPercentageBasis,
-                            IntrinsicISizeType          aConstraint);
+                            SizingConstraint            aConstraint);
 
   /**
    * Helper for ResolveIntrinsicSize.  It implements step 1 "size tracks to fit
    * non-spanning items" in the spec.  Return true if the track has a <flex>
    * max-sizing function, false otherwise.
    */
   bool ResolveIntrinsicSizeStep1(GridReflowInput&            aState,
                                  const TrackSizingFunctions& aFunctions,
                                  nscoord                     aPercentageBasis,
-                                 IntrinsicISizeType          aConstraint,
+                                 SizingConstraint            aConstraint,
                                  const LineRange&            aRange,
                                  const GridItemInfo&         aGridItem);
   /**
    * Collect the tracks which are growable (matching aSelector) into
    * aGrowableTracks, and return the amount of space that can be used
    * to grow those tracks.  Specifically, we return aAvailableSpace minus
    * the sum of mBase's (and corresponding grid gaps) in aPlan (clamped to 0)
    * for the tracks in aRange, or zero when there are no growable tracks.
@@ -1354,27 +1360,25 @@ struct nsGridContainerFrame::Tracks
                                    nsTArray<TrackSize>&      aPlan,
                                    const nsTArray<uint32_t>& aGrowableTracks,
                                    TrackSize::StateBits      aSelector,
                                    FitContentClamper aFitContentClamper) const
   {
     MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0);
     uint32_t numGrowable = aGrowableTracks.Length();
     if (aSelector) {
-      DebugOnly<TrackSize::StateBits> withoutFlexMin =
-        TrackSize::StateBits(aSelector & ~TrackSize::eFlexMinSizing);
-      MOZ_ASSERT(withoutFlexMin == TrackSize::eIntrinsicMinSizing ||
-                 withoutFlexMin == TrackSize::eMinOrMaxContentMinSizing ||
-                 withoutFlexMin == TrackSize::eMaxContentMinSizing);
+      MOZ_ASSERT(aSelector == (aSelector & TrackSize::eIntrinsicMinSizing) &&
+                 (aSelector & TrackSize::eMaxContentMinSizing),
+                 "Should only get here for track sizing steps 2.1 to 2.3");
       // Note that eMaxContentMinSizing is always included. We do those first:
       numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
                                        TrackSize::eMaxContentMinSizing,
                                        TrackSize::eMaxContentMaxSizing,
                                        TrackSize::eSkipGrowUnlimited1);
-      // Now mark min-content/auto/<flex> min-sizing tracks if requested.
+      // Now mark min-content/auto min-sizing tracks if requested.
       auto minOrAutoSelector = aSelector & ~TrackSize::eMaxContentMinSizing;
       if (minOrAutoSelector) {
         numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
                                          minOrAutoSelector,
                                          TrackSize::eIntrinsicMaxSizing,
                                          TrackSize::eSkipGrowUnlimited2);
       }
     }
@@ -1542,17 +1546,17 @@ struct nsGridContainerFrame::Tracks
    * Implements "12.3. Track Sizing Algorithm"
    * http://dev.w3.org/csswg/css-grid/#algo-track-sizing
    */
   void CalculateSizes(GridReflowInput&            aState,
                       nsTArray<GridItemInfo>&     aGridItems,
                       const TrackSizingFunctions& aFunctions,
                       nscoord                     aContentSize,
                       LineRange GridArea::*       aRange,
-                      IntrinsicISizeType          aConstraint);
+                      SizingConstraint            aConstraint);
 
   /**
    * Apply 'align/justify-content', whichever is relevant for this axis.
    * https://drafts.csswg.org/css-align-3/#propdef-align-content
    */
   void AlignJustifyContent(const nsStylePosition* aStyle,
                            WritingMode            aWM,
                            const LogicalSize&     aContainerSize);
@@ -1861,17 +1865,17 @@ struct MOZ_STACK_CLASS nsGridContainerFr
     }
   }
 
   /**
    * Calculate our track sizes.
    */
   void CalculateTrackSizes(const Grid&        aGrid,
                            const LogicalSize& aContentBox,
-                           IntrinsicISizeType aConstraint);
+                           SizingConstraint   aConstraint);
 
   /**
    * Return the containing block for a grid item occupying aArea.
    */
   LogicalRect ContainingBlockFor(const GridArea& aArea) const;
 
   /**
    * Return the containing block for an abs.pos. grid item occupying aArea.
@@ -2326,17 +2330,17 @@ struct MOZ_STACK_CLASS nsGridContainerFr
   uint32_t mExplicitGridOffsetCol;
   uint32_t mExplicitGridOffsetRow;
 };
 
 void
 nsGridContainerFrame::GridReflowInput::CalculateTrackSizes(
   const Grid&        aGrid,
   const LogicalSize& aContentBox,
-  IntrinsicISizeType aConstraint)
+  SizingConstraint   aConstraint)
 {
   mCols.Initialize(mColFunctions, mGridStyle->mGridColumnGap,
                    aGrid.mGridColEnd, aContentBox.ISize(mWM));
   mRows.Initialize(mRowFunctions, mGridStyle->mGridRowGap,
                    aGrid.mGridRowEnd, aContentBox.BSize(mWM));
 
   mCols.CalculateSizes(*this, mGridItems, mColFunctions,
                        aContentBox.ISize(mWM), &GridArea::mCols,
@@ -3629,117 +3633,148 @@ ContentContribution(const GridItemInfo& 
              "baseline offset should be non-negative at this point");
   MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||
              aGridItem.mBaselineOffset[aAxis] == nscoord(0),
              "baseline offset should be zero when not baseline-aligned");
   size += aGridItem.mBaselineOffset[aAxis];
   return std::max(size, 0);
 }
 
+struct CachedIntrinsicSizes
+{
+  Maybe<nscoord> mMinSize;
+  Maybe<nscoord> mMinContentContribution;
+  Maybe<nscoord> mMaxContentContribution;
+};
+
 static nscoord
 MinContentContribution(const GridItemInfo&    aGridItem,
                        const GridReflowInput& aState,
                        nsRenderingContext*    aRC,
                        WritingMode            aCBWM,
-                       LogicalAxis            aAxis)
+                       LogicalAxis            aAxis,
+                       CachedIntrinsicSizes*  aCache)
 {
-  return ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
-                             nsLayoutUtils::MIN_ISIZE);
+  if (aCache->mMinContentContribution.isSome()) {
+    return aCache->mMinContentContribution.value();
+  }
+  nscoord s = ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
+                                  nsLayoutUtils::MIN_ISIZE);
+  aCache->mMinContentContribution.emplace(s);
+  return s;
 }
 
 static nscoord
 MaxContentContribution(const GridItemInfo&    aGridItem,
                        const GridReflowInput& aState,
                        nsRenderingContext*    aRC,
                        WritingMode            aCBWM,
-                       LogicalAxis            aAxis)
+                       LogicalAxis            aAxis,
+                       CachedIntrinsicSizes*  aCache)
 {
-  return ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
-                             nsLayoutUtils::PREF_ISIZE);
+  if (aCache->mMaxContentContribution.isSome()) {
+    return aCache->mMaxContentContribution.value();
+  }
+  nscoord s = ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
+                                  nsLayoutUtils::PREF_ISIZE);
+  aCache->mMaxContentContribution.emplace(s);
+  return s;
 }
 
+// Computes the min-size contribution for a grid item, as defined at
+// https://drafts.csswg.org/css-grid/#min-size-contributions
 static nscoord
 MinSize(const GridItemInfo&    aGridItem,
         const GridReflowInput& aState,
         nsRenderingContext*    aRC,
         WritingMode            aCBWM,
-        LogicalAxis            aAxis)
+        LogicalAxis            aAxis,
+        CachedIntrinsicSizes*  aCache)
 {
+  if (aCache->mMinSize.isSome()) {
+    return aCache->mMinSize.value();
+  }
   nsIFrame* child = aGridItem.mFrame;
   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
   const nsStylePosition* stylePos = child->StylePosition();
-  const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth
-                                                      : stylePos->mMinHeight;
+  const nsStyleCoord& sizeStyle =
+    axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight;
+  if (sizeStyle.GetUnit() != eStyleUnit_Auto) {
+    nscoord s =
+      MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache);
+    aCache->mMinSize.emplace(s);
+    return s;
+  }
+
   // https://drafts.csswg.org/css-grid/#min-size-auto
   // This calculates the min-content contribution from either a definite
   // min-width (or min-height depending on aAxis), or the "specified /
   // transferred size" for min-width:auto if overflow == visible (as min-width:0
   // otherwise), or NS_UNCONSTRAINEDSIZE for other min-width intrinsic values
   // (which results in always taking the "content size" part below).
   MOZ_ASSERT(aGridItem.mBaselineOffset[aAxis] >= 0,
              "baseline offset should be non-negative at this point");
   MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||
              aGridItem.mBaselineOffset[aAxis] == nscoord(0),
              "baseline offset should be zero when not baseline-aligned");
   nscoord sz = aGridItem.mBaselineOffset[aAxis] +
     nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, child,
                                               nsLayoutUtils::MIN_ISIZE);
+  const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth
+                                                      : stylePos->mMinHeight;
   auto unit = style.GetUnit();
   if (unit == eStyleUnit_Enumerated ||
       (unit == eStyleUnit_Auto &&
        child->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) {
     // Now calculate the "content size" part and return whichever is smaller.
     MOZ_ASSERT(unit != eStyleUnit_Enumerated || sz == NS_UNCONSTRAINEDSIZE);
     sz = std::min(sz, ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
                                           nsLayoutUtils::MIN_ISIZE,
                                           nsLayoutUtils::MIN_INTRINSIC_ISIZE));
   }
+  aCache->mMinSize.emplace(sz);
   return sz;
 }
 
 void
 nsGridContainerFrame::Tracks::CalculateSizes(
   GridReflowInput&            aState,
   nsTArray<GridItemInfo>&     aGridItems,
   const TrackSizingFunctions& aFunctions,
   nscoord                     aContentBoxSize,
   LineRange GridArea::*       aRange,
-  IntrinsicISizeType          aConstraint)
+  SizingConstraint            aConstraint)
 {
   nscoord percentageBasis = aContentBoxSize;
   if (percentageBasis == NS_UNCONSTRAINEDSIZE) {
     percentageBasis = 0;
   }
   InitializeItemBaselines(aState, aGridItems);
   ResolveIntrinsicSize(aState, aGridItems, aFunctions, aRange, percentageBasis,
                        aConstraint);
-  if (aConstraint != nsLayoutUtils::MIN_ISIZE) {
+  if (aConstraint != SizingConstraint::eMinContent) {
     nscoord freeSpace = aContentBoxSize;
     if (freeSpace != NS_UNCONSTRAINEDSIZE) {
       freeSpace -= SumOfGridGaps();
     }
     DistributeFreeSpace(freeSpace);
     StretchFlexibleTracks(aState, aGridItems, aFunctions, freeSpace);
   }
 }
 
 bool
 nsGridContainerFrame::Tracks::HasIntrinsicButNoFlexSizingInRange(
   const LineRange&      aRange,
-  IntrinsicISizeType    aConstraint,
   TrackSize::StateBits* aState) const
 {
   MOZ_ASSERT(!aRange.IsAuto(), "must have a definite range");
   const uint32_t start = aRange.mStart;
   const uint32_t end = aRange.mEnd;
   const TrackSize::StateBits selector =
-    TrackSize::eIntrinsicMinSizing |
-    TrackSize::eIntrinsicMaxSizing |
-    (aConstraint == nsLayoutUtils::MIN_ISIZE ? TrackSize::eFlexMinSizing
-                                             : TrackSize::StateBits(0));
+    TrackSize::eIntrinsicMinSizing | TrackSize::eIntrinsicMaxSizing;
   bool foundIntrinsic = false;
   for (uint32_t i = start; i < end; ++i) {
     TrackSize::StateBits state = mSizes[i].mState;
     *aState |= state;
     if (state & TrackSize::eFlexMaxSizing) {
       return false;
     }
     if (state & selector) {
@@ -3749,61 +3784,58 @@ nsGridContainerFrame::Tracks::HasIntrins
   return foundIntrinsic;
 }
 
 bool
 nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
   GridReflowInput&            aState,
   const TrackSizingFunctions& aFunctions,
   nscoord                     aPercentageBasis,
-  IntrinsicISizeType          aConstraint,
+  SizingConstraint            aConstraint,
   const LineRange&            aRange,
   const GridItemInfo&         aGridItem)
 {
-  Maybe<nscoord> minContentContribution;
-  Maybe<nscoord> maxContentContribution;
+  CachedIntrinsicSizes cache;
   // min sizing
   TrackSize& sz = mSizes[aRange.mStart];
   WritingMode wm = aState.mWM;
   nsRenderingContext* rc = &aState.mRenderingContext;
   if (sz.mState & TrackSize::eAutoMinSizing) {
-    nscoord s = MinSize(aGridItem, aState, rc, wm, mAxis);
+    nscoord s;
+    if (aConstraint == SizingConstraint::eMinContent) {
+      s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
+    } else if (aConstraint == SizingConstraint::eMaxContent) {
+      s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
+    } else {
+      MOZ_ASSERT(aConstraint == SizingConstraint::eNoConstraint);
+      s = MinSize(aGridItem, aState, rc, wm, mAxis, &cache);
+    }
     sz.mBase = std::max(sz.mBase, s);
-  } else if ((sz.mState & TrackSize::eMinContentMinSizing) ||
-             (aConstraint == nsLayoutUtils::MIN_ISIZE &&
-              (sz.mState & TrackSize::eFlexMinSizing))) {
-    nscoord s = MinContentContribution(aGridItem, aState, rc, wm, mAxis);
-    minContentContribution.emplace(s);
-    sz.mBase = std::max(sz.mBase, minContentContribution.value());
+  } else if (sz.mState & TrackSize::eMinContentMinSizing) {
+    auto s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
+    sz.mBase = std::max(sz.mBase, s);
   } else if (sz.mState & TrackSize::eMaxContentMinSizing) {
-    nscoord s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis);
-    maxContentContribution.emplace(s);
-    sz.mBase = std::max(sz.mBase, maxContentContribution.value());
+    auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
+    sz.mBase = std::max(sz.mBase, s);
   }
   // max sizing
   if (sz.mState & TrackSize::eMinContentMaxSizing) {
-    if (minContentContribution.isNothing()) {
-      nscoord s = MinContentContribution(aGridItem, aState, rc, wm, mAxis);
-      minContentContribution.emplace(s);
-    }
+    auto s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
-      sz.mLimit = minContentContribution.value();
+      sz.mLimit = s;
     } else {
-      sz.mLimit = std::max(sz.mLimit, minContentContribution.value());
+      sz.mLimit = std::max(sz.mLimit, s);
     }
   } else if (sz.mState & (TrackSize::eAutoMaxSizing |
                           TrackSize::eMaxContentMaxSizing)) {
-    if (maxContentContribution.isNothing()) {
-      nscoord s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis);
-      maxContentContribution.emplace(s);
-    }
+    auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
-      sz.mLimit = maxContentContribution.value();
+      sz.mLimit = s;
     } else {
-      sz.mLimit = std::max(sz.mLimit, maxContentContribution.value());
+      sz.mLimit = std::max(sz.mLimit, s);
     }
     if (MOZ_UNLIKELY(sz.mState & TrackSize::eFitContent)) {
       // Clamp mLimit to the fit-content() size, for ยง12.5.1.
       auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
       nscoord fitContentClamp =
         nsRuleNode::ComputeCoordPercentCalc(maxCoord, aPercentageBasis);
       sz.mLimit = std::min(sz.mLimit, fitContentClamp);
     }
@@ -4078,17 +4110,17 @@ nsGridContainerFrame::Tracks::AlignBasel
 
 void
 nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
   GridReflowInput&            aState,
   nsTArray<GridItemInfo>&     aGridItems,
   const TrackSizingFunctions& aFunctions,
   LineRange GridArea::*       aRange,
   nscoord                     aPercentageBasis,
-  IntrinsicISizeType          aConstraint)
+  SizingConstraint            aConstraint)
 {
   // Some data we collect on each item for Step 2 of the algorithm below.
   struct Step2ItemData
   {
     uint32_t mSpan;
     TrackSize::StateBits mState;
     LineRange mLineRange;
     nscoord mMinSize;
@@ -4106,59 +4138,66 @@ nsGridContainerFrame::Tracks::ResolveInt
   // We're also setting eIsFlexing on the item state here to speed up
   // FindUsedFlexFraction later.
   AutoTArray<TrackSize::StateBits, 16> stateBitsPerSpan;
   nsTArray<Step2ItemData> step2Items;
   GridItemCSSOrderIterator& iter = aState.mIter;
   nsRenderingContext* rc = &aState.mRenderingContext;
   WritingMode wm = aState.mWM;
   uint32_t maxSpan = 0; // max span of the step2Items items
-  const TrackSize::StateBits flexMin =
-    aConstraint == nsLayoutUtils::MIN_ISIZE ? TrackSize::eFlexMinSizing
-                                            : TrackSize::StateBits(0);
+  // Setup track selector for step 2.2:
+  const auto contentBasedMinSelector =
+    aConstraint == SizingConstraint::eMinContent ?
+    TrackSize::eIntrinsicMinSizing : TrackSize::eMinOrMaxContentMinSizing;
+  // Setup track selector for step 2.3:
+  const auto maxContentMinSelector =
+    aConstraint == SizingConstraint::eMaxContent ?
+    (TrackSize::eMaxContentMinSizing | TrackSize::eAutoMinSizing) :
+    TrackSize::eMaxContentMinSizing;
   iter.Reset();
   for (; !iter.AtEnd(); iter.Next()) {
     auto& gridItem = aGridItems[iter.GridItemIndex()];
     const GridArea& area = gridItem.mArea;
     const LineRange& lineRange = area.*aRange;
     uint32_t span = lineRange.Extent();
     if (span == 1) {
       // Step 1. Size tracks to fit non-spanning items.
       if (ResolveIntrinsicSizeStep1(aState, aFunctions, aPercentageBasis,
                                     aConstraint, lineRange, gridItem)) {
         gridItem.mState[mAxis] |= ItemState::eIsFlexing;
       }
     } else {
       TrackSize::StateBits state = TrackSize::StateBits(0);
-      if (HasIntrinsicButNoFlexSizingInRange(lineRange, aConstraint, &state)) {
+      if (HasIntrinsicButNoFlexSizingInRange(lineRange, &state)) {
         // Collect data for Step 2.
         maxSpan = std::max(maxSpan, span);
         if (span >= stateBitsPerSpan.Length()) {
           uint32_t len = 2 * span;
           stateBitsPerSpan.SetCapacity(len);
           for (uint32_t i = stateBitsPerSpan.Length(); i < len; ++i) {
             stateBitsPerSpan.AppendElement(TrackSize::StateBits(0));
           }
         }
         stateBitsPerSpan[span] |= state;
+        CachedIntrinsicSizes cache;
         nscoord minSize = 0;
-        if (state & (flexMin | TrackSize::eIntrinsicMinSizing)) { // for 2.1
-          minSize = MinSize(gridItem, aState, rc, wm, mAxis);
+        if (state & (TrackSize::eIntrinsicMinSizing |   // for 2.1
+                     TrackSize::eIntrinsicMaxSizing)) { // for 2.5
+          minSize = MinSize(gridItem, aState, rc, wm, mAxis, &cache);
         }
         nscoord minContent = 0;
-        if (state & (flexMin | TrackSize::eMinOrMaxContentMinSizing | // for 2.2
-                     TrackSize::eIntrinsicMaxSizing)) {               // for 2.5
+        if (state & contentBasedMinSelector) { // for 2.2
           minContent = MinContentContribution(gridItem, aState,
-                                              rc, wm, mAxis);
+                                              rc, wm, mAxis, &cache);
         }
         nscoord maxContent = 0;
-        if (state & (TrackSize::eMaxContentMinSizing |         // for 2.3
+        if (state & (maxContentMinSelector |                   // for 2.3
                      TrackSize::eAutoOrMaxContentMaxSizing)) { // for 2.6
           maxContent = MaxContentContribution(gridItem, aState,
-                                              rc, wm, mAxis);
+                                              rc, wm, mAxis, &cache);
         }
         step2Items.AppendElement(
           Step2ItemData({span, state, lineRange, minSize,
                          minContent, maxContent, *iter}));
       } else if (state & TrackSize::eFlexMaxSizing) {
         gridItem.mState[mAxis] |= ItemState::eIsFlexing;
       }
     }
@@ -4181,17 +4220,17 @@ nsGridContainerFrame::Tracks::ResolveInt
       for (++i; i < len; ++i) {
         if (step2Items[i].mSpan != span) {
           spanGroupEndIndex = i;
           break;
         }
       }
 
       bool updatedBase = false; // Did we update any mBase in step 2.1 - 2.3?
-      TrackSize::StateBits selector(flexMin | TrackSize::eIntrinsicMinSizing);
+      TrackSize::StateBits selector(TrackSize::eIntrinsicMinSizing);
       if (stateBitsPerSpan[span] & selector) {
         // Step 2.1 MinSize to intrinsic min-sizing.
         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
           Step2ItemData& item = step2Items[i];
           if (!(item.mState & selector)) {
             continue;
           }
           nscoord space = item.mMinSize;
@@ -4203,19 +4242,20 @@ nsGridContainerFrame::Tracks::ResolveInt
                                   tracks);
           if (space > 0) {
             DistributeToTrackBases(space, plan, tracks, selector);
             updatedBase = true;
           }
         }
       }
 
-      selector = flexMin | TrackSize::eMinOrMaxContentMinSizing;
+      selector = contentBasedMinSelector;
       if (stateBitsPerSpan[span] & selector) {
-        // Step 2.2 MinContentContribution to min-/max-content min-sizing.
+        // Step 2.2 MinContentContribution to min-/max-content (and 'auto' when
+        // sizing under a min-content constraint) min-sizing.
         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
           Step2ItemData& item = step2Items[i];
           if (!(item.mState & selector)) {
             continue;
           }
           nscoord space = item.mMinContentContribution;
           if (space <= 0) {
             continue;
@@ -4225,34 +4265,34 @@ nsGridContainerFrame::Tracks::ResolveInt
                                   tracks);
           if (space > 0) {
             DistributeToTrackBases(space, plan, tracks, selector);
             updatedBase = true;
           }
         }
       }
 
-      if (stateBitsPerSpan[span] & TrackSize::eMaxContentMinSizing) {
-        // Step 2.3 MaxContentContribution to max-content min-sizing.
+      selector = maxContentMinSelector;
+      if (stateBitsPerSpan[span] & selector) {
+        // Step 2.3 MaxContentContribution to max-content (and 'auto' when
+        // sizing under a max-content constraint) min-sizing.
         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
           Step2ItemData& item = step2Items[i];
-          if (!(item.mState & TrackSize::eMaxContentMinSizing)) {
+          if (!(item.mState & selector)) {
             continue;
           }
           nscoord space = item.mMaxContentContribution;
           if (space <= 0) {
             continue;
           }
           tracks.ClearAndRetainStorage();
-          space = CollectGrowable(space, mSizes, item.mLineRange,
-                                  TrackSize::eMaxContentMinSizing,
+          space = CollectGrowable(space, mSizes, item.mLineRange, selector,
                                   tracks);
           if (space > 0) {
-            DistributeToTrackBases(space, plan, tracks,
-                                   TrackSize::eMaxContentMinSizing);
+            DistributeToTrackBases(space, plan, tracks, selector);
             updatedBase = true;
           }
         }
       }
 
       if (updatedBase) {
         // Step 2.4
         for (TrackSize& sz : mSizes) {
@@ -4266,23 +4306,23 @@ nsGridContainerFrame::Tracks::ResolveInt
         for (TrackSize& sz : plan) {
           if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
             // use mBase as the planned limit
           } else {
             sz.mBase = sz.mLimit;
           }
         }
 
-        // Step 2.5 MinContentContribution to intrinsic max-sizing.
+        // Step 2.5 MinSize to intrinsic max-sizing.
         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
           Step2ItemData& item = step2Items[i];
           if (!(item.mState & TrackSize::eIntrinsicMaxSizing)) {
             continue;
           }
-          nscoord space = item.mMinContentContribution;
+          nscoord space = item.mMinSize;
           if (space <= 0) {
             continue;
           }
           tracks.ClearAndRetainStorage();
           space = CollectGrowable(space, plan, item.mLineRange,
                                   TrackSize::eIntrinsicMaxSizing,
                                   tracks);
           if (space > 0) {
@@ -4410,17 +4450,19 @@ nsGridContainerFrame::Tracks::FindUsedFl
   nsRenderingContext* rc = &aState.mRenderingContext;
   GridItemCSSOrderIterator& iter = aState.mIter;
   iter.Reset();
   // ... the result of 'finding the size of an fr' for each item that spans
   // a flex track with its max-content contribution as 'space to fill'
   for (; !iter.AtEnd(); iter.Next()) {
     const GridItemInfo& item = aGridItems[iter.GridItemIndex()];
     if (item.mState[mAxis] & ItemState::eIsFlexing) {
-      nscoord spaceToFill = MaxContentContribution(item, aState, rc, wm, mAxis);
+      // XXX optimize: bug 1194446
+      nscoord spaceToFill = ContentContribution(item, aState, rc, wm, mAxis,
+                                                nsLayoutUtils::PREF_ISIZE);
       if (spaceToFill <= 0) {
         continue;
       }
       // ... and all its spanned tracks as input.
       const LineRange& range =
         mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
       nsTArray<uint32_t> itemFlexTracks;
       for (uint32_t i = range.mStart, end = range.mEnd; i < end; ++i) {
@@ -5689,17 +5731,17 @@ nsGridContainerFrame::Reflow(nsPresConte
 
   nscoord consumedBSize = 0;
   if (!prevInFlow) {
     Grid grid;
     grid.PlaceGridItems(gridReflowInput, aReflowInput.ComputedMinSize(),
                         computedSize, aReflowInput.ComputedMaxSize());
 
     gridReflowInput.CalculateTrackSizes(grid, computedSize,
-                                        nsLayoutUtils::PREF_ISIZE);
+                                        SizingConstraint::eNoConstraint);
   } else {
     consumedBSize = GetConsumedBSize();
     gridReflowInput.InitializeForContinuation(this, consumedBSize);
   }
 
   nscoord bSize = 0;
   if (computedBSize == NS_AUTOHEIGHT) {
     const uint32_t numRows = gridReflowInput.mRows.mSizes.Length();
@@ -5972,21 +6014,21 @@ nsGridContainerFrame::Reflow(nsPresConte
   }
 
   FinishAndStoreOverflow(&aDesiredSize);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
 }
 
 nscoord
 nsGridContainerFrame::IntrinsicISize(nsRenderingContext* aRenderingContext,
-                                     IntrinsicISizeType  aConstraint)
+                                     IntrinsicISizeType  aType)
 {
   RenumberList();
 
-  // Calculate the sum of column sizes under aConstraint.
+  // Calculate the sum of column sizes under intrinsic sizing.
   // http://dev.w3.org/csswg/css-grid/#intrinsic-sizes
   GridReflowInput state(this, *aRenderingContext);
   InitImplicitNamedAreas(state.mGridStyle); // XXX optimize
 
   auto GetDefiniteSizes = [] (const nsStyleCoord& aMinCoord,
                               const nsStyleCoord& aSizeCoord,
                               const nsStyleCoord& aMaxCoord,
                               nscoord* aMin,
@@ -6030,19 +6072,21 @@ nsGridContainerFrame::IntrinsicISize(nsR
 
   Grid grid;
   grid.PlaceGridItems(state, min, sz, max);  // XXX optimize
   if (grid.mGridColEnd == 0) {
     return 0;
   }
   state.mCols.Initialize(state.mColFunctions, state.mGridStyle->mGridColumnGap,
                          grid.mGridColEnd, NS_UNCONSTRAINEDSIZE);
+  auto constraint = aType == nsLayoutUtils::MIN_ISIZE ?
+    SizingConstraint::eMinContent : SizingConstraint::eMaxContent;
   state.mCols.CalculateSizes(state, state.mGridItems, state.mColFunctions,
                              NS_UNCONSTRAINEDSIZE, &GridArea::mCols,
-                             aConstraint);
+                             constraint);
   nscoord length = 0;
   for (const TrackSize& sz : state.mCols.mSizes) {
     length += sz.mBase;
   }
   return length + state.mCols.SumOfGridGaps();
 }
 
 nscoord
@@ -6283,18 +6327,16 @@ nsGridContainerFrame::TrackSize::Dump() 
 
   printf(" min:");
   if (mState & eAutoMinSizing) {
     printf("auto ");
   } else if (mState & eMinContentMinSizing) {
     printf("min-content ");
   } else if (mState & eMaxContentMinSizing) {
     printf("max-content ");
-  } else if (mState & eFlexMinSizing) {
-    printf("flex ");
   }
 
   printf(" max:");
   if (mState & eAutoMaxSizing) {
     printf("auto ");
   } else if (mState & eMinContentMaxSizing) {
     printf("min-content ");
   } else if (mState & eMaxContentMaxSizing) {
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -3555,36 +3555,16 @@ private:
 void
 nsPrintEngine::FirePrintCompletionEvent()
 {
   nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint);
   if (NS_FAILED(NS_DispatchToCurrentThread(event)))
     NS_WARNING("failed to dispatch print completion event");
 }
 
-bool
-nsPrintEngine::MayHavePluginFrames()
-{
-  nsPrintData* prt = mPrt;
-  if (!mPrt) {
-    prt = mPrtPreview;
-    if (!prt) {
-      prt = mOldPrtPreview;
-    }
-  }
-  if (prt) {
-    for (uint32_t i = 0; i < prt->mPrintDocList.Length(); ++i) {
-      if (prt->mPrintDocList[i]->MayHavePluginFrames()) {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
 //---------------------------------------------------------------
 //---------------------------------------------------------------
 //-- Debug helper routines
 //---------------------------------------------------------------
 //---------------------------------------------------------------
 #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING)
 #include "windows.h"
 #include "process.h"
--- a/layout/printing/nsPrintEngine.h
+++ b/layout/printing/nsPrintEngine.h
@@ -198,18 +198,16 @@ public:
     return mIsCreatingPrintPreview;
   }
 
   void SetDisallowSelectionPrint(bool aDisallowSelectionPrint)
   {
     mDisallowSelectionPrint = aDisallowSelectionPrint;
   }
 
-  bool MayHavePluginFrames();
-
 protected:
   ~nsPrintEngine();
 
   nsresult CommonPrint(bool aIsPrintPreview, nsIPrintSettings* aPrintSettings,
                        nsIWebProgressListener* aWebProgressListener,
                        nsIDOMDocument* aDoc);
 
   nsresult DoCommonPrint(bool aIsPrintPreview, nsIPrintSettings* aPrintSettings,
--- a/layout/printing/nsPrintObject.cpp
+++ b/layout/printing/nsPrintObject.cpp
@@ -106,13 +106,8 @@ nsPrintObject::DestroyPresentation()
     nsCOMPtr<nsIPresShell> shell = mPresShell;
     mPresShell = nullptr;
     shell->Destroy();
   }
   mPresContext = nullptr;
   mViewManager = nullptr;
 }
 
-bool
-nsPrintObject::MayHavePluginFrames()
-{
-  return mDocument && mDocument->MayHavePluginFramesForPrinting();
-}
--- a/layout/printing/nsPrintObject.h
+++ b/layout/printing/nsPrintObject.h
@@ -31,19 +31,16 @@ public:
   nsPrintObject();
   ~nsPrintObject(); // non-virtual
 
   // Methods
   nsresult Init(nsIDocShell* aDocShell, nsIDOMDocument* aDoc,
                 bool aPrintPreview);
 
   bool IsPrintable()  { return !mDontPrint; }
-
-  bool MayHavePluginFrames();
-
   void   DestroyPresentation();
 
   // Data Members
   nsCOMPtr<nsIDocShell>    mDocShell;
   nsCOMPtr<nsIDocShellTreeOwner> mTreeOwner;
   nsCOMPtr<nsIDocument>    mDocument;
 
   RefPtr<nsPresContext>  mPresContext;
--- a/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html
@@ -40,19 +40,25 @@ body,html { color:black; background:whit
 
 br { clear:both; }
 
 #px-border      .item { border-left:20px solid blue; }
 #percent-border .item { padding-left:10%; }
 
 #px-border .grid { grid-template-columns: minmax(20px,0) 1fr; }
 .c100 { grid-template-columns: minmax(100px,0) 1fr; }
+.c100100 { grid-template-columns: minmax(100px,0) 100px; }
 #px-border .c100 { grid-template-columns: minmax(120px,0) 1fr; }
+#px-border .c100100 { grid-template-columns: minmax(120px,0) 120px; }
 .c10 { grid-template-columns: minmax(10px,0) 1fr; }
 #px-border .c10 { grid-template-columns: minmax(30px,0) 1fr; }
+
+#percent-border .c100 { grid-template-columns: minmax(100px,0) 11px; }
+#percent-border .c10 { grid-template-columns: minmax(10px,0) 1px; }
+#percent-border .c100100 { grid-template-columns: minmax(100px,0) 150px; }
   </style>
 </head>
 <body>
 
 <table border="1">
 <tr><th>no border/padding/margin</th><th>'border-left:20px'</th><th>'padding-left:10%'</th>
 <tr><td id="no-border"></td><td id="px-border"></td><td id="percent-border"></td>
 </tr></table>
@@ -81,33 +87,33 @@ var styles = [
 "min-width:calc(75px + 50%); width:100px",
 "min-width:calc(100px + 50%); max-width:1px",
 "min-width:calc(100px + 50%); max-width:150px",
 ];
 var grids = [
 "grid",
 "grid",
 "grid c100",
-"grid",
+"grid c100",
 "grid",
-"grid",
+"grid c100100",
 "grid c10",
 "grid c100",
 "grid c100",
 "grid",
 "grid",
 "grid",
 "grid",
-"grid",
+"grid c100",
 "grid c100",
 "grid",
+"grid c100100",
+"grid c10",
 "grid c100",
-"grid",
-"grid",
-"grid",
+"grid c100",
 "grid",
 "grid",
 ];
 var containers = [ "no-border", "px-border", "percent-border" ];
 for (var i = 0; i < containers.length; ++i) {
   var c = document.querySelector("#"+containers[i]);
   for (var j = 0; j < styles.length; ++j) {
     c.appendChild(document.createElement('br'));
--- a/layout/reftests/css-grid/grid-flex-min-sizing-001-ref.html
+++ b/layout/reftests/css-grid/grid-flex-min-sizing-001-ref.html
@@ -16,20 +16,21 @@ body,html { color:black; background:whit
  float: left;
  min-width:100px;
 }
 .fixed .grid {
  width:140px;
 }
 
 .g1 {
- grid-template-columns: minmax(0,min-content)
+ grid-template-columns: 4px
                         minmax(0,0)
                         minmax(0,0)
                         1fr;
+ min-width:104px;
 }
 
 .g2 {
  grid-template-columns: minmax(0,max-content)
                         minmax(0,0)
                         minmax(0,0)
                         1fr;
 }
@@ -41,30 +42,33 @@ body,html { color:black; background:whit
                         1fr;
 }
 
 .g4 {
  grid-template-columns: minmax(2px,0)
                         minmax(1px,0)
                         minmax(1px,0)
                         1fr;
+ min-width:104px;
 }
 
 .g5 {
  grid-template-columns: minmax(20px,0)
                         minmax(0,0)
                         minmax(0,0)
                         1fr;
+ min-width:104px;
 }
 
 .g6 {
  grid-template-columns: minmax(2px,0)
                         minmax(1px,0)
                         minmax(1px,0)
                         20px;
+ min-width:124px;
 }
 
 .g7 {
  grid-template-columns: minmax(20px,1fr)
                         minmax(0,0)
                         minmax(0,0)
                         20px;
 }
@@ -76,56 +80,60 @@ body,html { color:black; background:whit
                         20px;
 }
 
 .g9 {
  grid-template-columns: 20px
                         30px
                         minmax(0,0)
                         10px;
+ min-width:114px;
 }
 
 .gA {
  grid-template-columns: minmax(0,0)
                         minmax(min-content,40px)
                         minmax(0,0)
                         20px;
+ min-width:140px;
 }
 
 .gB {
  grid-template-columns: minmax(0,0)
                         minmax(auto,40px)
                         minmax(0,0)
                         20px;
 }
 
 .gC {
  grid-template-columns: minmax(0,20px)
-                        minmax(auto,40px)
+                        minmax(0,40px)
                         minmax(0,0)
                         20px;
+ min-width:124px;
 }
 
 .gD {