merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 07 Sep 2016 17:20:12 +0200
changeset 313011 95acb9299fafdc69463c49860caf367e4fbcc8e3
parent 313010 a14f88a9af7a59e677478694bafd9375ac53683e (current diff)
parent 312921 b294f305f8d1115fdcfdbf66eb4cb55393e5af04 (diff)
child 313012 80dccdd8c94ae0f47a9c037bc56e4c4ed79ebfbb
child 313018 027ead0b3b0bed97d7ec7fd01ee79c7e01848047
child 313093 af11902f242f7bdaa7437a497f286e2528af4f31
push id81509
push usercbook@mozilla.com
push dateWed, 07 Sep 2016 15:23:10 +0000
treeherdermozilla-inbound@80dccdd8c94a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.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
docshell/base/nsDocShell.cpp
dom/ipc/TabParent.cpp
dom/promise/PromiseNativeHandler.cpp
gfx/angle/src/libANGLE/renderer/copyimage.cpp
gfx/angle/src/libANGLE/renderer/copyimage.h
gfx/angle/src/libANGLE/renderer/copyimage.inl
gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.py
gfx/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
gfx/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
gfx/angle/src/libANGLE/renderer/d3d/generatemip.h
gfx/angle/src/libANGLE/renderer/d3d/generatemip.inl
gfx/angle/src/libANGLE/renderer/d3d/loadimage.cpp
gfx/angle/src/libANGLE/renderer/d3d/loadimage.h
gfx/angle/src/libANGLE/renderer/d3d/loadimage.inl
gfx/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp
gfx/angle/src/libANGLE/renderer/d3d/loadimage_etc.h
gfx/angle/src/libANGLE/renderer/imageformats.h
gfx/angle/src/tests/gl_tests/CompressedTextureTest.cpp
toolkit/components/passwordmgr/nsLoginManagerPrompter.js
--- a/accessible/tests/mochitest/text/test_atcaretoffset.html
+++ b/accessible/tests/mochitest/text/test_atcaretoffset.html
@@ -409,36 +409,28 @@
       // 10 11 12 13 14 15
 
       traverseTextByLines(gQueue, "textarea",
                           [ [ "aword", "\n", 0, 5, { words: [ 0, 5 ] } ],
                             [ "two ", "", 6, 10, { words: [ 6, 9 ] } ],
                             [ "words", "", 10, 15, { words: [ 10, 15 ] } ]
                           ] );
 
-      var line2 = [ // " my "
-        [ "TextBeforeOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ],
-        [ "TextAfterOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ]
-      ];
-      var line4 = [ // "riend"
-        [ "TextBeforeOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ],
-        [ "TextAfterOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ]
-      ];
-      var line5 = [ // " t "
+      var line4 = [ // "riend "
         [ "TextBeforeOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ],
         [ "TextAfterOffset", BOUNDARY_WORD_END, kTodo, kTodo, kTodo ]
       ];
       traverseTextByLines(gQueue, "ta_wrapped", 
                           [ [ "hi ", "", 0, 3, { words: [ 0, 2 ] } ],
-                            [ "hello", "", 3, 8, { words: [ 3, 8 ] } ],
-                            [ " my ", "", 8, 12, { words: [ 9, 11 ], lsf: line2 } ],
+                            [ "hello ", "", 3, 9, { words: [ 3, 8 ] } ],
+                            [ "my ", "", 9, 12, { words: [ 9, 11 ] } ],
                             [ "longf", "", 12, 17, { words: [ 12, 17 ] } ],
-                            [ "riend", "", 17, 22, { words: [ 17, 22 ], lsf: line4 } ],
-                            [ " t ", "", 22, 25, { words: [ 23, 24 ], lsf: line5 } ],
-                            [ "sq t", "", 25, 29, { words: [ 25, 27, 28, 29 ] } ]
+                            [ "riend ", "", 17, 23, { words: [ 17, 22 ], lsf: line4 } ],
+                            [ "t sq ", "", 23, 28, { words: [ 23, 24, 25, 27 ] } ],
+                            [ "t", "", 28, 29, { words: [ 28, 29 ] } ]
                           ] );
 
       gQueue.invoke(); // will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -28,16 +28,19 @@ LOCAL_INCLUDES += [
     '/xpcom/base',
     '/xpcom/build',
 ]
 
 USE_LIBS += [
     'mozglue',
 ]
 
+if CONFIG['LIBFUZZER']:
+  USE_LIBS += [ 'fuzzer' ]
+
 if CONFIG['_MSC_VER']:
     # Always enter a Windows program through wmain, whether or not we're
     # a console application.
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     RCINCLUDE = 'splash.rc'
     DEFINES['MOZ_PHOENIX'] = True
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -124,33 +124,52 @@ XRE_TelemetryAccumulateType XRE_Telemetr
 XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
 XRE_mainType XRE_main;
 XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
 XRE_XPCShellMainType XRE_XPCShellMain;
 XRE_GetProcessTypeType XRE_GetProcessType;
 XRE_SetProcessTypeType XRE_SetProcessType;
 XRE_InitChildProcessType XRE_InitChildProcess;
 XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc;
+#ifdef LIBFUZZER
+XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain;
+XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs;
+#endif
 
 static const nsDynamicFunctionLoad kXULFuncs[] = {
     { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
     { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
     { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
     { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
     { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
     { "XRE_main", (NSFuncPtr*) &XRE_main },
     { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
     { "XRE_XPCShellMain", (NSFuncPtr*) &XRE_XPCShellMain },
     { "XRE_GetProcessType", (NSFuncPtr*) &XRE_GetProcessType },
     { "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType },
     { "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess },
     { "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc },
+#ifdef LIBFUZZER
+    { "XRE_LibFuzzerSetMain", (NSFuncPtr*) &XRE_LibFuzzerSetMain },
+    { "XRE_LibFuzzerGetFuncs", (NSFuncPtr*) &XRE_LibFuzzerGetFuncs },
+#endif
     { nullptr, nullptr }
 };
 
+#ifdef LIBFUZZER
+int libfuzzer_main(int argc, char **argv);
+
+/* This wrapper is used by the libFuzzer main to call into libxul */
+
+void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc,
+                       LibFuzzerTestingFunc* testingFunc) {
+  return XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc);
+}
+#endif
+
 static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory)
 {
   nsCOMPtr<nsIFile> appini;
   nsresult rv;
   uint32_t mainFlags = 0;
 
   // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
   // Note that -app must be the *first* argument.
@@ -251,16 +270,21 @@ static int do_main(int argc, char* argv[
   if (!brokerServices) {
     Output("Couldn't initialize the broker services.\n");
     return 255;
   }
 #endif
   appData.sandboxBrokerServices = brokerServices;
 #endif
 
+#ifdef LIBFUZZER
+  if (getenv("LIBFUZZER"))
+    XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
+#endif
+
   return XRE_main(argc, argv, &appData, mainFlags);
 }
 
 static bool
 FileExists(const char *path)
 {
 #ifdef XP_WIN
   wchar_t wideDir[MAX_PATH];
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -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/. */
 
+"use strict";
+
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/AppConstants.jsm");
 
 function init(aEvent)
 {
   if (aEvent.target != document)
     return;
@@ -34,29 +36,40 @@ function init(aEvent)
       }
     }
   }
   catch (e) {
     // Pref is unset
   }
 
   // Include the build ID and display warning if this is an "a#" (nightly or aurora) build
+  let versionField = document.getElementById("version");
   let version = Services.appinfo.version;
   if (/a\d+$/.test(version)) {
     let buildID = Services.appinfo.appBuildID;
-    let buildDate = buildID.slice(0, 4) + "-" + buildID.slice(4, 6) + "-" + buildID.slice(6, 8);
-    document.getElementById("version").textContent += " (" + buildDate + ")";
+    let year = buildID.slice(0, 4);
+    let month = buildID.slice(4, 6);
+    let day = buildID.slice(6, 8);
+    versionField.textContent += ` (${year}-${month}-${day})`;
+
     document.getElementById("experimental").hidden = false;
     document.getElementById("communityDesc").hidden = true;
   }
 
+  // Append "(32-bit)" or "(64-bit)" build architecture to the version number:
+  let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+  let archResource = Services.appinfo.is64Bit
+                     ? "aboutDialog.architecture.sixtyFourBit"
+                     : "aboutDialog.architecture.thirtyTwoBit";
+  let arch = bundle.GetStringFromName(archResource);
+  versionField.textContent += ` (${arch})`;
+
   if (AppConstants.MOZ_UPDATER) {
     gAppUpdater = new appUpdater();
 
-    let defaults = Services.prefs.getDefaultBranch("");
     let channelLabel = document.getElementById("currentChannel");
     let currentChannelText = document.getElementById("currentChannelText");
     channelLabel.value = UpdateUtils.UpdateChannel;
     if (/^release($|\-)/.test(channelLabel.value))
         currentChannelText.hidden = true;
   }
 
   if (AppConstants.platform == "macosx") {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -686,66 +686,65 @@
                    aria-label="&urlbar.viewSiteInfo.label;"
                    onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
                    onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
                    ondragstart="gIdentityHandler.onDragStart(event);">
                 <image id="identity-icon"
                        consumeanchor="identity-box"
                        onclick="PageProxyClickHandler(event);"/>
                 <image id="sharing-icon" mousethrough="always"/>
-                <box id="blocked-permissions-container" align="center" tooltiptext="">
+                <box id="blocked-permissions-container" align="center">
                   <image data-permission-id="geo" class="blocked-permission-icon geo-icon" role="button"
-                         aria-label="&urlbar.geolocationNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.geolocationBlocked.tooltip;"/>
                   <image data-permission-id="desktop-notification" class="blocked-permission-icon desktop-notification-icon" role="button"
-                         aria-label="&urlbar.webNotsNotificationAnchor3.label;"/>
+                         tooltiptext="&urlbar.webNotificationsBlocked.tooltip;"/>
                   <image data-permission-id="camera" class="blocked-permission-icon camera-icon" role="button"
-                         aria-label="&urlbar.webRTCShareDevicesNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.cameraBlocked.tooltip;"/>
                   <image data-permission-id="indexedDB" class="blocked-permission-icon indexedDB-icon" role="button"
-                         aria-label="&urlbar.indexedDBNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.indexedDBBlocked.tooltip;"/>
                   <image data-permission-id="microphone" class="blocked-permission-icon microphone-icon" role="button"
-                         aria-label="&urlbar.webRTCShareMicrophoneNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.microphoneBlocked.tooltip;"/>
                   <image data-permission-id="screen" class="blocked-permission-icon screen-icon" role="button"
-                         aria-label="&urlbar.webRTCShareScreenNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.screenBlocked.tooltip;"/>
                 </box>
                 <box id="notification-popup-box"
                      hidden="true"
-                     tooltiptext=""
                      onmouseover="document.getElementById('identity-icon').classList.add('no-hover');"
                      onmouseout="document.getElementById('identity-icon').classList.remove('no-hover');"
                      align="center">
                   <image id="default-notification-icon" class="notification-anchor-icon" role="button"
-                         aria-label="&urlbar.defaultNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.defaultNotificationAnchor.tooltip;"/>
                   <image id="geo-notification-icon" class="notification-anchor-icon geo-icon" role="button"
-                         aria-label="&urlbar.geolocationNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.geolocationNotificationAnchor.tooltip;"/>
                   <image id="addons-notification-icon" class="notification-anchor-icon install-icon" role="button"
-                         aria-label="&urlbar.addonsNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.addonsNotificationAnchor.tooltip;"/>
                   <image id="indexedDB-notification-icon" class="notification-anchor-icon indexedDB-icon" role="button"
-                         aria-label="&urlbar.indexedDBNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.indexedDBNotificationAnchor.tooltip;"/>
                   <image id="login-fill-notification-icon" class="notification-anchor-icon login-icon" role="button"
-                         aria-label="&urlbar.loginFillNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.loginFillNotificationAnchor.tooltip;"/>
                   <image id="password-notification-icon" class="notification-anchor-icon login-icon" role="button"
-                         aria-label="&urlbar.passwordNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.passwordNotificationAnchor.tooltip;"/>
                   <image id="plugins-notification-icon" class="notification-anchor-icon plugin-icon" role="button"
-                         aria-label="&urlbar.pluginsNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.pluginsNotificationAnchor.tooltip;"/>
                   <image id="web-notifications-notification-icon" class="notification-anchor-icon desktop-notification-icon" role="button"
-                         aria-label="&urlbar.webNotsNotificationAnchor3.label;"/>
+                         tooltiptext="&urlbar.webNotificationAnchor.tooltip;"/>
                   <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon camera-icon" role="button"
-                         aria-label="&urlbar.webRTCShareDevicesNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.webRTCShareDevicesNotificationAnchor.tooltip;"/>
                   <image id="webRTC-shareMicrophone-notification-icon" class="notification-anchor-icon microphone-icon" role="button"
-                         aria-label="&urlbar.webRTCShareMicrophoneNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.webRTCShareMicrophoneNotificationAnchor.tooltip;"/>
                   <image id="webRTC-shareScreen-notification-icon" class="notification-anchor-icon screen-icon" role="button"
-                         aria-label="&urlbar.webRTCShareScreenNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.webRTCShareScreenNotificationAnchor.tooltip;"/>
                   <image id="servicesInstall-notification-icon" class="notification-anchor-icon service-icon" role="button"
-                         aria-label="&urlbar.servicesNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.servicesNotificationAnchor.tooltip;"/>
                   <image id="translate-notification-icon" class="notification-anchor-icon translation-icon" role="button"
-                         aria-label="&urlbar.translateNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.translateNotificationAnchor.tooltip;"/>
                   <image id="translated-notification-icon" class="notification-anchor-icon translation-icon in-use" role="button"
-                         aria-label="&urlbar.translatedNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.translatedNotificationAnchor.tooltip;"/>
                   <image id="eme-notification-icon" class="notification-anchor-icon drm-icon" role="button"
-                         aria-label="&urlbar.emeNotificationAnchor.label;"/>
+                         tooltiptext="&urlbar.emeNotificationAnchor.tooltip;"/>
                 </box>
                 <image id="tracking-protection-icon"/>
                 <image id="connection-icon"/>
                 <hbox id="identity-icon-labels">
                   <label id="identity-icon-label" class="plain" flex="1"/>
                   <label id="identity-icon-country-label" class="plain"/>
                 </hbox>
               </box>
@@ -1042,17 +1041,17 @@
     <hbox flex="1" id="browser">
       <vbox id="browser-border-start" hidden="true" layer="true"/>
       <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
         <sidebarheader id="sidebar-header" align="center">
           <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
           <image id="sidebar-throbber"/>
           <toolbarbutton class="close-icon tabbable" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="SidebarUI.hide();"/>
         </sidebarheader>
-        <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true"
+        <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true" disablefullscreen="true"
                   style="min-width: 14em; width: 18em; max-width: 36em;" tooltip="aHTMLTooltip"/>
       </vbox>
 
       <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
       <vbox id="appcontent" flex="1">
         <notificationbox id="high-priority-global-notificationbox" notificationside="top"/>
         <tabbrowser id="content"
                     flex="1" contenttooltip="aHTMLTooltip"
--- a/browser/base/content/test/popupNotifications/browser.ini
+++ b/browser/base/content/test/popupNotifications/browser.ini
@@ -7,8 +7,10 @@ skip-if = (os == "linux" && (debug || as
 [browser_popupNotification.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_2.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_3.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_4.js]
 skip-if = (os == "linux" && (debug || asan))
+[browser_popupNotification_checkbox.js]
+skip-if = (os == "linux" && (debug || asan))
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js
@@ -0,0 +1,197 @@
+/* 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/. */
+
+function test() {
+  waitForExplicitFinish();
+
+  ok(PopupNotifications, "PopupNotifications object exists");
+  ok(PopupNotifications.panel, "PopupNotifications panel exists");
+
+  setup();
+  goNext();
+}
+
+function checkCheckbox(checkbox, label, checked=false, hidden=false) {
+  is(checkbox.label, label, "Checkbox should have the correct label");
+  is(checkbox.hidden, hidden, "Checkbox should be shown");
+  is(checkbox.checked, checked, "Checkbox should be checked by default");
+}
+
+function checkMainAction(notification, disabled=false) {
+  let mainAction = notification.button;
+  let warningLabel = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-warning");
+  is(warningLabel.hidden, !disabled, "Warning label should be shown");
+  is(mainAction.disabled, disabled, "MainAction should be disabled");
+}
+
+var gNotification;
+
+var tests = [
+  // Test that passing the checkbox field shows the checkbox.
+  { id: "show_checkbox",
+    run: function () {
+      this.notifyObj = new BasicNotification(this.id);
+      this.notifyObj.options.checkbox = {
+        label: "This is a checkbox",
+      };
+      gNotification = showNotification(this.notifyObj);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObj);
+      let notification = popup.childNodes[0];
+      checkCheckbox(notification.checkbox, "This is a checkbox");
+      triggerMainCommand(popup);
+    },
+    onHidden: function () { }
+  },
+
+  // Test checkbox being checked by default
+  { id: "checkbox_checked",
+    run: function () {
+      this.notifyObj = new BasicNotification(this.id);
+      this.notifyObj.options.checkbox = {
+        label: "Check this",
+        checked: true,
+      };
+      gNotification = showNotification(this.notifyObj);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObj);
+      let notification = popup.childNodes[0];
+      checkCheckbox(notification.checkbox, "Check this", true);
+      triggerMainCommand(popup);
+    },
+    onHidden: function () { }
+  },
+
+  // Test checkbox passing the checkbox state on mainAction
+  { id: "checkbox_passCheckboxChecked_mainAction",
+    run: function () {
+      this.notifyObj = new BasicNotification(this.id);
+      this.notifyObj.mainAction.callback = ({checkboxChecked}) => this.mainActionChecked = checkboxChecked;
+      this.notifyObj.options.checkbox = {
+        label: "This is a checkbox",
+      };
+      gNotification = showNotification(this.notifyObj);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObj);
+      let notification = popup.childNodes[0];
+      let checkbox = notification.checkbox;
+      checkCheckbox(checkbox, "This is a checkbox");
+      EventUtils.synthesizeMouseAtCenter(checkbox, {});
+      checkCheckbox(checkbox, "This is a checkbox", true);
+      triggerMainCommand(popup);
+    },
+    onHidden: function () {
+      is(this.mainActionChecked, true, "mainAction callback is passed the correct checkbox value");
+    }
+  },
+
+  // Test checkbox passing the checkbox state on secondaryAction
+  { id: "checkbox_passCheckboxChecked_secondaryAction",
+    run: function () {
+      this.notifyObj = new BasicNotification(this.id);
+      this.notifyObj.secondaryActions = [{
+        label: "Test Secondary",
+        accessKey: "T",
+        callback: ({checkboxChecked}) => this.secondaryActionChecked = checkboxChecked,
+      }];
+      this.notifyObj.options.checkbox = {
+        label: "This is a checkbox",
+      };
+      gNotification = showNotification(this.notifyObj);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObj);
+      let notification = popup.childNodes[0];
+      let checkbox = notification.checkbox;
+      checkCheckbox(checkbox, "This is a checkbox");
+      EventUtils.synthesizeMouseAtCenter(checkbox, {});
+      checkCheckbox(checkbox, "This is a checkbox", true);
+      triggerSecondaryCommand(popup, 0);
+    },
+    onHidden: function () {
+      is(this.secondaryActionChecked, true, "secondaryAction callback is passed the correct checkbox value");
+    }
+  },
+
+  // Test checkbox preserving its state through re-opening the doorhanger
+  { id: "checkbox_reopen",
+    run: function () {
+      this.notifyObj = new BasicNotification(this.id);
+      this.notifyObj.options.checkbox = {
+        label: "This is a checkbox",
+        checkedState: {
+          disableMainAction: true,
+          warningLabel: "Testing disable",
+        },
+      };
+      gNotification = showNotification(this.notifyObj);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObj);
+      let notification = popup.childNodes[0];
+      let checkbox = notification.checkbox;
+      checkCheckbox(checkbox, "This is a checkbox");
+      EventUtils.synthesizeMouseAtCenter(checkbox, {});
+      dismissNotification(popup);
+    },
+    onHidden: function (popup) {
+      let icon = document.getElementById("default-notification-icon");
+      EventUtils.synthesizeMouseAtCenter(icon, {});
+      let notification = popup.childNodes[0];
+      let checkbox = notification.checkbox;
+      checkCheckbox(checkbox, "This is a checkbox", true);
+      checkMainAction(notification, true);
+      gNotification.remove();
+    }
+  },
+];
+
+// Test checkbox disabling the main action in different combinations
+["checkedState", "uncheckedState"].forEach(function (state) {
+  [true, false].forEach(function (checked) {
+    tests.push(
+      { id: `checkbox_disableMainAction_${state}_${checked ? 'checked' : 'unchecked'}`,
+        run: function () {
+          this.notifyObj = new BasicNotification(this.id);
+          this.notifyObj.options.checkbox = {
+            label: "This is a checkbox",
+            checked: checked,
+            [state]: {
+              disableMainAction: true,
+              warningLabel: "Testing disable",
+            },
+          };
+          gNotification = showNotification(this.notifyObj);
+        },
+        onShown: function (popup) {
+          checkPopup(popup, this.notifyObj);
+          let notification = popup.childNodes[0];
+          let checkbox = notification.checkbox;
+          let disabled = (state === "checkedState" && checked) ||
+                         (state === "uncheckedState" && !checked);
+
+          checkCheckbox(checkbox, "This is a checkbox", checked);
+          checkMainAction(notification, disabled);
+          EventUtils.synthesizeMouseAtCenter(checkbox, {});
+          checkCheckbox(checkbox, "This is a checkbox", !checked);
+          checkMainAction(notification, !disabled);
+          EventUtils.synthesizeMouseAtCenter(checkbox, {});
+          checkCheckbox(checkbox, "This is a checkbox", checked);
+          checkMainAction(notification, disabled);
+
+          // Unblock the main command if it's currently disabled.
+          if (disabled) {
+            EventUtils.synthesizeMouseAtCenter(checkbox, {});
+          }
+          triggerMainCommand(popup);
+        },
+        onHidden: function () { }
+      }
+    );
+  });
+});
+
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -201,36 +201,41 @@ These should match what Safari and other
 <!ENTITY stopCmd.label                "Stop">
 <!ENTITY stopCmd.macCommandKey        ".">
 <!ENTITY stopButton.tooltip           "Stop loading this page">
 <!ENTITY goEndCap.tooltip             "Go to the address in the Location Bar">
 <!ENTITY printButton.label            "Print">
 <!ENTITY printButton.tooltip          "Print this page">
 
 <!ENTITY urlbar.viewSiteInfo.label                      "View site information">
-<!-- LOCALIZATION NOTE: all of the following urlbar NotificationAnchor.label strings are
-     used to provide accessible labels to users of assistive technology like screenreaders.
-     It is not possible to see them visually in the UI. -->
-<!ENTITY urlbar.defaultNotificationAnchor.label         "View a notification">
-<!ENTITY urlbar.geolocationNotificationAnchor.label     "View the location request">
-<!ENTITY urlbar.addonsNotificationAnchor.label          "View the add-on install message">
-<!ENTITY urlbar.indexedDBNotificationAnchor.label       "View the app-offline storage message">
-<!ENTITY urlbar.loginFillNotificationAnchor.label       "Manage your login information">
-<!ENTITY urlbar.passwordNotificationAnchor.label        "Check if you want to save your password">
-<!ENTITY urlbar.pluginsNotificationAnchor.label         "Manage plugin usage on this page">
-<!ENTITY urlbar.webNotsNotificationAnchor3.label        "Change whether you can receive notifications from the site">
+
+<!ENTITY urlbar.defaultNotificationAnchor.tooltip         "Open message panel">
+<!ENTITY urlbar.geolocationNotificationAnchor.tooltip     "Open location request panel">
+<!ENTITY urlbar.addonsNotificationAnchor.tooltip          "Open add-on installation message panel">
+<!ENTITY urlbar.indexedDBNotificationAnchor.tooltip       "Open offline storage message panel">
+<!ENTITY urlbar.loginFillNotificationAnchor.tooltip       "Manage your login information">
+<!ENTITY urlbar.passwordNotificationAnchor.tooltip        "Open save password message panel">
+<!ENTITY urlbar.pluginsNotificationAnchor.tooltip         "Manage plug-in use">
+<!ENTITY urlbar.webNotificationAnchor.tooltip             "Change whether you can receive notifications from the site">
 
-<!ENTITY urlbar.webRTCShareDevicesNotificationAnchor.label      "Manage sharing your camera and/or microphone with the site">
-<!ENTITY urlbar.webRTCShareMicrophoneNotificationAnchor.label   "Manage sharing your microphone with the site">
-<!ENTITY urlbar.webRTCShareScreenNotificationAnchor.label       "Manage sharing your windows or screen with the site">
+<!ENTITY urlbar.webRTCShareDevicesNotificationAnchor.tooltip      "Manage sharing your camera and/or microphone with the site">
+<!ENTITY urlbar.webRTCShareMicrophoneNotificationAnchor.tooltip   "Manage sharing your microphone with the site">
+<!ENTITY urlbar.webRTCShareScreenNotificationAnchor.tooltip       "Manage sharing your windows or screen with the site">
 
-<!ENTITY urlbar.servicesNotificationAnchor.label        "View the service install message">
-<!ENTITY urlbar.translateNotificationAnchor.label       "Translate this page">
-<!ENTITY urlbar.translatedNotificationAnchor.label      "Manage page translation">
-<!ENTITY urlbar.emeNotificationAnchor.label             "Manage use of DRM software">
+<!ENTITY urlbar.servicesNotificationAnchor.tooltip        "Open install message panel">
+<!ENTITY urlbar.translateNotificationAnchor.tooltip       "Translate this page">
+<!ENTITY urlbar.translatedNotificationAnchor.tooltip      "Manage page translation">
+<!ENTITY urlbar.emeNotificationAnchor.tooltip             "Manage use of DRM software">
+
+<!ENTITY urlbar.cameraBlocked.tooltip            "You have blocked your camera for this website.">
+<!ENTITY urlbar.microphoneBlocked.tooltip        "You have blocked your microphone for this website.">
+<!ENTITY urlbar.screenBlocked.tooltip            "You have blocked this website from sharing your screen.">
+<!ENTITY urlbar.geolocationBlocked.tooltip       "You have blocked location information for this website.">
+<!ENTITY urlbar.indexedDBBlocked.tooltip         "You have blocked data storage for this website.">
+<!ENTITY urlbar.webNotificationsBlocked.tooltip  "You have blocked notifications for this website.">
 
 <!ENTITY urlbar.openHistoryPopup.tooltip                "Show history">
 
 <!ENTITY urlbar.zoomReset.tooltip     "Reset zoom level">
 
 <!ENTITY searchItem.title             "Search">
 
 <!-- Toolbar items --> 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -740,8 +740,16 @@ decoder.noCodecs.accesskey = L
 decoder.noCodecs.message = To play video, you may need to install Microsoft’s Media Feature Pack.
 decoder.noCodecsVista.message = To play video, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 decoder.noCodecsXP.message = To play video, you may need to enable Adobe’s Primetime Content Decryption Module.
 decoder.noCodecsLinux.message = To play video, you may need to install the required video codecs.
 decoder.noHWAcceleration.message = To improve video quality, you may need to install Microsoft’s Media Feature Pack.
 decoder.noHWAccelerationVista.message = To improve video quality, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 
 permissions.remove.tooltip = Clear this permission and ask again
+
+# LOCALIZATION NOTE (aboutDialog.architecture.*):
+# The sixtyFourBit and thirtyTwoBit strings describe the architecture of the
+# current Firefox build: 32-bit or 64-bit. These strings are used in parentheses
+# between the Firefox version and the "What's new" link in the About dialog,
+# e.g.: "48.0.2 (32-bit) <What's new>" or "51.0a1 (2016-09-05) (64-bit)".
+aboutDialog.architecture.sixtyFourBit = 64-bit
+aboutDialog.architecture.thirtyTwoBit = 32-bit
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -342,18 +342,18 @@ function prompt(aBrowser, aRequest) {
 
   if (aRequest.secure && !sharingScreen && !sharingAudio) {
     // Don't show the 'Always' action if the connection isn't secure, or for
     // screen/audio sharing (because we can't guess which window the user wants
     // to share without prompting).
     secondaryActions.unshift({
       label: stringBundle.getString("getUserMedia.always.label"),
       accessKey: stringBundle.getString("getUserMedia.always.accesskey"),
-      callback: function () {
-        mainAction.callback(true);
+      callback: function (aState) {
+        mainAction.callback(aState, true);
       }
     });
   }
 
   let options = {
     eventCallback: function(aTopic, aNewBrowser) {
       if (aTopic == "swapping")
         return true;
@@ -514,17 +514,17 @@ function prompt(aBrowser, aRequest) {
       if (sharingScreen)
         listScreenShareDevices(windowMenupopup, videoDevices);
       else
         listDevices(camMenupopup, videoDevices);
 
       if (!sharingAudio)
         listDevices(micMenupopup, audioDevices);
 
-      this.mainAction.callback = function(aRemember) {
+      this.mainAction.callback = function(aState, aRemember) {
         let allowedDevices = [];
         let perms = Services.perms;
         if (videoDevices.length) {
           let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
           let videoDeviceIndex = chromeDoc.getElementById(listId).value;
           let allowCamera = videoDeviceIndex != "-1";
           if (allowCamera) {
             allowedDevices.push(videoDeviceIndex);
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -50,22 +50,21 @@
   background-color: transparent;
   border-top: none;
 }
 
 #navigator-toolbox::after {
   content: "";
   display: -moz-box;
   -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */
-  height: 1px;
-  background-color: ThreeDShadow;
+  border-bottom: 1px solid ThreeDShadow;
 }
 
 #navigator-toolbox:-moz-lwtheme::after {
-  background-color: rgba(0,0,0,.3);
+  border-bottom-color: rgba(0,0,0,.3);
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#addon-bar) {
   background-image: linear-gradient(@toolbarHighlight@, @toolbarHighlight@);
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#addon-bar):-moz-lwtheme {
   background-image: linear-gradient(@toolbarHighlightLWT@, @toolbarHighlightLWT@);
@@ -1735,36 +1734,34 @@ toolbarbutton.chevron > .toolbarbutton-i
   box-shadow: 1px 1px 2px hsl(0,0%,12%);
 }
 
 .ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner > .tabPreview-canvas {
   margin-bottom: 2px;
 }
 
 .ctrlTab-preview-inner {
-  padding-bottom: 10px;
+  padding: 8px;
+  border: 2px solid transparent;
+  border-radius: .5em;
+}
+
+.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner {
+  margin: -10px -10px 0;
 }
 
 #ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner {
-  padding: 10px;
   background-color: rgba(255,255,255,.2);
-  border-radius: .5em;
 }
 
 .ctrlTab-preview:focus > * > .ctrlTab-preview-inner {
   color: white;
   background-color: rgba(0,0,0,.6);
   text-shadow: none;
-  padding: 8px;
-  border: 2px solid white;
-  border-radius: .5em;
-}
-
-.ctrlTab-preview:not(#ctrlTab-showAll):focus > * > .ctrlTab-preview-inner {
-  margin: -10px -10px 0;
+  border-color: white;
 }
 
 #ctrlTab-showAll {
   margin-top: .5em;
 }
 
 /* Status panel */
 
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -50,28 +50,30 @@
 
 #urlbar:-moz-lwtheme:not([focused="true"]),
 .searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
   opacity: .9;
 }
 
 #navigator-toolbox::after {
   -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */
-  background-image: linear-gradient(to top, hsla(0,0%,0%,.15), hsla(0,0%,0%,.15) 1px, hsla(0,0%,100%,.15) 1px, hsla(0,0%,100%,.15) 2px, transparent 3px);
   content: "";
   display: -moz-box;
-  height: 2px;
+  border-top: 1px solid hsla(0,0%,100%,.15);
+  border-bottom: 1px solid hsla(0,0%,0%,.15);
   margin-top: -2px;
   position: relative;
   z-index: 2; /* navbar is at 1 */
 }
 
 @media (-moz-mac-yosemite-theme) {
   #navigator-toolbox:-moz-window-inactive::after {
-    background-image: linear-gradient(to top, hsla(0,0%,0%,.1), hsla(0,0%,0%,.1) 1px, hsla(0,0%,100%,0) 1px, hsla(0,0%,100%,0) 2px, transparent 3px);
+    border-top-style: none;
+    border-bottom-color: hsla(0,0%,0%,.1);
+    margin-top: -1px;
   }
 }
 
 #navigator-toolbox toolbarbutton:-moz-lwtheme {
   color: inherit;
   text-shadow: inherit;
 }
 
@@ -3144,36 +3146,34 @@ menulist.translate-infobar-element > .me
   box-shadow: 1px 1px 2px hsl(0,0%,12%);
 }
 
 .ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner > .tabPreview-canvas {
   margin-bottom: 2px;
 }
 
 .ctrlTab-preview-inner {
-  padding-bottom: 10px;
+  padding: 8px;
+  border: 2px solid transparent;
+  border-radius: .5em;
+}
+
+.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner {
+  margin: -10px -10px 0;
 }
 
 #ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner {
-  padding: 10px;
   background-color: rgba(255,255,255,.2);
-  border-radius: .5em;
 }
 
 .ctrlTab-preview:focus > * > .ctrlTab-preview-inner {
   color: white;
   background-color: rgba(0,0,0,.6);
   text-shadow: none;
-  padding: 8px;
-  border: 2px solid white;
-  border-radius: .5em;
-}
-
-.ctrlTab-preview:not(#ctrlTab-showAll):focus > * > .ctrlTab-preview-inner {
-  margin: -10px -10px 0;
+  border-color: white;
 }
 
 #ctrlTab-showAll {
   margin-top: .5em;
 }
 
 /* Status panel */
 
--- a/browser/themes/osx/devedition.css
+++ b/browser/themes/osx/devedition.css
@@ -5,17 +5,18 @@
 %include ../shared/devedition.inc.css
 
 :root {
   --forwardbutton-width: 32px;
 }
 
 /* Use only 1px separator between nav toolbox and page content */
 #navigator-toolbox::after {
-  background: linear-gradient(to top, var(--chrome-navigator-toolbox-separator-color), var(--chrome-navigator-toolbox-separator-color) 1px, transparent 1px);
+  border-top-style: none;
+  margin-top: -1px;
 }
 
 /* Include extra space on left/right for dragging since there is no space above
    the tabs */
 #main-window[tabsintitlebar] #TabsToolbar {
   padding-left: 50px;
   padding-right: 50px;
   margin-bottom: 0; /* Don't overlap the inner highlight at the top of the nav-bar */
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -141,17 +141,17 @@
 #tabbrowser-tabs,
 #TabsToolbar,
 #browser-panel {
   background: var(--chrome-background-color);
   color: var(--chrome-color);
 }
 
 #navigator-toolbox:-moz-lwtheme::after {
-  background: var(--chrome-navigator-toolbox-separator-color);
+  border-bottom-color: var(--chrome-navigator-toolbox-separator-color);
 }
 
 #navigator-toolbox > toolbar:not(#TabsToolbar):not(#toolbar-menubar),
 .browserContainer > findbar,
 #browser-bottombox {
   background-color: var(--chrome-secondary-background-color) !important;
   background-image: none !important;
   color: var(--chrome-color);
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -435,20 +435,30 @@
 .tab-label[attention]:not([selected="true"]) {
   font-weight: bold;
 }
 
 /* Tab separators */
 
 .tabbrowser-tab::after,
 .tabbrowser-tab::before {
-  margin-top: 5px;
-  margin-bottom: 4px;
   margin-inline-start: -1px;
-  border-left: 1px solid currentColor;
+  /* Vertical margin doesn't work here for positioned pinned tabs, see
+     bug 1198236 and bug 1300410. We're using linear-gradient instead
+     to cut off the border at the top and at the bottom. */
+  border-left: 1px solid;
+  border-image: linear-gradient(transparent 6px,
+                                currentColor 6px,
+                                currentColor calc(100% - 5px),
+                                transparent calc(100% - 5px));
+  border-image-slice: 1;
+  /* The 1px border and negative margin may amount to a different number of
+     device pixels (bug 477157), so we also set a width to match the margin. */
+  width: 1px;
+  box-sizing: border-box;
   opacity: 0.2;
 }
 
 #TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-tab::before,
 #TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-tab::after {
   opacity: 0.4;
 }
 
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -330,26 +330,31 @@
     color: white;
   }
 
   /* Show borders on vista through win8, but not on win10 and later: */
   @media (-moz-os-version: windows-vista),
          (-moz-os-version: windows-win7),
          (-moz-os-version: windows-win8) {
     /* Vertical toolbar border */
-    #main-window:not([customizing])[sizemode=normal] #navigator-toolbox:not(:-moz-lwtheme)::after,
     #main-window:not([customizing])[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(:-moz-lwtheme),
     #main-window:not([customizing])[sizemode=normal] #navigator-toolbox:-moz-lwtheme,
-    #main-window[customizing] #navigator-toolbox::after,
     #main-window[customizing] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
       border-left: 1px solid @toolbarShadowColor@;
       border-right: 1px solid @toolbarShadowColor@;
       background-clip: padding-box;
     }
 
+    #main-window:not([customizing])[sizemode=normal] #navigator-toolbox:not(:-moz-lwtheme)::after,
+    #main-window[customizing] #navigator-toolbox::after {
+      box-shadow: 1px 0 0 @toolbarShadowColor@, -1px 0 0 @toolbarShadowColor@;
+      margin-left: 1px;
+      margin-right: 1px;
+    }
+
     #main-window[sizemode=normal] #browser-border-start,
     #main-window[sizemode=normal] #browser-border-end {
       display: -moz-box;
       background-color: @toolbarShadowColor@;
       width: 1px;
     }
 
     #main-window[sizemode=normal] #browser-bottombox {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -117,38 +117,37 @@
   background-color: transparent;
   border-top: none;
 }
 
 #navigator-toolbox::after {
   content: "";
   display: -moz-box;
   -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */
-  height: 1px;
-  background-color: ThreeDShadow;
+  border-bottom: 1px solid ThreeDShadow;
 }
 
 @media (-moz-windows-default-theme) {
   @media (-moz-os-version: windows-vista),
          (-moz-os-version: windows-win7) {
     #navigator-toolbox::after {
-      background-color: #aabccf;
+      border-bottom-color: #aabccf;
     }
   }
 
   @media (-moz-os-version: windows-win8),
          (-moz-os-version: windows-win10) {
     #navigator-toolbox::after {
-      background-color: #c2c2c2;
+      border-bottom-color: #c2c2c2;
     }
   }
 }
 
 #navigator-toolbox:-moz-lwtheme::after {
-  background-color: rgba(0,0,0,.3);
+  border-bottom-color: rgba(0,0,0,.3);
 }
 
 #navigator-toolbox > toolbar {
   -moz-appearance: none;
   border-style: none;
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
@@ -2417,36 +2416,34 @@ notification[value="translation"] {
   box-shadow: 1px 1px 2px hsl(0,0%,12%);
 }
 
 .ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner > .tabPreview-canvas {
   margin-bottom: 2px;
 }
 
 .ctrlTab-preview-inner {
-  padding-bottom: 10px;
+  padding: 8px;
+  border: 2px solid transparent;
+  border-radius: .5em;
+}
+
+.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner {
+  margin: -10px -10px 0;
 }
 
 #ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner {
-  padding: 10px;
   background-color: rgba(255,255,255,.2);
-  border-radius: .5em;
 }
 
 .ctrlTab-preview:focus > * > .ctrlTab-preview-inner {
   color: white;
   background-color: rgba(0,0,0,.6);
   text-shadow: none;
-  padding: 8px;
-  border: 2px solid white;
-  border-radius: .5em;
-}
-
-.ctrlTab-preview:not(#ctrlTab-showAll):focus > * > .ctrlTab-preview-inner {
-  margin: -10px -10px 0;
+  border-color: white;
 }
 
 #ctrlTab-showAll {
   margin-top: .5em;
 }
 
 /* Status panel */
 
--- a/devtools/shared/heapsnapshot/AutoMemMap.cpp
+++ b/devtools/shared/heapsnapshot/AutoMemMap.cpp
@@ -1,34 +1,36 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/devtools/AutoMemMap.h"
+
+#include "mozilla/Unused.h"
 #include "nsDebug.h"
 
 namespace mozilla {
 namespace devtools {
 
 AutoMemMap::~AutoMemMap()
 {
   if (addr) {
-    NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
+    Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
     addr = nullptr;
   }
 
   if (fileMap) {
-    NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
+    Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
     fileMap = nullptr;
   }
 
   if (fd) {
-    NS_WARN_IF(PR_Close(fd) != PR_SUCCESS);
+    Unused << NS_WARN_IF(PR_Close(fd) != PR_SUCCESS);
     fd = nullptr;
   }
 }
 
 nsresult
 AutoMemMap::init(const char* filePath, int flags, int mode, PRFileMapProtect prot)
 {
   MOZ_ASSERT(!fd);
--- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/devtools/FileDescriptorOutputStream.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/devtools/ZeroCopyNSIOutputStream.h"
 #include "mozilla/dom/ChromeUtils.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/HeapSnapshotBinding.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Unused.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCRTGlue.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsIOutputStream.h"
@@ -1468,17 +1469,17 @@ HeapSnapshot::CreateUniqueCoreDumpFile(E
 
 // Deletion policy for cleaning up PHeapSnapshotTempFileHelperChild pointers.
 class DeleteHeapSnapshotTempFileHelperChild
 {
 public:
   constexpr DeleteHeapSnapshotTempFileHelperChild() { }
 
   void operator()(PHeapSnapshotTempFileHelperChild* ptr) const {
-    NS_WARN_IF(!HeapSnapshotTempFileHelperChild::Send__delete__(ptr));
+    Unused << NS_WARN_IF(!HeapSnapshotTempFileHelperChild::Send__delete__(ptr));
   }
 };
 
 // A UniquePtr alias to automatically manage PHeapSnapshotTempFileHelperChild
 // pointers.
 using UniqueHeapSnapshotTempFileHelperChild = UniquePtr<PHeapSnapshotTempFileHelperChild,
                                                         DeleteHeapSnapshotTempFileHelperChild>;
 
--- a/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp
+++ b/devtools/shared/heapsnapshot/ZeroCopyNSIOutputStream.cpp
@@ -1,16 +1,17 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/devtools/ZeroCopyNSIOutputStream.h"
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace devtools {
 
 ZeroCopyNSIOutputStream::ZeroCopyNSIOutputStream(nsCOMPtr<nsIOutputStream>& out)
   : out(out)
   , result_(NS_OK)
   , amountUsed(0)
@@ -19,17 +20,17 @@ ZeroCopyNSIOutputStream::ZeroCopyNSIOutp
   DebugOnly<bool> nonBlocking = false;
   MOZ_ASSERT(out->IsNonBlocking(&nonBlocking) == NS_OK);
   MOZ_ASSERT(!nonBlocking);
 }
 
 ZeroCopyNSIOutputStream::~ZeroCopyNSIOutputStream()
 {
   if (!failed())
-    NS_WARN_IF(NS_FAILED(writeBuffer()));
+    Unused << NS_WARN_IF(NS_FAILED(writeBuffer()));
 }
 
 nsresult
 ZeroCopyNSIOutputStream::writeBuffer()
 {
   if (failed())
     return result_;
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2501,50 +2501,57 @@ nsDocShell::GetFullscreenAllowed(bool* a
 
   // Assume false until we determine otherwise...
   *aFullscreenAllowed = false;
 
   nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
   if (!win) {
     return NS_OK;
   }
-  nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
-  if (frameElement && !frameElement->IsXULElement()) {
-    // We do not allow document inside any containing element other
-    // than iframe to enter fullscreen.
-    if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
-      // If any ancestor iframe does not have allowfullscreen attribute
-      // set, then fullscreen is not allowed.
-      if (!frameElement->HasAttr(kNameSpaceID_None,
-                                 nsGkAtoms::allowfullscreen) &&
-          !frameElement->HasAttr(kNameSpaceID_None,
-                                 nsGkAtoms::mozallowfullscreen)) {
-        return NS_OK;
-      }
-    } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
-      // Respect allowfullscreen only if this is a rewritten YouTube embed.
-      nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
-        do_QueryInterface(frameElement);
-      if (!objectLoadingContent) {
-        return NS_OK;
-      }
-      nsObjectLoadingContent* olc =
-        static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
-      if (!olc->IsRewrittenYoutubeEmbed()) {
-        return NS_OK;
-      }
-      // We don't have to check prefixed attributes because Flash does not
-      // support them.
-      if (!frameElement->HasAttr(kNameSpaceID_None,
-                                 nsGkAtoms::allowfullscreen)) {
+  if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) {
+    if (frameElement->IsXULElement()) {
+      if (frameElement->HasAttr(kNameSpaceID_None,
+                                nsGkAtoms::disablefullscreen)) {
+        // Document inside this frame is explicitly disabled.
         return NS_OK;
       }
     } else {
-      // neither iframe nor embed
-      return NS_OK;
+      // We do not allow document inside any containing element other
+      // than iframe to enter fullscreen.
+      if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
+        // If any ancestor iframe does not have allowfullscreen attribute
+        // set, then fullscreen is not allowed.
+        if (!frameElement->HasAttr(kNameSpaceID_None,
+                                  nsGkAtoms::allowfullscreen) &&
+            !frameElement->HasAttr(kNameSpaceID_None,
+                                  nsGkAtoms::mozallowfullscreen)) {
+          return NS_OK;
+        }
+      } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
+        // Respect allowfullscreen only if this is a rewritten YouTube embed.
+        nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
+          do_QueryInterface(frameElement);
+        if (!objectLoadingContent) {
+          return NS_OK;
+        }
+        nsObjectLoadingContent* olc =
+          static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
+        if (!olc->IsRewrittenYoutubeEmbed()) {
+          return NS_OK;
+        }
+        // We don't have to check prefixed attributes because Flash does not
+        // support them.
+        if (!frameElement->HasAttr(kNameSpaceID_None,
+                                  nsGkAtoms::allowfullscreen)) {
+          return NS_OK;
+        }
+      } else {
+        // neither iframe nor embed
+        return NS_OK;
+      }
     }
   }
 
   // If we have no parent then we're the root docshell; no ancestor of the
   // original docshell doesn't have a allowfullscreen attribute, so
   // report fullscreen as allowed.
   RefPtr<nsDocShell> parent = GetParentDocshell();
   if (!parent) {
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -1344,22 +1344,22 @@ AudioChannelService::AudioChannelWindow:
 
 void
 AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
                                                                    AudibleState aAudible,
                                                                    AudibleChangedReasons aReason)
 {
   RefPtr<AudioPlaybackRunnable> runnable =
     new AudioPlaybackRunnable(aWindow, aAudible, aReason);
-  nsresult rv = NS_DispatchToCurrentThread(runnable);
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
 }
 
 void
 AudioChannelService::AudioChannelWindow::NotifyChannelActive(uint64_t aWindowID,
                                                              AudioChannel aChannel,
                                                              bool aActive)
 {
   RefPtr<NotifyChannelActiveRunnable> runnable =
     new NotifyChannelActiveRunnable(aWindowID, aChannel, aActive);
-  nsresult rv = NS_DispatchToCurrentThread(runnable);
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
 }
--- a/dom/base/MultipartBlobImpl.cpp
+++ b/dom/base/MultipartBlobImpl.cpp
@@ -162,17 +162,17 @@ MultipartBlobImpl::CreateSlice(uint64_t 
 
   return impl.forget();
 }
 
 void
 MultipartBlobImpl::InitializeBlob(ErrorResult& aRv)
 {
   SetLengthAndModifiedDate(aRv);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed");
 }
 
 void
 MultipartBlobImpl::InitializeBlob(JSContext* aCx,
                                   const Sequence<Blob::BlobPart>& aData,
                                   const nsAString& aContentType,
                                   bool aNativeEOL,
                                   ErrorResult& aRv)
@@ -216,17 +216,17 @@ MultipartBlobImpl::InitializeBlob(JSCont
     else {
       MOZ_CRASH("Impossible blob data type.");
     }
   }
 
 
   mBlobImpls = blobSet.GetBlobImpls();
   SetLengthAndModifiedDate(aRv);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed");
 }
 
 void
 MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv)
 {
   MOZ_ASSERT(mLength == UINT64_MAX);
   MOZ_ASSERT(mLastModificationDate == INT64_MAX);
 
@@ -347,17 +347,17 @@ MultipartBlobImpl::InitializeChromeFile(
   }
 
 
   BlobSet blobSet;
   blobSet.AppendBlobImpl(aBlob.Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate(aRv);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed");
 }
 
 void
 MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindowInner* aWindow,
                                         nsIFile* aFile,
                                         const ChromeFilePropertyBag& aBag,
                                         bool aIsFromNsIFile,
                                         ErrorResult& aRv)
@@ -419,17 +419,17 @@ MultipartBlobImpl::InitializeChromeFile(
     blob->GetType(mContentType);
   }
 
   BlobSet blobSet;
   blobSet.AppendBlobImpl(static_cast<File*>(blob.get())->Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate(aRv);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed");
 }
 
 void
 MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindowInner* aWindow,
                                         const nsAString& aData,
                                         const ChromeFilePropertyBag& aBag,
                                         ErrorResult& aRv)
 {
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -42,16 +42,17 @@
 #include "mozilla/dom/FlyWebPublishedServer.h"
 #include "mozilla/dom/FlyWebService.h"
 #include "mozilla/dom/IccManager.h"
 #include "mozilla/dom/InputPortManager.h"
 #include "mozilla/dom/MobileMessageManager.h"
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/Presentation.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
+#include "mozilla/dom/StorageManager.h"
 #include "mozilla/dom/TCPSocket.h"
 #include "mozilla/dom/Telephony.h"
 #include "mozilla/dom/Voicemail.h"
 #include "mozilla/dom/TVManager.h"
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/workers/RuntimeService.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
@@ -227,16 +228,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTVManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
 #ifdef MOZ_B2G_RIL
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
 #endif
 #ifdef MOZ_B2G_BT
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
@@ -271,16 +273,18 @@ Navigator::Invalidate()
 
   if (mPlugins) {
     mPlugins->Invalidate();
     mPlugins = nullptr;
   }
 
   mPermissions = nullptr;
 
+  mStorageManager = nullptr;
+
   // If there is a page transition, make sure delete the geolocation object.
   if (mGeolocation) {
     mGeolocation->Shutdown();
     mGeolocation = nullptr;
   }
 
   if (mNotification) {
     mNotification->Shutdown();
@@ -653,16 +657,31 @@ Navigator::GetPermissions(ErrorResult& a
 
   if (!mPermissions) {
     mPermissions = new Permissions(mWindow);
   }
 
   return mPermissions;
 }
 
+StorageManager*
+Navigator::Storage()
+{
+  MOZ_ASSERT(mWindow);
+
+  if(!mStorageManager) {
+    nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
+    MOZ_ASSERT(global);
+
+    mStorageManager = new StorageManager(global);
+  }
+
+  return mStorageManager;
+}
+
 // Values for the network.cookie.cookieBehavior pref are documented in
 // nsCookieService.cpp.
 #define COOKIE_BEHAVIOR_REJECT 2
 
 bool
 Navigator::CookieEnabled()
 {
   bool cookieEnabled =
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -96,16 +96,17 @@ class IccManager;
 class Telephony;
 class Voicemail;
 class TVManager;
 class InputPortManager;
 class DeviceStorageAreaListener;
 class Presentation;
 class LegacyMozTCPSocket;
 class VRDisplay;
+class StorageManager;
 
 namespace time {
 class TimeManager;
 } // namespace time
 
 namespace system {
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 class AudioChannelManager;
@@ -282,16 +283,18 @@ public:
                               ErrorResult& aRv);
 
   already_AddRefed<ServiceWorkerContainer> ServiceWorker();
 
   void GetLanguages(nsTArray<nsString>& aLanguages);
 
   bool MozE10sEnabled();
 
+  StorageManager* Storage();
+
   static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
 
   // WebIDL helper methods
   static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasCameraSupport(JSContext* /* unused */,
                                JSObject* aGlobal);
   static bool HasWifiManagerSupport(JSContext* /* unused */,
                                   JSObject* aGlobal);
@@ -372,14 +375,15 @@ private:
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   RefPtr<DeviceStorageAreaListener> mDeviceStorageAreaListener;
   RefPtr<Presentation> mPresentation;
 #ifdef MOZ_GAMEPAD
   RefPtr<GamepadServiceTest> mGamepadServiceTest;
 #endif
   nsTArray<RefPtr<Promise> > mVRGetDisplaysPromises;
   nsTArray<uint32_t> mRequestedVibrationPattern;
+  RefPtr<StorageManager> mStorageManager;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Navigator_h
--- a/dom/base/ScreenOrientation.cpp
+++ b/dom/base/ScreenOrientation.cpp
@@ -394,19 +394,21 @@ ScreenOrientation::UnlockDeviceOrientati
   if (!mFullScreenListener || !GetOwner()) {
     mFullScreenListener = nullptr;
     return;
   }
 
   // Remove event listener in case of fullscreen lock.
   nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner()->GetDoc());
   if (target) {
-    nsresult rv = target->RemoveSystemEventListener(NS_LITERAL_STRING("fullscreenchange"),
-                                                    mFullScreenListener, /* useCapture */ true);
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv =
+      target->RemoveSystemEventListener(NS_LITERAL_STRING("fullscreenchange"),
+                                        mFullScreenListener,
+                                        /* useCapture */ true);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RemoveSystemEventListener failed");
   }
 
   mFullScreenListener = nullptr;
 }
 
 OrientationType
 ScreenOrientation::DeviceType() const
 {
@@ -525,63 +527,63 @@ ScreenOrientation::Notify(const hal::Scr
     // the values we care about.
     return;
   }
 
   OrientationType previousOrientation = mType;
   mAngle = aConfiguration.angle();
   mType = InternalOrientationToType(orientation);
 
-  nsresult rv;
+  DebugOnly<nsresult> rv;
   if (mScreen && mType != previousOrientation) {
     // Use of mozorientationchange is deprecated.
     rv = mScreen->DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange"));
-    NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed");
   }
 
   if (doc->Hidden() && !mVisibleListener) {
     mVisibleListener = new VisibleEventListener();
     rv = doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
                                      mVisibleListener, /* useCapture = */ true);
-    NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddSystemEventListener failed");
     return;
   }
 
   if (mType != doc->CurrentOrientationType()) {
     doc->SetCurrentOrientation(mType, mAngle);
 
     Promise* pendingPromise = doc->GetOrientationPendingPromise();
     if (pendingPromise) {
       pendingPromise->MaybeResolveWithUndefined();
       doc->SetOrientationPendingPromise(nullptr);
     }
 
     nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod(this,
       &ScreenOrientation::DispatchChangeEvent);
     rv = NS_DispatchToMainThread(runnable);
-    NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
   }
 }
 
 void
 ScreenOrientation::UpdateActiveOrientationLock(ScreenOrientationInternal aOrientation)
 {
   if (aOrientation == eScreenOrientation_None) {
     hal::UnlockScreenOrientation();
   } else {
-    bool rv = hal::LockScreenOrientation(aOrientation);
-    NS_WARN_IF(!rv);
+    DebugOnly<bool> ok = hal::LockScreenOrientation(aOrientation);
+    NS_WARNING_ASSERTION(ok, "hal::LockScreenOrientation failed");
   }
 }
 
 void
 ScreenOrientation::DispatchChangeEvent()
 {
-  nsresult rv = DispatchTrustedEvent(NS_LITERAL_STRING("change"));
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = DispatchTrustedEvent(NS_LITERAL_STRING("change"));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed");
 }
 
 JSObject*
 ScreenOrientation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ScreenOrientationBinding::Wrap(aCx, this, aGivenProto);
 }
 
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/OffscreenCanvas.h"
 #include "mozilla/dom/OffscreenCanvasBinding.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/URLSearchParams.h"
+#include "mozilla/dom/URLSearchParamsBinding.h"
 #include "mozilla/dom/WebCryptoCommon.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "MultipartBlobImpl.h"
 #include "nsIRemoteBlob.h"
 #include "nsQueryObject.h"
--- a/dom/base/nsContentCreatorFunctions.h
+++ b/dom/base/nsContentCreatorFunctions.h
@@ -26,27 +26,27 @@ class Element;
 class NodeInfo;
 } // namespace dom
 } // namespace mozilla
 
 nsresult
 NS_NewElement(mozilla::dom::Element** aResult,
               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
               mozilla::dom::FromParser aFromParser,
-              nsAString* aIs = nullptr);
+              const nsAString* aIs = nullptr);
 
 nsresult
 NS_NewXMLElement(mozilla::dom::Element** aResult,
                  already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 nsresult
 NS_NewHTMLElement(mozilla::dom::Element** aResult,
                   already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   mozilla::dom::FromParser aFromParser,
-                  nsAString* aIs = nullptr);
+                  const nsAString* aIs = nullptr);
 
 // First argument should be nsHTMLTag, but that adds dependency to parser
 // for a bunch of files.
 already_AddRefed<nsGenericHTMLElement>
 CreateHTMLElement(uint32_t aNodeType,
                   already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   mozilla::dom::FromParser aFromParser);
 
--- a/dom/base/nsContentIterator.cpp
+++ b/dom/base/nsContentIterator.cpp
@@ -11,32 +11,34 @@
 #include "nsRange.h"
 #include "nsIContent.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsContentUtils.h"
 #include "nsINode.h"
 #include "nsCycleCollectionParticipant.h"
 
+using mozilla::DebugOnly;
+
 // couple of utility static functs
 
 ///////////////////////////////////////////////////////////////////////////
 // NodeToParentOffset: returns the node's parent and offset.
 //
 
 static nsINode*
 NodeToParentOffset(nsINode* aNode, int32_t* aOffset)
 {
   *aOffset = 0;
 
   nsINode* parent = aNode->GetParentNode();
 
   if (parent) {
     *aOffset = parent->IndexOf(aNode);
-    NS_WARN_IF(*aOffset < 0);
+    NS_WARNING_ASSERTION(*aOffset >= 0, "bad offset");
   }
 
   return parent;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // NodeIsInTraversalRange: returns true if content is visited during
 // the traversal of the range in the specified mode.
@@ -68,17 +70,17 @@ NodeIsInTraversalRange(nsINode* aNode, b
   }
 
   nsINode* parent = aNode->GetParentNode();
   if (!parent) {
     return false;
   }
 
   int32_t indx = parent->IndexOf(aNode);
-  NS_WARN_IF(indx == -1);
+  NS_WARNING_ASSERTION(indx != -1, "bad indx");
 
   if (!aIsPreMode) {
     ++indx;
   }
 
   return nsContentUtils::ComparePoints(aStartNode, aStartOffset,
                                        parent, indx) <= 0 &&
          nsContentUtils::ComparePoints(aEndNode, aEndOffset,
@@ -270,20 +272,20 @@ nsContentIterator::Init(nsINode* aRoot)
   }
 
   mIsDone = false;
   mIndexes.Clear();
 
   if (mPre) {
     mFirst = aRoot;
     mLast  = GetDeepLastChild(aRoot);
-    NS_WARN_IF(!mLast);
+    NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
   } else {
     mFirst = GetDeepFirstChild(aRoot);
-    NS_WARN_IF(!mFirst);
+    NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
     mLast  = aRoot;
   }
 
   mCommonParent = aRoot;
   mCurNode = mFirst;
   RebuildIndexStack();
   return NS_OK;
 }
@@ -301,25 +303,25 @@ nsContentIterator::Init(nsIDOMRange* aDO
   // get common content parent
   mCommonParent = range->GetCommonAncestor();
   if (NS_WARN_IF(!mCommonParent)) {
     return NS_ERROR_FAILURE;
   }
 
   // get the start node and offset
   int32_t startIndx = range->StartOffset();
-  NS_WARN_IF(startIndx < 0);
+  NS_WARNING_ASSERTION(startIndx >= 0, "bad startIndx");
   nsINode* startNode = range->GetStartParent();
   if (NS_WARN_IF(!startNode)) {
     return NS_ERROR_FAILURE;
   }
 
   // get the end node and offset
   int32_t endIndx = range->EndOffset();
-  NS_WARN_IF(endIndx < 0);
+  NS_WARNING_ASSERTION(endIndx >= 0, "bad endIndx");
   nsINode* endNode = range->GetEndParent();
   if (NS_WARN_IF(!endNode)) {
     return NS_ERROR_FAILURE;
   }
 
   bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
 
   // short circuit when start node == end node
@@ -337,29 +339,29 @@ nsContentIterator::Init(nsIDOMRange* aDO
     }
 
     if (startIsData) {
       // It's a character data node.
       mFirst   = startNode->AsContent();
       mLast    = mFirst;
       mCurNode = mFirst;
 
-      nsresult rv = RebuildIndexStack();
-      NS_WARN_IF(NS_FAILED(rv));
+      DebugOnly<nsresult> rv = RebuildIndexStack();
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RebuildIndexStack failed");
       return NS_OK;
     }
   }
 
   // Find first node in range.
 
   nsIContent* cChild = nullptr;
 
   if (!startIsData && startNode->HasChildren()) {
     cChild = startNode->GetChildAt(startIndx);
-    NS_WARN_IF(!cChild);
+    NS_WARNING_ASSERTION(cChild, "GetChildAt returned null");
   }
 
   if (!cChild) {
     // no children, must be a text node
     //
     // XXXbz no children might also just mean no children.  So I'm not
     // sure what that comment above is talking about.
 
@@ -368,17 +370,17 @@ nsContentIterator::Init(nsIDOMRange* aDO
       //      character in the cdata node, should we set mFirst to
       //      the next sibling?
 
       // If the node has no child, the child may be <br> or something.
       // So, we shouldn't skip the empty node if the start offset is 0.
       // In other words, if the offset is 1, the node should be ignored.
       if (!startIsData && startIndx) {
         mFirst = GetNextSibling(startNode);
-        NS_WARN_IF(!mFirst);
+        NS_WARNING_ASSERTION(mFirst, "GetNextSibling returned null");
 
         // Does mFirst node really intersect the range?  The range could be
         // 'degenerate', i.e., not collapsed but still contain no content.
         if (mFirst &&
             NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, startNode,
                                                startIndx, endNode, endIndx))) {
           mFirst = nullptr;
         }
@@ -395,17 +397,17 @@ nsContentIterator::Init(nsIDOMRange* aDO
       }
     }
   } else {
     if (mPre) {
       mFirst = cChild;
     } else {
       // post-order
       mFirst = GetDeepFirstChild(cChild);
-      NS_WARN_IF(!mFirst);
+      NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
 
       // Does mFirst node really intersect the range?  The range could be
       // 'degenerate', i.e., not collapsed but still contain no content.
 
       if (mFirst &&
           !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
                                   endNode, endIndx)) {
         mFirst = nullptr;
@@ -424,17 +426,17 @@ nsContentIterator::Init(nsIDOMRange* aDO
         // Not much else to do here...
         mLast = nullptr;
       } else {
         // If the end node is an empty element and the end offset is 0,
         // the last element should be the previous node (i.e., shouldn't
         // include the end node in the range).
         if (!endIsData && !endNode->HasChildren() && !endIndx) {
           mLast = GetPrevSibling(endNode);
-          NS_WARN_IF(!mLast);
+          NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null");
           if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre,
                                                  startNode, startIndx,
                                                  endNode, endIndx))) {
             mLast = nullptr;
           }
         } else {
           mLast = endNode->AsContent();
         }
@@ -442,17 +444,17 @@ nsContentIterator::Init(nsIDOMRange* aDO
     } else {
       // post-order
       //
       // XXX: In the future, if end offset is before the first character in the
       //      cdata node, should we set mLast to the prev sibling?
 
       if (!endIsData) {
         mLast = GetPrevSibling(endNode);
-        NS_WARN_IF(!mLast);
+        NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null");
 
         if (!NodeIsInTraversalRange(mLast, mPre,
                                     startNode, startIndx,
                                     endNode, endIndx)) {
           mLast = nullptr;
         }
       } else {
         mLast = endNode->AsContent();
@@ -466,17 +468,17 @@ nsContentIterator::Init(nsIDOMRange* aDO
     if (NS_WARN_IF(!cChild)) {
       // No child at offset!
       NS_NOTREACHED("nsContentIterator::nsContentIterator");
       return NS_ERROR_FAILURE;
     }
 
     if (mPre) {
       mLast  = GetDeepLastChild(cChild);
-      NS_WARN_IF(!mLast);
+      NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
 
       if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre,
                                              startNode, startIndx,
                                              endNode, endIndx))) {
         mLast = nullptr;
       }
     } else {
       // post-order
@@ -492,18 +494,18 @@ nsContentIterator::Init(nsIDOMRange* aDO
   }
 
   mCurNode = mFirst;
   mIsDone  = !mCurNode;
 
   if (!mCurNode) {
     mIndexes.Clear();
   } else {
-    nsresult rv = RebuildIndexStack();
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = RebuildIndexStack();
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RebuildIndexStack failed");
   }
 
   return NS_OK;
 }
 
 
 /******************************************************
  * Helper routines
@@ -649,26 +651,26 @@ nsContentIterator::GetNextSibling(nsINod
   NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
                "ContentIterator stack underflow");
   if (aIndexes && !aIndexes->IsEmpty()) {
     // use the last entry on the Indexes array for the current index
     indx = (*aIndexes)[aIndexes->Length()-1];
   } else {
     indx = mCachedIndex;
   }
-  NS_WARN_IF(indx < 0);
+  NS_WARNING_ASSERTION(indx >= 0, "bad indx");
 
   // reverify that the index of the current node hasn't changed.
   // not super cheap, but a lot cheaper than IndexOf(), and still O(1).
   // ignore result this time - the index may now be out of range.
   nsIContent* sib = parent->GetChildAt(indx);
   if (sib != aNode) {
     // someone changed our index - find the new index the painful way
     indx = parent->IndexOf(aNode);
-    NS_WARN_IF(indx < 0);
+    NS_WARNING_ASSERTION(indx >= 0, "bad indx");
   }
 
   // indx is now canonically correct
   if ((sib = parent->GetChildAt(++indx))) {
     // update index cache
     if (aIndexes && !aIndexes->IsEmpty()) {
       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
     } else {
@@ -719,17 +721,17 @@ nsContentIterator::GetPrevSibling(nsINod
   }
 
   // reverify that the index of the current node hasn't changed
   // ignore result this time - the index may now be out of range.
   nsIContent* sib = parent->GetChildAt(indx);
   if (sib != aNode) {
     // someone changed our index - find the new index the painful way
     indx = parent->IndexOf(aNode);
-    NS_WARN_IF(indx < 0);
+    NS_WARNING_ASSERTION(indx >= 0, "bad indx");
   }
 
   // indx is now canonically correct
   if (indx > 0 && (sib = parent->GetChildAt(--indx))) {
     // update index cache
     if (aIndexes && !aIndexes->IsEmpty()) {
       aIndexes->ElementAt(aIndexes->Length()-1) = indx;
     } else {
@@ -797,17 +799,17 @@ nsContentIterator::NextNode(nsINode* aNo
   // cheap, but a lot cheaper than IndexOf(), and still O(1).  ignore result
   // this time - the index may now be out of range.
   if (indx >= 0) {
     sibling = parent->GetChildAt(indx);
   }
   if (sibling != node) {
     // someone changed our index - find the new index the painful way
     indx = parent->IndexOf(node);
-    NS_WARN_IF(indx < 0);
+    NS_WARNING_ASSERTION(indx >= 0, "bad indx");
   }
 
   // indx is now canonically correct
   sibling = parent->GetChildAt(++indx);
   if (sibling) {
     // update cache
     if (aIndexes && !aIndexes->IsEmpty()) {
       // replace an entry on the index stack
@@ -862,23 +864,23 @@ nsContentIterator::PrevNode(nsINode* aNo
       indx = mCachedIndex;
     }
 
     // reverify that the index of the current node hasn't changed.  not super
     // cheap, but a lot cheaper than IndexOf(), and still O(1).  ignore result
     // this time - the index may now be out of range.
     if (indx >= 0) {
       sibling = parent->GetChildAt(indx);
-      NS_WARN_IF(!sibling);
+      NS_WARNING_ASSERTION(sibling, "GetChildAt returned null");
     }
 
     if (sibling != node) {
       // someone changed our index - find the new index the painful way
       indx = parent->IndexOf(node);
-      NS_WARN_IF(indx < 0);
+      NS_WARNING_ASSERTION(indx >= 0, "bad indx");
     }
 
     // indx is now canonically correct
     if (indx && (sibling = parent->GetChildAt(--indx))) {
       // update cache
       if (aIndexes && !aIndexes->IsEmpty()) {
         // replace an entry on the index stack
         aIndexes->ElementAt(aIndexes->Length()-1) = indx;
@@ -898,22 +900,22 @@ nsContentIterator::PrevNode(nsINode* aNo
       // this might be wrong, but we are better off guessing
       mCachedIndex = 0;
     }
     return parent;
   }
 
   // post-order
   int32_t numChildren = node->GetChildCount();
-  NS_WARN_IF(numChildren < 0);
+  NS_WARNING_ASSERTION(numChildren >= 0, "no children");
 
   // if it has children then prev node is last child
   if (numChildren) {
     nsIContent* lastChild = node->GetLastChild();
-    NS_WARN_IF(!lastChild);
+    NS_WARNING_ASSERTION(lastChild, "GetLastChild returned null");
     numChildren--;
 
     // update cache
     if (aIndexes) {
       // push an entry on the index stack
       aIndexes->AppendElement(numChildren);
     } else {
       mCachedIndex = numChildren;
@@ -1021,42 +1023,42 @@ nsContentIterator::PositionAt(nsINode* a
 
   nsINode* firstNode = mFirst;
   nsINode* lastNode = mLast;
   int32_t firstOffset = 0, lastOffset = 0;
 
   if (firstNode && lastNode) {
     if (mPre) {
       firstNode = NodeToParentOffset(mFirst, &firstOffset);
-      NS_WARN_IF(!firstNode);
-      NS_WARN_IF(firstOffset < 0);
+      NS_WARNING_ASSERTION(firstNode, "NodeToParentOffset returned null");
+      NS_WARNING_ASSERTION(firstOffset >= 0, "bad firstOffset");
 
       if (lastNode->GetChildCount()) {
         lastOffset = 0;
       } else {
         lastNode = NodeToParentOffset(mLast, &lastOffset);
-        NS_WARN_IF(!lastNode);
-        NS_WARN_IF(lastOffset < 0);
+        NS_WARNING_ASSERTION(lastNode, "NodeToParentOffset returned null");
+        NS_WARNING_ASSERTION(lastOffset >= 0, "bad lastOffset");
         ++lastOffset;
       }
     } else {
       uint32_t numChildren = firstNode->GetChildCount();
 
       if (numChildren) {
         firstOffset = numChildren;
-        NS_WARN_IF(firstOffset < 0);
+        NS_WARNING_ASSERTION(firstOffset >= 0, "bad firstOffset");
       } else {
         firstNode = NodeToParentOffset(mFirst, &firstOffset);
-        NS_WARN_IF(!firstNode);
-        NS_WARN_IF(firstOffset < 0);
+        NS_WARNING_ASSERTION(firstNode, "NodeToParentOffset returned null");
+        NS_WARNING_ASSERTION(firstOffset >= 0, "bad firstOffset");
       }
 
       lastNode = NodeToParentOffset(mLast, &lastOffset);
-      NS_WARN_IF(!lastNode);
-      NS_WARN_IF(lastOffset < 0);
+      NS_WARNING_ASSERTION(lastNode, "NodeToParentOffset returned null");
+      NS_WARNING_ASSERTION(lastOffset >= 0, "bad lastOffset");
       ++lastOffset;
     }
   }
 
   // The end positions are always in the range even if it has no parent.  We
   // need to allow that or 'iter->Init(root)' would assert in Last() or First()
   // for example, bug 327694.
   if (mFirst != mCurNode && mLast != mCurNode &&
@@ -1113,17 +1115,17 @@ nsContentIterator::PositionAt(nsINode* a
     nsINode* parent = newCurNode->GetParentNode();
 
     if (NS_WARN_IF(!parent)) {
       // this node has no parent, and thus no index
       break;
     }
 
     int32_t indx = parent->IndexOf(newCurNode);
-    NS_WARN_IF(indx < 0);
+    NS_WARNING_ASSERTION(indx >= 0, "bad indx");
 
     // insert at the head!
     newIndexes.InsertElementAt(0, indx);
 
     // look to see if the parent is in the stack
     indx = oldParentStack.IndexOf(parent);
     if (indx >= 0) {
       // ok, the parent IS on the old stack!  Rework things.  We want
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -9416,17 +9416,17 @@ nsContentUtils::HttpsStateIsModern(nsIDo
   if (principal->GetIsNullPrincipal()) {
     return false;
   }
 
   MOZ_ASSERT(principal->GetIsCodebasePrincipal());
 
   nsCOMPtr<nsIContentSecurityManager> csm =
     do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
-  NS_WARN_IF(!csm);
+  NS_WARNING_ASSERTION(csm, "csm is null");
   if (csm) {
     bool isTrustworthyOrigin = false;
     csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
     if (isTrustworthyOrigin) {
       return true;
     }
   }
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5369,17 +5369,19 @@ nsDocument::GetDocumentElement(nsIDOMEle
 }
 
 NS_IMETHODIMP
 nsDocument::CreateElement(const nsAString& aTagName,
                           nsIDOMElement** aReturn)
 {
   *aReturn = nullptr;
   ErrorResult rv;
-  ElementCreationOptions options;
+  ElementCreationOptionsOrString options;
+
+  options.SetAsString();
   nsCOMPtr<Element> element = CreateElement(aTagName, options, rv);
   NS_ENSURE_FALSE(rv.Failed(), rv.StealNSResult());
   return CallQueryInterface(element, aReturn);
 }
 
 bool IsLowercaseASCII(const nsAString& aValue)
 {
   int32_t len = aValue.Length();
@@ -5414,35 +5416,38 @@ nsDocument::GetCustomElementsRegistry()
     return nullptr;
   }
 
   return registry.forget();
 }
 
 already_AddRefed<Element>
 nsDocument::CreateElement(const nsAString& aTagName,
-                          const ElementCreationOptions& aOptions,
+                          const ElementCreationOptionsOrString& aOptions,
                           ErrorResult& rv)
 {
   rv = nsContentUtils::CheckQName(aTagName, false);
   if (rv.Failed()) {
     return nullptr;
   }
 
   bool needsLowercase = IsHTMLDocument() && !IsLowercaseASCII(aTagName);
   nsAutoString lcTagName;
   if (needsLowercase) {
     nsContentUtils::ASCIIToLower(aTagName, lcTagName);
   }
 
-  // Throw NotFoundError if 'is' is not-null and definition is null
-  nsString* is = CheckCustomElementName(
-    aOptions, needsLowercase ? lcTagName : aTagName, mDefaultElementType, rv);
-  if (rv.Failed()) {
-    return nullptr;
+  const nsString* is = nullptr;
+  if (aOptions.IsElementCreationOptions()) {
+    // Throw NotFoundError if 'is' is not-null and definition is null
+    is = CheckCustomElementName(aOptions.GetAsElementCreationOptions(),
+      needsLowercase ? lcTagName : aTagName, mDefaultElementType, rv);
+    if (rv.Failed()) {
+      return nullptr;
+    }
   }
 
   RefPtr<Element> elem = CreateElem(
     needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
 
   return elem.forget();
 }
 
@@ -5472,17 +5477,17 @@ nsDocument::CreateElementNS(const nsAStr
                                             mNodeInfoManager,
                                             nsIDOMNode::ELEMENT_NODE,
                                             getter_AddRefs(nodeInfo));
   if (rv.Failed()) {
     return nullptr;
   }
 
   // Throw NotFoundError if 'is' is not-null and definition is null
-  nsString* is = CheckCustomElementName(
+  const nsString* is = CheckCustomElementName(
     aOptions, aQualifiedName, nodeInfo->NamespaceID(), rv);
   if (rv.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<Element> element;
   rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
                      NOT_FROM_PARSER, is);
@@ -8145,17 +8150,17 @@ nsDocument::RetrieveRelevantHeaders(nsIC
   mLastModified.Truncate();
   if (modDate != 0) {
     GetFormattedTimeString(modDate, mLastModified);
   }
 }
 
 already_AddRefed<Element>
 nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix,
-                       int32_t aNamespaceID, nsAString* aIs)
+                       int32_t aNamespaceID, const nsAString* aIs)
 {
 #ifdef DEBUG
   nsAutoString qName;
   if (aPrefix) {
     aPrefix->ToString(qName);
     qName.Append(':');
   }
   qName.Append(aName);
@@ -12885,30 +12890,30 @@ nsIDocument::UpdateStyleBackendType()
   if (!mDocumentContainer) {
     NS_WARNING("stylo: No docshell yet, assuming Gecko style system");
   } else if (nsLayoutUtils::SupportsServoStyleBackend(this)) {
     mStyleBackendType = StyleBackendType::Servo;
   }
 #endif
 }
 
-nsString*
+const nsString*
 nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions,
                                    const nsAString& aLocalName,
                                    uint32_t aNamespaceID,
                                    ErrorResult& rv)
 {
   // only check aOptions if 'is' is passed and the webcomponents preference
   // is enabled
   if (!aOptions.mIs.WasPassed() ||
       !Preferences::GetBool("dom.webcomponents.enabled")) {
       return nullptr;
   }
 
-  nsString* is = const_cast<nsString*>(&(aOptions.mIs.Value()));
+  const nsString* is = &aOptions.mIs.Value();
 
   // Throw NotFoundError if 'is' is not-null and definition is null
   if (!nsContentUtils::LookupCustomElementDefinition(this, aLocalName,
                                                      aNamespaceID, is)) {
       rv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
   }
 
   return is;
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -823,17 +823,17 @@ public:
 
   NS_DECL_NSIDOMXPATHEVALUATOR
 
   virtual nsresult Init();
 
   virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
                                                nsIAtom* aPrefix,
                                                int32_t aNamespaceID,
-                                               nsAString* aIs = nullptr) override;
+                                               const nsAString* aIs = nullptr) override;
 
   virtual void Sanitize() override;
 
   virtual void EnumerateSubDocuments(nsSubDocEnumFunc aCallback,
                                                  void *aData) override;
 
   virtual bool CanSavePresentation(nsIRequest *aNewRequest) override;
   virtual void Destroy() override;
@@ -1126,17 +1126,17 @@ public:
                     JS::MutableHandle<JSObject*> aRetval,
                     mozilla::ErrorResult& rv) override;
   virtual mozilla::dom::StyleSheetList* StyleSheets() override;
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) override;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) override;
   virtual mozilla::dom::DOMStringList* StyleSheetSets() override;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) override;
   virtual already_AddRefed<Element> CreateElement(const nsAString& aTagName,
-                                                  const mozilla::dom::ElementCreationOptions& aOptions,
+                                                  const mozilla::dom::ElementCreationOptionsOrString& aOptions,
                                                   ErrorResult& rv) override;
   virtual already_AddRefed<Element> CreateElementNS(const nsAString& aNamespaceURI,
                                                     const nsAString& aQualifiedName,
                                                     const mozilla::dom::ElementCreationOptions& aOptions,
                                                     mozilla::ErrorResult& rv) override;
 
   virtual nsIDocument* MasterDocument() override
   {
@@ -1373,17 +1373,17 @@ private:
   /**
    * Check if the passed custom element name, aOptions.mIs, is a registered
    * custom element type or not, then return the custom element name for future
    * usage.
    *
    * If there is no existing custom element definition for this name, throw a
    * NotFoundError.
    */
-  nsString* CheckCustomElementName(
+  const nsString* CheckCustomElementName(
     const mozilla::dom::ElementCreationOptions& aOptions,
     const nsAString& aLocalName,
     uint32_t aNamespaceID,
     ErrorResult& rv);
 
 public:
   virtual already_AddRefed<mozilla::dom::CustomElementsRegistry>
     GetCustomElementsRegistry() override;
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -307,16 +307,17 @@ GK_ATOM(digit, "digit")
 GK_ATOM(dir, "dir")
 GK_ATOM(dirAutoSetBy, "dirAutoSetBy")
 GK_ATOM(directionality, "directionality")
 GK_ATOM(directory, "directory")
 GK_ATOM(disableOutputEscaping, "disable-output-escaping")
 GK_ATOM(disabled, "disabled")
 GK_ATOM(disableglobalhistory, "disableglobalhistory")
 GK_ATOM(disablehistory, "disablehistory")
+GK_ATOM(disablefullscreen, "disablefullscreen")
 GK_ATOM(display, "display")
 GK_ATOM(displayMode, "display-mode")
 GK_ATOM(distinct, "distinct")
 GK_ATOM(div, "div")
 GK_ATOM(dl, "dl")
 GK_ATOM(doctypePublic, "doctype-public")
 GK_ATOM(doctypeSystem, "doctype-system")
 GK_ATOM(document, "document")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -538,17 +538,16 @@ nsTimeout::~nsTimeout()
   MOZ_COUNT_DTOR(nsTimeout);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
 
 nsresult
 nsTimeout::InitTimer(uint32_t aDelay)
 {
@@ -2412,17 +2411,17 @@ nsGlobalWindow::ComputeIsSecureContext(n
     principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
     if (NS_WARN_IF(!principal)) {
       return false;
     }
   }
 
   nsCOMPtr<nsIContentSecurityManager> csm =
     do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
-  NS_WARN_IF(!csm);
+  NS_WARNING_ASSERTION(csm, "csm is null");
   if (csm) {
     bool isTrustworthyOrigin = false;
     csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
     if (isTrustworthyOrigin) {
       return true;
     }
   }
 
@@ -12031,33 +12030,16 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
   uint32_t nestingLevel = sNestingLevel + 1;
   uint32_t realInterval = interval;
   if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
     // Don't allow timeouts less than DOMMinTimeoutValue() from
     // now...
     realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue()));
   }
 
-  // Get principal of currently executing code, save for execution of timeout.
-  // If our principals subsume the subject principal then use the subject
-  // principal. Otherwise, use our principal to avoid running script in
-  // elevated principals.
-  //
-  // Note the direction of this test: We don't allow setTimeouts running with
-  // chrome privileges on content windows, but we do allow setTimeouts running
-  // with content privileges on chrome windows (where they can't do very much,
-  // of course).
-  nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
-  nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
-  if (ourPrincipal->Subsumes(subjectPrincipal)) {
-    timeout->mPrincipal = subjectPrincipal;
-  } else {
-    timeout->mPrincipal = ourPrincipal;
-  }
-
   TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
 
   if (!IsFrozen() && !mTimeoutsSuspendDepth) {
     // If we're not currently frozen, then we set timeout->mWhen to be the
     // actual firing time of the timer (i.e., now + delta). We also actually
     // create a timer and fire it off.
 
     timeout->mWhen = TimeStamp::Now() + delta;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -193,19 +193,16 @@ public:
   // mWhen and mTimeRemaining can't be in a union, sadly, because they
   // have constructors.
   // Nominal time to run this timeout.  Use only when timeouts are not
   // suspended.
   mozilla::TimeStamp mWhen;
   // Remaining time to wait.  Used only when timeouts are suspended.
   mozilla::TimeDuration mTimeRemaining;
 
-  // Principal with which to execute
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-
   // stack depth at which timeout is firing
   uint32_t mFiringDepth;
 
   uint32_t mNestingLevel;
 
   // The popup state at timeout creation time if not created from
   // another timeout
   PopupControlState mPopupState;
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -135,33 +135,34 @@ BroadcastBlobURLRegistration(const nsACS
   }
 
   ContentChild* cc = ContentChild::GetSingleton();
   BlobChild* actor = cc->GetOrCreateActorForBlobImpl(aBlobImpl);
   if (NS_WARN_IF(!actor)) {
     return;
   }
 
-  NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration(nsCString(aURI), actor,
-                                                           IPC::Principal(aPrincipal)));
+  Unused << NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration(
+    nsCString(aURI), actor, IPC::Principal(aPrincipal)));
 }
 
 void
 BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo)
 {
   MOZ_ASSERT(aInfo);
   MOZ_ASSERT(NS_IsMainThread());
 
   if (XRE_IsParentProcess()) {
     ContentParent::BroadcastBlobURLUnregistration(aURI);
     return;
   }
 
   ContentChild* cc = ContentChild::GetSingleton();
-  NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(nsCString(aURI)));
+  Unused << NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(
+    nsCString(aURI)));
 }
 
 class HostObjectURLsReporter final : public nsIMemoryReporter
 {
   ~HostObjectURLsReporter() {}
 
  public:
   NS_DECL_ISUPPORTS
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -19,30 +19,39 @@
 #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 "mozilla/net/ReferrerPolicy.h"  // for member
 #include "nsWeakReference.h"
-#include "mozilla/dom/DocumentBinding.h"
 #include "mozilla/UseCounter.h"
 #include "mozilla/WeakPtr.h"
 #include "Units.h"
 #include "nsContentListDeclarations.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "prclist.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/StyleBackendType.h"
 #include "mozilla/StyleSheetHandle.h"
 #include <bitset>                        // for member
 
+#ifdef MOZILLA_INTERNAL_API
+#include "mozilla/dom/DocumentBinding.h"
+#else
+namespace mozilla {
+namespace dom {
+class ElementCreationOptionsOrString;
+} // namespace dom
+} // namespace mozilla
+#endif // MOZILLA_INTERNAL_API
+
 class gfxUserFontSet;
 class imgIRequest;
 class nsAString;
 class nsBindingManager;
 class nsIDocShell;
 class nsDocShell;
 class nsDOMNavigationTiming;
 class nsFrameLoader;
@@ -1508,17 +1517,17 @@ public:
 
   /**
    * Create an element with the specified name, prefix and namespace ID.
    * Returns null if element name parsing failed.
    */
   virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
                                                nsIAtom* aPrefix,
                                                int32_t aNamespaceID,
-                                               nsAString* aIs = nullptr) = 0;
+                                               const nsAString* aIs = nullptr) = 0;
 
   /**
    * Get the security info (i.e. SSL state etc) that the document got
    * from the channel/document that created the content of the
    * document.
    *
    * @see nsIChannel
    */
@@ -2499,17 +2508,17 @@ public:
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName,
                            mozilla::ErrorResult& aResult);
   already_AddRefed<nsContentList>
     GetElementsByClassName(const nsAString& aClasses);
   // GetElementById defined above
   virtual already_AddRefed<Element>
     CreateElement(const nsAString& aTagName,
-                  const mozilla::dom::ElementCreationOptions& aOptions,
+                  const mozilla::dom::ElementCreationOptionsOrString& aOptions,
                   mozilla::ErrorResult& rv) = 0;
   virtual already_AddRefed<Element>
     CreateElementNS(const nsAString& aNamespaceURI,
                     const nsAString& aQualifiedName,
                     const mozilla::dom::ElementCreationOptions& aOptions,
                     mozilla::ErrorResult& rv) = 0;
   already_AddRefed<mozilla::dom::DocumentFragment>
     CreateDocumentFragment() const;
@@ -2586,16 +2595,17 @@ public:
     return !!GetFullscreenElement();
   }
   void ExitFullscreen();
   Element* GetPointerLockElement();
   void ExitPointerLock()
   {
     UnlockPointer(this);
   }
+#ifdef MOZILLA_INTERNAL_API
   bool Hidden() const
   {
     return mVisibilityState != mozilla::dom::VisibilityState::Visible;
   }
   bool MozHidden() const
   {
     WarnOnceAbout(ePrefixedVisibilityAPI);
     return Hidden();
@@ -2604,16 +2614,17 @@ public:
   {
     return mVisibilityState;
   }
   mozilla::dom::VisibilityState MozVisibilityState() const
   {
     WarnOnceAbout(ePrefixedVisibilityAPI);
     return VisibilityState();
   }
+#endif
   virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
   void GetPreferredStyleSheetSet(nsAString& aSheetSet);
   virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
   Element* ElementFromPoint(float aX, float aY);
@@ -2907,18 +2918,23 @@ protected:
   RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
 
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
+#ifdef MOZILLA_INTERNAL_API
   // Our visibility state
   mozilla::dom::VisibilityState mVisibilityState;
+  static_assert(sizeof(mozilla::dom::VisibilityState) == sizeof(uint32_t), "Error size of mVisibilityState and mDummy");
+#else
+  uint32_t mDummy;
+#endif
 
   // Whether this document has (or will have, once we have a pres shell) a
   // Gecko- or Servo-backed style system.
   mozilla::StyleBackendType mStyleBackendType;
 
   // True if BIDI is enabled.
   bool mBidiEnabled : 1;
   // True if a MathML element has ever been owned by this document.
--- a/dom/base/nsNameSpaceManager.cpp
+++ b/dom/base/nsNameSpaceManager.cpp
@@ -103,17 +103,17 @@ nsNameSpaceManager::RegisterNameSpace(co
 
     rv = AddNameSpace(atom.forget(), aNameSpaceID);
     if (NS_FAILED(rv)) {
       aNameSpaceID = kNameSpaceID_Unknown;
     }
   }
 
   NS_POSTCONDITION(aNameSpaceID >= -1, "Bogus namespace ID");
-  
+
   return rv;
 }
 
 nsresult
 nsNameSpaceManager::GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI)
 {
   NS_PRECONDITION(aNameSpaceID >= 0, "Bogus namespace ID");
 
@@ -164,17 +164,17 @@ nsNameSpaceManager::GetNameSpaceID(nsIAt
 
   return kNameSpaceID_Unknown;
 }
 
 nsresult
 NS_NewElement(Element** aResult,
               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
               FromParser aFromParser,
-              nsAString* aIs)
+              const nsAString* aIs)
 {
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
   int32_t ns = ni->NamespaceID();
   if (ns == kNameSpaceID_XHTML) {
     return NS_NewHTMLElement(aResult, ni.forget(), aFromParser, aIs);
   }
 #ifdef MOZ_XUL
   if (ns == kNameSpaceID_XUL) {
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -495,12 +495,30 @@ struct MOZ_STACK_CLASS ParentObject {
 
   // We don't want to make this an nsCOMPtr because of performance reasons, but
   // it's safe because ParentObject is a stack class.
   nsISupports* const MOZ_NON_OWNING_REF mObject;
   nsWrapperCache* const mWrapperCache;
   bool mUseXBLScope;
 };
 
+namespace binding_detail {
+
+// Class for simple sequence arguments, only used internally by codegen.
+template<typename T>
+class AutoSequence : public AutoTArray<T, 16>
+{
+public:
+  AutoSequence() : AutoTArray<T, 16>()
+  {}
+
+  // Allow converting to const sequences as needed
+  operator const Sequence<T>&() const {
+    return *reinterpret_cast<const Sequence<T>*>(this);
+  }
+};
+
+} // namespace binding_detail
+
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -33,16 +33,17 @@
 #include "nsIDocument.h"
 #include "nsIGlobalObject.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsISupportsImpl.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
 #include "nsIVariant.h"
+#include "mozilla/dom/FakeString.h"
 
 #include "nsWrapperCacheInlines.h"
 
 class nsIJSID;
 
 namespace mozilla {
 
 enum UseCounter : int16_t;
@@ -1895,156 +1896,16 @@ HasPropertyOnPrototype(JSContext* cx, JS
 // then the "proxy" argument is ignored.
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                        nsTArray<nsString>& names,
                        bool shadowPrototypeProperties, JS::AutoIdVector& props);
 
 namespace binding_detail {
 
-// A struct that has the same layout as an nsString but much faster
-// constructor and destructor behavior. FakeString uses inline storage
-// for small strings and a nsStringBuffer for longer strings.
-struct FakeString {
-  FakeString() :
-    mFlags(nsString::F_TERMINATED)
-  {
-  }
-
-  ~FakeString() {
-    if (mFlags & nsString::F_SHARED) {
-      nsStringBuffer::FromData(mData)->Release();
-    }
-  }
-
-  void Rebind(const nsString::char_type* aData, nsString::size_type aLength) {
-    MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
-    mData = const_cast<nsString::char_type*>(aData);
-    mLength = aLength;
-  }
-
-  // Share aString's string buffer, if it has one; otherwise, make this string
-  // depend upon aString's data.  aString should outlive this instance of
-  // FakeString.
-  void ShareOrDependUpon(const nsAString& aString) {
-    RefPtr<nsStringBuffer> sharedBuffer = nsStringBuffer::FromString(aString);
-    if (!sharedBuffer) {
-      Rebind(aString.Data(), aString.Length());
-    } else {
-      AssignFromStringBuffer(sharedBuffer.forget());
-      mLength = aString.Length();
-    }
-  }
-
-  void Truncate() {
-    MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
-    mData = nsString::char_traits::sEmptyBuffer;
-    mLength = 0;
-  }
-
-  void SetIsVoid(bool aValue) {
-    MOZ_ASSERT(aValue,
-               "We don't support SetIsVoid(false) on FakeString!");
-    Truncate();
-    mFlags |= nsString::F_VOIDED;
-  }
-
-  const nsString::char_type* Data() const
-  {
-    return mData;
-  }
-
-  nsString::char_type* BeginWriting()
-  {
-    return mData;
-  }
-
-  nsString::size_type Length() const
-  {
-    return mLength;
-  }
-
-  // Reserve space to write aLength chars, not including null-terminator.
-  bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) {
-    // Use mInlineStorage for small strings.
-    if (aLength < sInlineCapacity) {
-      SetData(mInlineStorage);
-    } else {
-      RefPtr<nsStringBuffer> buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type));
-      if (MOZ_UNLIKELY(!buf)) {
-        return false;
-      }
-
-      AssignFromStringBuffer(buf.forget());
-    }
-    mLength = aLength;
-    mData[mLength] = char16_t(0);
-    return true;
-  }
-
-  // If this ever changes, change the corresponding code in the
-  // Optional<nsAString> specialization as well.
-  const nsAString* ToAStringPtr() const {
-    return reinterpret_cast<const nsString*>(this);
-  }
-
-operator const nsAString& () const {
-    return *reinterpret_cast<const nsString*>(this);
-  }
-
-private:
-  nsAString* ToAStringPtr() {
-    return reinterpret_cast<nsString*>(this);
-  }
-
-  nsString::char_type* mData;
-  nsString::size_type mLength;
-  uint32_t mFlags;
-
-  static const size_t sInlineCapacity = 64;
-  nsString::char_type mInlineStorage[sInlineCapacity];
-
-  FakeString(const FakeString& other) = delete;
-  void operator=(const FakeString& other) = delete;
-
-  void SetData(nsString::char_type* aData) {
-    MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
-    mData = const_cast<nsString::char_type*>(aData);
-  }
-  void AssignFromStringBuffer(already_AddRefed<nsStringBuffer> aBuffer) {
-    SetData(static_cast<nsString::char_type*>(aBuffer.take()->Data()));
-    mFlags = nsString::F_SHARED | nsString::F_TERMINATED;
-  }
-
-  friend class NonNull<nsAString>;
-
-  // A class to use for our static asserts to ensure our object layout
-  // matches that of nsString.
-  class StringAsserter;
-  friend class StringAsserter;
-
-  class StringAsserter : public nsString {
-  public:
-    static void StaticAsserts() {
-      static_assert(offsetof(FakeString, mInlineStorage) ==
-                      sizeof(nsString),
-                    "FakeString should include all nsString members");
-      static_assert(offsetof(FakeString, mData) ==
-                      offsetof(StringAsserter, mData),
-                    "Offset of mData should match");
-      static_assert(offsetof(FakeString, mLength) ==
-                      offsetof(StringAsserter, mLength),
-                    "Offset of mLength should match");
-      static_assert(offsetof(FakeString, mFlags) ==
-                      offsetof(StringAsserter, mFlags),
-                    "Offset of mFlags should match");
-    }
-  };
-};
-
 class FastErrorResult :
     public mozilla::binding_danger::TErrorResult<
       mozilla::binding_danger::JustAssertCleanupPolicy>
 {
 };
 
 } // namespace binding_detail
 
@@ -2123,34 +1984,16 @@ bool
 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
                            bool nullable, nsACString& result);
 
 template<typename T>
 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
 template<typename T>
 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
 
-// Class for simple sequence arguments, only used internally by codegen.
-namespace binding_detail {
-
-template<typename T>
-class AutoSequence : public AutoTArray<T, 16>
-{
-public:
-  AutoSequence() : AutoTArray<T, 16>()
-  {}
-
-  // Allow converting to const sequences as needed
-  operator const Sequence<T>&() const {
-    return *reinterpret_cast<const Sequence<T>*>(this);
-  }
-};
-
-} // namespace binding_detail
-
 // Class used to trace sequences, with specializations for various
 // sequence types.
 template<typename T,
          bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
          bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
          bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
 class SequenceTracer
 {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -13286,19 +13286,23 @@ class CGBindingRoot(CGThing):
 
         unionTypes = UnionsForFile(config, webIDLFile)
 
         (unionHeaders, unionImplheaders, unionDeclarations, traverseMethods,
          unlinkMethods, unionStructs) = UnionTypes(unionTypes, config)
 
         bindingDeclareHeaders.update(dict.fromkeys(unionHeaders, True))
         bindingHeaders.update(dict.fromkeys(unionImplheaders, True))
-
         bindingDeclareHeaders["mozilla/dom/UnionMember.h"] = len(unionStructs) > 0
-        bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = len(unionStructs) > 0
+        bindingDeclareHeaders["mozilla/dom/FakeString.h"] = len(unionStructs) > 0
+        # BindingUtils.h is only needed for SetToObject.
+        # If it stops being inlined or stops calling CallerSubsumes
+        # both this bit and the bit in UnionTypes can be removed.
+        bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = any(d.isObject() for t in unionTypes
+                                                                  for d in t.flatMemberTypes)
         bindingDeclareHeaders["mozilla/dom/IterableIterator.h"] = any(d.interface.isIteratorInterface() or
                                                                       d.interface.isIterable() for d in descriptors)
 
         def descriptorHasCrossOriginProperties(desc):
             def hasCrossOriginProperty(m):
                 props = memberProperties(m, desc)
                 return (props.isCrossOriginMethod or
                         props.isCrossOriginGetter or
@@ -16354,17 +16358,19 @@ class GlobalGenRoots():
                         unlinkMethods +
                         [CGUnionStruct(t, config) for t in unionStructs] +
                         [CGUnionStruct(t, config, True) for t in unionStructs],
                         "\n")
 
         includes.add("mozilla/OwningNonNull.h")
         includes.add("mozilla/dom/UnionMember.h")
         includes.add("mozilla/dom/BindingDeclarations.h")
-        # Need BindingUtils.h for FakeString
+        # BindingUtils.h is only needed for SetToObject.
+        # If it stops being inlined or stops calling CallerSubsumes
+        # both this bit and the bit in CGBindingRoot can be removed.
         includes.add("mozilla/dom/BindingUtils.h")
         implincludes.add("mozilla/dom/PrimitiveConversions.h")
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 
         curr = CGWrapper(curr, post='\n')
 
copy from dom/bindings/BindingUtils.h
copy to dom/bindings/FakeString.h
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/FakeString.h
@@ -1,1910 +1,24 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_BindingUtils_h__
-#define mozilla_dom_BindingUtils_h__
+#ifndef mozilla_dom_FakeString_h__
+#define mozilla_dom_FakeString_h__
 
-#include "jsfriendapi.h"
-#include "jswrapper.h"
-#include "js/Conversions.h"
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/Alignment.h"
-#include "mozilla/Array.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/CycleCollectedJSRuntime.h"
-#include "mozilla/DeferredFinalize.h"
-#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/CallbackObject.h"
-#include "mozilla/dom/DOMJSClass.h"
-#include "mozilla/dom/DOMJSProxyHandler.h"
-#include "mozilla/dom/Exceptions.h"
-#include "mozilla/dom/NonRefcountedDOMObject.h"
-#include "mozilla/dom/Nullable.h"
-#include "mozilla/dom/RootedDictionary.h"
-#include "mozilla/SegmentedVector.h"
-#include "mozilla/dom/workers/Workers.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/Likely.h"
-#include "mozilla/MemoryReporting.h"
-#include "nsAutoPtr.h"
-#include "nsIDocument.h"
-#include "nsIGlobalObject.h"
-#include "nsIXPConnect.h"
-#include "nsJSUtils.h"
-#include "nsISupportsImpl.h"
-#include "qsObjectHelper.h"
-#include "xpcpublic.h"
-#include "nsIVariant.h"
-
-#include "nsWrapperCacheInlines.h"
-
-class nsIJSID;
+#include "nsString.h"
+#include "nsStringBuffer.h"
+#include "mozilla/RefPtr.h"
 
 namespace mozilla {
-
-enum UseCounter : int16_t;
-
 namespace dom {
-template<typename DataType> class MozMap;
-
-nsresult
-UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
-
-nsresult
-UnwrapWindowProxyImpl(JS::Handle<JSObject*> src, nsPIDOMWindowOuter** ppArg);
-
-/** Convert a jsval to an XPCOM pointer. */
-template <class Interface>
-inline nsresult
-UnwrapArg(JS::Handle<JSObject*> src, Interface** ppArg)
-{
-  return UnwrapArgImpl(src, NS_GET_TEMPLATE_IID(Interface),
-                       reinterpret_cast<void**>(ppArg));
-}
-
-template <>
-inline nsresult
-UnwrapArg<nsPIDOMWindowOuter>(JS::Handle<JSObject*> src, nsPIDOMWindowOuter** ppArg)
-{
-  return UnwrapWindowProxyImpl(src, ppArg);
-}
-
-bool
-ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
-                 bool aSecurityError, const char* aInterfaceName);
-
-bool
-ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
-                 bool aSecurityError, prototypes::ID aProtoId);
-
-// Returns true if the JSClass is used for DOM objects.
-inline bool
-IsDOMClass(const JSClass* clasp)
-{
-  return clasp->flags & JSCLASS_IS_DOMJSCLASS;
-}
-
-inline bool
-IsDOMClass(const js::Class* clasp)
-{
-  return IsDOMClass(Jsvalify(clasp));
-}
-
-// Return true if the JSClass is used for non-proxy DOM objects.
-inline bool
-IsNonProxyDOMClass(const js::Class* clasp)
-{
-  return IsDOMClass(clasp) && !clasp->isProxy();
-}
-
-inline bool
-IsNonProxyDOMClass(const JSClass* clasp)
-{
-  return IsNonProxyDOMClass(js::Valueify(clasp));
-}
-
-// Returns true if the JSClass is used for DOM interface and interface
-// prototype objects.
-inline bool
-IsDOMIfaceAndProtoClass(const JSClass* clasp)
-{
-  return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
-}
-
-inline bool
-IsDOMIfaceAndProtoClass(const js::Class* clasp)
-{
-  return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
-}
-
-static_assert(DOM_OBJECT_SLOT == 0,
-              "DOM_OBJECT_SLOT doesn't match the proxy private slot.  "
-              "Expect bad things");
-template <class T>
-inline T*
-UnwrapDOMObject(JSObject* obj)
-{
-  MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
-             "Don't pass non-DOM objects to this function");
-
-  JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
-  return static_cast<T*>(val.toPrivate());
-}
-
-template <class T>
-inline T*
-UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
-{
-  // This is used by the OjectMoved JSClass hook which can be called before
-  // JS_NewObject has returned and so before we have a chance to set
-  // DOM_OBJECT_SLOT to anything useful.
-
-  MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
-             "Don't pass non-DOM objects to this function");
-
-  JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
-  if (val.isUndefined()) {
-    return nullptr;
-  }
-  return static_cast<T*>(val.toPrivate());
-}
-
-inline const DOMJSClass*
-GetDOMClass(const js::Class* clasp)
-{
-  return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
-}
-
-inline const DOMJSClass*
-GetDOMClass(JSObject* obj)
-{
-  return GetDOMClass(js::GetObjectClass(obj));
-}
-
-inline nsISupports*
-UnwrapDOMObjectToISupports(JSObject* aObject)
-{
-  const DOMJSClass* clasp = GetDOMClass(aObject);
-  if (!clasp || !clasp->mDOMObjectIsISupports) {
-    return nullptr;
-  }
-
-  return UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObject);
-}
-
-inline bool
-IsDOMObject(JSObject* obj)
-{
-  return IsDOMClass(js::GetObjectClass(obj));
-}
-
-#define UNWRAP_OBJECT(Interface, obj, value)                                 \
-  mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface,        \
-    mozilla::dom::Interface##Binding::NativeType>(obj, value)
-
-// Some callers don't want to set an exception when unwrapping fails
-// (for example, overload resolution uses unwrapping to tell what sort
-// of thing it's looking at).
-// U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
-template <class T, typename U>
-MOZ_ALWAYS_INLINE nsresult
-UnwrapObject(JSObject* obj, U& value, prototypes::ID protoID,
-             uint32_t protoDepth)
-{
-  /* First check to see whether we have a DOM object */
-  const DOMJSClass* domClass = GetDOMClass(obj);
-  if (!domClass) {
-    /* Maybe we have a security wrapper or outer window? */
-    if (!js::IsWrapper(obj)) {
-      /* Not a DOM object, not a wrapper, just bail */
-      return NS_ERROR_XPC_BAD_CONVERT_JS;
-    }
-
-    obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
-    if (!obj) {
-      return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
-    }
-    MOZ_ASSERT(!js::IsWrapper(obj));
-    domClass = GetDOMClass(obj);
-    if (!domClass) {
-      /* We don't have a DOM object */
-      return NS_ERROR_XPC_BAD_CONVERT_JS;
-    }
-  }
-
-  /* This object is a DOM object.  Double-check that it is safely
-     castable to T by checking whether it claims to inherit from the
-     class identified by protoID. */
-  if (domClass->mInterfaceChain[protoDepth] == protoID) {
-    value = UnwrapDOMObject<T>(obj);
-    return NS_OK;
-  }
-
-  /* It's the wrong sort of DOM object */
-  return NS_ERROR_XPC_BAD_CONVERT_JS;
-}
-
-template <prototypes::ID PrototypeID, class T, typename U>
-MOZ_ALWAYS_INLINE nsresult
-UnwrapObject(JSObject* obj, U& value)
-{
-  return UnwrapObject<T>(obj, value, PrototypeID,
-                         PrototypeTraits<PrototypeID>::Depth);
-}
-
-inline bool
-IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj,
-                  bool* notDateOrRegExp)
-{
-  MOZ_ASSERT(obj);
-
-  js::ESClass cls;
-  if (!js::GetBuiltinClass(cx, obj, &cls)) {
-    return false;
-  }
-
-  *notDateOrRegExp = cls != js::ESClass::Date && cls != js::ESClass::RegExp;
-  return true;
-}
-
-MOZ_ALWAYS_INLINE bool
-IsObjectValueConvertibleToDictionary(JSContext* cx,
-                                     JS::Handle<JS::Value> objVal,
-                                     bool* convertible)
-{
-  JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
-  return IsNotDateOrRegExp(cx, obj, convertible);
-}
-
-MOZ_ALWAYS_INLINE bool
-IsConvertibleToDictionary(JSContext* cx, JS::Handle<JS::Value> val,
-                          bool* convertible)
-{
-  if (val.isNullOrUndefined()) {
-    *convertible = true;
-    return true;
-  }
-  if (!val.isObject()) {
-    *convertible = false;
-    return true;
-  }
-  return IsObjectValueConvertibleToDictionary(cx, val, convertible);
-}
-
-MOZ_ALWAYS_INLINE bool
-IsConvertibleToCallbackInterface(JSContext* cx, JS::Handle<JSObject*> obj,
-                                 bool* convertible)
-{
-  return IsNotDateOrRegExp(cx, obj, convertible);
-}
-
-// The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
-// constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
-// The end of the prototype objects should be the start of the interface
-// objects, and the end of the interface objects should be the start of the
-// named properties objects.
-static_assert((size_t)constructors::id::_ID_Start ==
-              (size_t)prototypes::id::_ID_Count &&
-              (size_t)namedpropertiesobjects::id::_ID_Start ==
-              (size_t)constructors::id::_ID_Count,
-              "Overlapping or discontiguous indexes.");
-const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
-
-class ProtoAndIfaceCache
-{
-  // The caching strategy we use depends on what sort of global we're dealing
-  // with.  For a window-like global, we want everything to be as fast as
-  // possible, so we use a flat array, indexed by prototype/constructor ID.
-  // For everything else (e.g. globals for JSMs), space is more important than
-  // speed, so we use a two-level lookup table.
-
-  class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
-  {
-  public:
-    JSObject* EntrySlotIfExists(size_t i) {
-      return (*this)[i];
-    }
-
-    JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
-      return (*this)[i];
-    }
-
-    JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
-      return (*this)[i];
-    }
-
-    void Trace(JSTracer* aTracer) {
-      for (size_t i = 0; i < ArrayLength(*this); ++i) {
-        JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
-      }
-    }
-
-    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
-      return aMallocSizeOf(this);
-    }
-  };
-
-  class PageTableCache
-  {
-  public:
-    PageTableCache() {
-      memset(&mPages, 0, sizeof(mPages));
-    }
-
-    ~PageTableCache() {
-      for (size_t i = 0; i < ArrayLength(mPages); ++i) {
-        delete mPages[i];
-      }
-    }
-
-    JSObject* EntrySlotIfExists(size_t i) {
-      MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
-      size_t pageIndex = i / kPageSize;
-      size_t leafIndex = i % kPageSize;
-      Page* p = mPages[pageIndex];
-      if (!p) {
-        return nullptr;
-      }
-      return (*p)[leafIndex];
-    }
-
-    JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
-      MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
-      size_t pageIndex = i / kPageSize;
-      size_t leafIndex = i % kPageSize;
-      Page* p = mPages[pageIndex];
-      if (!p) {
-        p = new Page;
-        mPages[pageIndex] = p;
-      }
-      return (*p)[leafIndex];
-    }
-
-    JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
-      MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
-      size_t pageIndex = i / kPageSize;
-      size_t leafIndex = i % kPageSize;
-      Page* p = mPages[pageIndex];
-      MOZ_ASSERT(p);
-      return (*p)[leafIndex];
-    }
-
-    void Trace(JSTracer* trc) {
-      for (size_t i = 0; i < ArrayLength(mPages); ++i) {
-        Page* p = mPages[i];
-        if (p) {
-          for (size_t j = 0; j < ArrayLength(*p); ++j) {
-            JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
-          }
-        }
-      }
-    }
-
-    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
-      size_t n = aMallocSizeOf(this);
-      for (size_t i = 0; i < ArrayLength(mPages); ++i) {
-        n += aMallocSizeOf(mPages[i]);
-      }
-      return n;
-    }
-
-  private:
-    static const size_t kPageSize = 16;
-    typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
-    static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
-      size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
-    Array<Page*, kNPages> mPages;
-  };
-
-public:
-  enum Kind {
-    WindowLike,
-    NonWindowLike
-  };
-
-  explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
-    MOZ_COUNT_CTOR(ProtoAndIfaceCache);
-    if (aKind == WindowLike) {
-      mArrayCache = new ArrayCache();
-    } else {
-      mPageTableCache = new PageTableCache();
-    }
-  }
-
-  ~ProtoAndIfaceCache() {
-    if (mKind == WindowLike) {
-      delete mArrayCache;
-    } else {
-      delete mPageTableCache;
-    }
-    MOZ_COUNT_DTOR(ProtoAndIfaceCache);
-  }
-
-#define FORWARD_OPERATION(opName, args)              \
-  do {                                               \
-    if (mKind == WindowLike) {                       \
-      return mArrayCache->opName args;               \
-    } else {                                         \
-      return mPageTableCache->opName args;           \
-    }                                                \
-  } while(0)
-
-  // Return the JSObject stored in slot i, if that slot exists.  If
-  // the slot does not exist, return null.
-  JSObject* EntrySlotIfExists(size_t i) {
-    FORWARD_OPERATION(EntrySlotIfExists, (i));
-  }
-
-  // Return a reference to slot i, creating it if necessary.  There
-  // may not be an object in the returned slot.
-  JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
-    FORWARD_OPERATION(EntrySlotOrCreate, (i));
-  }
-
-  // Return a reference to slot i, which is guaranteed to already
-  // exist.  There may not be an object in the slot, if prototype and
-  // constructor initialization for one of our bindings failed.
-  JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
-    FORWARD_OPERATION(EntrySlotMustExist, (i));
-  }
-
-  void Trace(JSTracer *aTracer) {
-    FORWARD_OPERATION(Trace, (aTracer));
-  }
-
-  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
-    size_t n = aMallocSizeOf(this);
-    n += (mKind == WindowLike
-          ? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
-          : mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
-    return n;
-  }
-#undef FORWARD_OPERATION
-
-private:
-  union {
-    ArrayCache *mArrayCache;
-    PageTableCache *mPageTableCache;
-  };
-  Kind mKind;
-};
-
-inline void
-AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
-{
-  MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
-  MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
-
-  ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
-
-  js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
-                      JS::PrivateValue(protoAndIfaceCache));
-}
-
-#ifdef DEBUG
-struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
-{
-  bool ok;
-
-  explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext* cx)
-    : JS::CallbackTracer(cx), ok(false)
-  {}
-
-  void onChild(const JS::GCCellPtr&) override {
-    // We don't do anything here, we only want to verify that
-    // TraceProtoAndIfaceCache was called.
-  }
-
-  TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
-};
-#endif
-
-inline void
-TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
-{
-  MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
-
-#ifdef DEBUG
-  if (trc->isCallbackTracer() &&
-      (trc->asCallbackTracer()->getTracerKind() ==
-       JS::CallbackTracer::TracerKind::VerifyTraceProtoAndIface)) {
-    // We don't do anything here, we only want to verify that
-    // TraceProtoAndIfaceCache was called.
-    static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
-    return;
-  }
-#endif
-
-  if (!DOMGlobalHasProtoAndIFaceCache(obj))
-    return;
-  ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
-  protoAndIfaceCache->Trace(trc);
-}
-
-inline void
-DestroyProtoAndIfaceCache(JSObject* obj)
-{
-  MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
-
-  if (!DOMGlobalHasProtoAndIFaceCache(obj)) {
-    return;
-  }
-
-  ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
-
-  delete protoAndIfaceCache;
-}
-
-/**
- * Add constants to an object.
- */
-bool
-DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
-                const ConstantSpec* cs);
-
-struct JSNativeHolder
-{
-  JSNative mNative;
-  const NativePropertyHooks* mPropertyHooks;
-};
-
-struct NamedConstructor
-{
-  const char* mName;
-  const JSNativeHolder mHolder;
-  unsigned mNargs;
-};
-
-/*
- * Create a DOM interface object (if constructorClass is non-null) and/or a
- * DOM interface prototype object (if protoClass is non-null).
- *
- * global is used as the parent of the interface object and the interface
- *        prototype object
- * protoProto is the prototype to use for the interface prototype object.
- * interfaceProto is the prototype to use for the interface object.  This can be
- *                null if both constructorClass and constructor are null (as in,
- *                if we're not creating an interface object at all).
- * protoClass is the JSClass to use for the interface prototype object.
- *            This is null if we should not create an interface prototype
- *            object.
- * protoCache a pointer to a JSObject pointer where we should cache the
- *            interface prototype object. This must be null if protoClass is and
- *            vice versa.
- * constructorClass is the JSClass to use for the interface object.
- *                  This is null if we should not create an interface object or
- *                  if it should be a function object.
- * constructor holds the JSNative to back the interface object which should be a
- *             Function, unless constructorClass is non-null in which case it is
- *             ignored. If this is null and constructorClass is also null then
- *             we should not create an interface object at all.
- * ctorNargs is the length of the constructor function; 0 if no constructor
- * constructorCache a pointer to a JSObject pointer where we should cache the
- *                  interface object. This must be null if both constructorClass
- *                  and constructor are null, and non-null otherwise.
- * properties contains the methods, attributes and constants to be defined on
- *            objects in any compartment.
- * chromeProperties contains the methods, attributes and constants to be defined
- *                  on objects in chrome compartments. This must be null if the
- *                  interface doesn't have any ChromeOnly properties or if the
- *                  object is being created in non-chrome compartment.
- * defineOnGlobal controls whether properties should be defined on the given
- *                global for the interface object (if any) and named
- *                constructors (if any) for this interface.  This can be
- *                false in situations where we want the properties to only
- *                appear on privileged Xrays but not on the unprivileged
- *                underlying global.
- * unscopableNames if not null it points to a null-terminated list of const
- *                 char* names of the unscopable properties for this interface.
- * isGlobal if true, we're creating interface objects for a [Global] or
- *        [PrimaryGlobal] interface, and hence shouldn't define properties on
- *        the prototype object.
- *
- * At least one of protoClass, constructorClass or constructor should be
- * non-null. If constructorClass or constructor are non-null, the resulting
- * interface object will be defined on the given global with property name
- * |name|, which must also be non-null.
- */
-void
-CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
-                       JS::Handle<JSObject*> protoProto,
-                       const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
-                       JS::Handle<JSObject*> interfaceProto,
-                       const js::Class* constructorClass,
-                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
-                       JS::Heap<JSObject*>* constructorCache,
-                       const NativeProperties* regularProperties,
-                       const NativeProperties* chromeOnlyProperties,
-                       const char* name, bool defineOnGlobal,
-                       const char* const* unscopableNames,
-                       bool isGlobal);
-
-/**
- * Define the properties (regular and chrome-only) on obj.
- *
- * obj the object to instal the properties on. This should be the interface
- *     prototype object for regular interfaces and the instance object for
- *     interfaces marked with Global.
- * properties contains the methods, attributes and constants to be defined on
- *            objects in any compartment.
- * chromeProperties contains the methods, attributes and constants to be defined
- *                  on objects in chrome compartments. This must be null if the
- *                  interface doesn't have any ChromeOnly properties or if the
- *                  object is being created in non-chrome compartment.
- */
-bool
-DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
-                 const NativeProperties* properties,
-                 const NativeProperties* chromeOnlyProperties);
-
-/*
- * Define the unforgeable methods on an object.
- */
-bool
-DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
-                         const Prefable<const JSFunctionSpec>* props);
-
-/*
- * Define the unforgeable attributes on an object.
- */
-bool
-DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
-                            const Prefable<const JSPropertySpec>* props);
-
-#define HAS_MEMBER_TYPEDEFS                                               \
-private:                                                                  \
-  typedef char yes[1];                                                    \
-  typedef char no[2]
-
-#ifdef _MSC_VER
-#define HAS_MEMBER_CHECK(_name)                                           \
-  template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
-#else
-#define HAS_MEMBER_CHECK(_name)                                           \
-  template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
-#endif
-
-#define HAS_MEMBER(_memberName, _valueName)                               \
-private:                                                                  \
-  HAS_MEMBER_CHECK(_memberName);                                          \
-  template<typename V> static no& Check##_memberName(...);                \
-                                                                          \
-public:                                                                   \
-  static bool const _valueName =                                          \
-    sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
-
-template<class T>
-struct NativeHasMember
-{
-  HAS_MEMBER_TYPEDEFS;
-
-  HAS_MEMBER(GetParentObject, GetParentObject);
-  HAS_MEMBER(WrapObject, WrapObject);
-};
-
-template<class T>
-struct IsSmartPtr
-{
-  HAS_MEMBER_TYPEDEFS;
-
-  HAS_MEMBER(get, value);
-};
-
-template<class T>
-struct IsRefcounted
-{
-  HAS_MEMBER_TYPEDEFS;
-
-  HAS_MEMBER(AddRef, HasAddref);
-  HAS_MEMBER(Release, HasRelease);
-
-public:
-  static bool const value = HasAddref && HasRelease;
-
-private:
-  // This struct only works if T is fully declared (not just forward declared).
-  // The IsBaseOf check will ensure that, we don't really need it for any other
-  // reason (the static assert will of course always be true).
-  static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
-                "Classes derived from nsISupports are refcounted!");
-
-};
-
-#undef HAS_MEMBER
-#undef HAS_MEMBER_CHECK
-#undef HAS_MEMBER_TYPEDEFS
-
-#ifdef DEBUG
-template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct
-CheckWrapperCacheCast
-{
-  static bool Check()
-  {
-    return reinterpret_cast<uintptr_t>(
-      static_cast<nsWrapperCache*>(
-        reinterpret_cast<T*>(1))) == 1;
-  }
-};
-template <class T>
-struct
-CheckWrapperCacheCast<T, true>
-{
-  static bool Check()
-  {
-    return true;
-  }
-};
-#endif
-
-MOZ_ALWAYS_INLINE bool
-CouldBeDOMBinding(void*)
-{
-  return true;
-}
-
-MOZ_ALWAYS_INLINE bool
-CouldBeDOMBinding(nsWrapperCache* aCache)
-{
-  return aCache->IsDOMBinding();
-}
-
-inline bool
-TryToOuterize(JS::MutableHandle<JS::Value> rval)
-{
-  if (js::IsWindow(&rval.toObject())) {
-    JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
-    MOZ_ASSERT(obj);
-    rval.set(JS::ObjectValue(*obj));
-  }
-
-  return true;
-}
-
-// Make sure to wrap the given string value into the right compartment, as
-// needed.
-MOZ_ALWAYS_INLINE
-bool
-MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(rval.isString());
-  JSString* str = rval.toString();
-  if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
-    return JS_WrapValue(cx, rval);
-  }
-  return true;
-}
-
-// Make sure to wrap the given object value into the right compartment as
-// needed.  This will work correctly, but possibly slowly, on all objects.
-MOZ_ALWAYS_INLINE
-bool
-MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(rval.isObject());
-
-  // Cross-compartment always requires wrapping.
-  JSObject* obj = &rval.toObject();
-  if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
-    return JS_WrapValue(cx, rval);
-  }
-
-  // We're same-compartment, but even then we might need to wrap
-  // objects specially.  Check for that.
-  if (IsDOMObject(obj)) {
-    return TryToOuterize(rval);
-  }
-
-  // It's not a WebIDL object.  But it might be an XPConnect one, in which case
-  // we may need to outerize here, so make sure to call JS_WrapValue.
-  return JS_WrapValue(cx, rval);
-}
-
-// Like MaybeWrapObjectValue, but also allows null
-MOZ_ALWAYS_INLINE
-bool
-MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(rval.isObjectOrNull());
-  if (rval.isNull()) {
-    return true;
-  }
-  return MaybeWrapObjectValue(cx, rval);
-}
-
-// Wrapping for objects that are known to not be DOM or XPConnect objects
-MOZ_ALWAYS_INLINE
-bool
-MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(rval.isObject());
-  MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
-  MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
-               JSCLASS_PRIVATE_IS_NSISUPPORTS));
-
-  JSObject* obj = &rval.toObject();
-  if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
-    return true;
-  }
-  return JS_WrapValue(cx, rval);
-}
-
-// Like MaybeWrapNonDOMObjectValue but allows null
-MOZ_ALWAYS_INLINE
-bool
-MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(rval.isObjectOrNull());
-  if (rval.isNull()) {
-    return true;
-  }
-  return MaybeWrapNonDOMObjectValue(cx, rval);
-}
-
-// If rval is a gcthing and is not in the compartment of cx, wrap rval
-// into the compartment of cx (typically by replacing it with an Xray or
-// cross-compartment wrapper around the original object).
-MOZ_ALWAYS_INLINE bool
-MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
-{
-  if (rval.isString()) {
-    return MaybeWrapStringValue(cx, rval);
-  }
-
-  if (!rval.isObject()) {
-    return true;
-  }
-
-  return MaybeWrapObjectValue(cx, rval);
-}
-
 namespace binding_detail {
-enum GetOrCreateReflectorWrapBehavior {
-  eWrapIntoContextCompartment,
-  eDontWrapIntoContextCompartment
-};
-
-template <class T>
-struct TypeNeedsOuterization
-{
-  // We only need to outerize Window objects, so anything inheriting from
-  // nsGlobalWindow (which inherits from EventTarget itself).
-  static const bool value =
-    IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value;
-};
-
-#ifdef DEBUG
-template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct CheckWrapperCacheTracing
-{
-  static inline void Check(T* aObject)
-  {
-  }
-};
-
-template<typename T>
-struct CheckWrapperCacheTracing<T, true>
-{
-  static void Check(T* aObject)
-  {
-    // Rooting analysis thinks QueryInterface may GC, but we're dealing with
-    // a subset of QueryInterface, C++ only types here.
-    JS::AutoSuppressGCAnalysis nogc;
-
-    nsWrapperCache* wrapperCacheFromQI = nullptr;
-    aObject->QueryInterface(NS_GET_IID(nsWrapperCache),
-                            reinterpret_cast<void**>(&wrapperCacheFromQI));
-
-    MOZ_ASSERT(wrapperCacheFromQI,
-               "Missing nsWrapperCache from QueryInterface implementation?");
-
-    if (!wrapperCacheFromQI->GetWrapperPreserveColor()) {
-      // Can't assert that we trace the wrapper, since we don't have any
-      // wrapper to trace.
-      return;
-    }
-
-    nsISupports* ccISupports = nullptr;
-    aObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
-                            reinterpret_cast<void**>(&ccISupports));
-    MOZ_ASSERT(ccISupports,
-               "nsWrapperCache object which isn't cycle collectable?");
-
-    nsXPCOMCycleCollectionParticipant* participant = nullptr;
-    CallQueryInterface(ccISupports, &participant);
-    MOZ_ASSERT(participant, "Can't QI to CycleCollectionParticipant?");
-
-    bool wasPreservingWrapper = wrapperCacheFromQI->PreservingWrapper();
-    wrapperCacheFromQI->SetPreservingWrapper(true);
-    wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant);
-    wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper);
-  }
-};
-
-void
-AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
-                             JS::Handle<JSObject*> aGivenProto);
-#endif // DEBUG
-
-template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
-MOZ_ALWAYS_INLINE bool
-DoGetOrCreateDOMReflector(JSContext* cx, T* value,
-                          JS::Handle<JSObject*> givenProto,
-                          JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(value);
-  // We can get rid of this when we remove support for hasXPConnectImpls.
-  bool couldBeDOMBinding = CouldBeDOMBinding(value);
-  JSObject* obj = value->GetWrapper();
-  if (obj) {
-#ifdef DEBUG
-    AssertReflectorHasGivenProto(cx, obj, givenProto);
-    // Have to reget obj because AssertReflectorHasGivenProto can
-    // trigger gc so the pointer may now be invalid.
-    obj = value->GetWrapper();
-#endif
-  } else {
-    // Inline this here while we have non-dom objects in wrapper caches.
-    if (!couldBeDOMBinding) {
-      return false;
-    }
-
-    obj = value->WrapObject(cx, givenProto);
-    if (!obj) {
-      // At this point, obj is null, so just return false.
-      // Callers seem to be testing JS_IsExceptionPending(cx) to
-      // figure out whether WrapObject() threw.
-      return false;
-    }
-
-#ifdef DEBUG
-    if (IsBaseOf<nsWrapperCache, T>::value) {
-      CheckWrapperCacheTracing<T>::Check(value);
-    }
-#endif
-  }
-
-#ifdef DEBUG
-  const DOMJSClass* clasp = GetDOMClass(obj);
-  // clasp can be null if the cache contained a non-DOM object.
-  if (clasp) {
-    // Some sanity asserts about our object.  Specifically:
-    // 1)  If our class claims we're nsISupports, we better be nsISupports
-    //     XXXbz ideally, we could assert that reinterpret_cast to nsISupports
-    //     does the right thing, but I don't see a way to do it.  :(
-    // 2)  If our class doesn't claim we're nsISupports we better be
-    //     reinterpret_castable to nsWrapperCache.
-    MOZ_ASSERT(clasp, "What happened here?");
-    MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
-    MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
-  }
-#endif
-
-  rval.set(JS::ObjectValue(*obj));
-
-  bool sameCompartment =
-    js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
-  if (sameCompartment && couldBeDOMBinding) {
-    return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true;
-  }
-
-  if (wrapBehavior == eDontWrapIntoContextCompartment) {
-    if (TypeNeedsOuterization<T>::value) {
-      JSAutoCompartment ac(cx, obj);
-      return TryToOuterize(rval);
-    }
-
-    return true;
-  }
-
-  return JS_WrapValue(cx, rval);
-}
-
-} // namespace binding_detail
-
-// Create a JSObject wrapping "value", if there isn't one already, and store it
-// in rval.  "value" must be a concrete class that implements a
-// GetWrapperPreserveColor() which can return its existing wrapper, if any, and
-// a WrapObject() which will try to create a wrapper. Typically, this is done by
-// having "value" inherit from nsWrapperCache.
-//
-// The value stored in rval will be ready to be exposed to whatever JS
-// is running on cx right now.  In particular, it will be in the
-// compartment of cx, and outerized as needed.
-template <class T>
-MOZ_ALWAYS_INLINE bool
-GetOrCreateDOMReflector(JSContext* cx, T* value,
-                        JS::MutableHandle<JS::Value> rval,
-                        JS::Handle<JSObject*> givenProto = nullptr)
-{
-  using namespace binding_detail;
-  return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
-                                                                   givenProto,
-                                                                   rval);
-}
-
-// Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
-// and hence does not actually require cx to be in a compartment.
-template <class T>
-MOZ_ALWAYS_INLINE bool
-GetOrCreateDOMReflectorNoWrap(JSContext* cx, T* value,
-                              JS::MutableHandle<JS::Value> rval)
-{
-  using namespace binding_detail;
-  return DoGetOrCreateDOMReflector<T, eDontWrapIntoContextCompartment>(cx,
-                                                                       value,
-                                                                       nullptr,
-                                                                       rval);
-}
-
-// Create a JSObject wrapping "value", for cases when "value" is a
-// non-wrapper-cached object using WebIDL bindings.  "value" must implement a
-// WrapObject() method taking a JSContext and a scope.
-template <class T>
-inline bool
-WrapNewBindingNonWrapperCachedObject(JSContext* cx,
-                                     JS::Handle<JSObject*> scopeArg,
-                                     T* value,
-                                     JS::MutableHandle<JS::Value> rval,
-                                     JS::Handle<JSObject*> givenProto = nullptr)
-{
-  static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
-  MOZ_ASSERT(value);
-  // We try to wrap in the compartment of the underlying object of "scope"
-  JS::Rooted<JSObject*> obj(cx);
-  {
-    // scope for the JSAutoCompartment so that we restore the compartment
-    // before we call JS_WrapValue.
-    Maybe<JSAutoCompartment> ac;
-    // Maybe<Handle> doesn't so much work, and in any case, adding
-    // more Maybe (one for a Rooted and one for a Handle) adds more
-    // code (and branches!) than just adding a single rooted.
-    JS::Rooted<JSObject*> scope(cx, scopeArg);
-    JS::Rooted<JSObject*> proto(cx, givenProto);
-    if (js::IsWrapper(scope)) {
-      scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
-      if (!scope)
-        return false;
-      ac.emplace(cx, scope);
-      if (!JS_WrapObject(cx, &proto)) {
-        return false;
-      }
-    }
-
-    MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
-    if (!value->WrapObject(cx, proto, &obj)) {
-      return false;
-    }
-  }
-
-  // We can end up here in all sorts of compartments, per above.  Make
-  // sure to JS_WrapValue!
-  rval.set(JS::ObjectValue(*obj));
-  return MaybeWrapObjectValue(cx, rval);
-}
-
-// Create a JSObject wrapping "value", for cases when "value" is a
-// non-wrapper-cached owned object using WebIDL bindings.  "value" must implement a
-// WrapObject() method taking a JSContext, a scope, and a boolean outparam that
-// is true if the JSObject took ownership
-template <class T>
-inline bool
-WrapNewBindingNonWrapperCachedObject(JSContext* cx,
-                                     JS::Handle<JSObject*> scopeArg,
-                                     nsAutoPtr<T>& value,
-                                     JS::MutableHandle<JS::Value> rval,
-                                     JS::Handle<JSObject*> givenProto = nullptr)
-{
-  static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
-  // We do a runtime check on value, because otherwise we might in
-  // fact end up wrapping a null and invoking methods on it later.
-  if (!value) {
-    NS_RUNTIMEABORT("Don't try to wrap null objects");
-  }
-  // We try to wrap in the compartment of the underlying object of "scope"
-  JS::Rooted<JSObject*> obj(cx);
-  {
-    // scope for the JSAutoCompartment so that we restore the compartment
-    // before we call JS_WrapValue.
-    Maybe<JSAutoCompartment> ac;
-    // Maybe<Handle> doesn't so much work, and in any case, adding
-    // more Maybe (one for a Rooted and one for a Handle) adds more
-    // code (and branches!) than just adding a single rooted.
-    JS::Rooted<JSObject*> scope(cx, scopeArg);
-    JS::Rooted<JSObject*> proto(cx, givenProto);
-    if (js::IsWrapper(scope)) {
-      scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
-      if (!scope)
-        return false;
-      ac.emplace(cx, scope);
-      if (!JS_WrapObject(cx, &proto)) {
-        return false;
-      }
-    }
-
-    MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
-    if (!value->WrapObject(cx, proto, &obj)) {
-      return false;
-    }
-
-    value.forget();
-  }
-
-  // We can end up here in all sorts of compartments, per above.  Make
-  // sure to JS_WrapValue!
-  rval.set(JS::ObjectValue(*obj));
-  return MaybeWrapObjectValue(cx, rval);
-}
-
-// Helper for smart pointers (nsRefPtr/nsCOMPtr).
-template <template <typename> class SmartPtr, typename T,
-          typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type,
-          typename V=typename EnableIf<IsSmartPtr<SmartPtr<T>>::value, T>::Type>
-inline bool
-WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
-                                     const SmartPtr<T>& value,
-                                     JS::MutableHandle<JS::Value> rval,
-                                     JS::Handle<JSObject*> givenProto = nullptr)
-{
-  return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval,
-                                              givenProto);
-}
-
-// Helper for object references (as opposed to pointers).
-template <typename T,
-          typename U=typename EnableIf<!IsSmartPtr<T>::value, T>::Type>
-inline bool
-WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
-                                     T& value,
-                                     JS::MutableHandle<JS::Value> rval,
-                                     JS::Handle<JSObject*> givenProto = nullptr)
-{
-  return WrapNewBindingNonWrapperCachedObject(cx, scope, &value, rval,
-                                              givenProto);
-}
-
-// Only set allowNativeWrapper to false if you really know you need it, if in
-// doubt use true. Setting it to false disables security wrappers.
-bool
-NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
-                                         JS::Handle<JSObject*> aScope,
-                                         JS::MutableHandle<JS::Value> aRetval,
-                                         xpcObjectHelper& aHelper,
-                                         const nsIID* aIID,
-                                         bool aAllowNativeWrapper);
-
-/**
- * A method to handle new-binding wrap failure, by possibly falling back to
- * wrapping as a non-new-binding object.
- */
-template <class T>
-MOZ_ALWAYS_INLINE bool
-HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
-                                T* value, JS::MutableHandle<JS::Value> rval)
-{
-  if (JS_IsExceptionPending(cx)) {
-    return false;
-  }
-
-  qsObjectHelper helper(value, GetWrapperCache(value));
-  return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
-                                                  helper, nullptr, true);
-}
-
-// Helper for calling HandleNewBindingWrappingFailure with smart pointers
-// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
-
-template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
-struct HandleNewBindingWrappingFailureHelper
-{
-  static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
-                          const T& value, JS::MutableHandle<JS::Value> rval)
-  {
-    return HandleNewBindingWrappingFailure(cx, scope, value.get(), rval);
-  }
-};
-
-template <class T>
-struct HandleNewBindingWrappingFailureHelper<T, false>
-{
-  static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
-                          JS::MutableHandle<JS::Value> rval)
-  {
-    return HandleNewBindingWrappingFailure(cx, scope, &value, rval);
-  }
-};
-
-template<class T>
-inline bool
-HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
-                                T& value, JS::MutableHandle<JS::Value> rval)
-{
-  return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
-}
-
-template<bool Fatal>
-inline bool
-EnumValueNotFound(JSContext* cx, JSString* str, const char* type,
-                  const char* sourceDescription)
-{
-  return false;
-}
-
-template<>
-inline bool
-EnumValueNotFound<false>(JSContext* cx, JSString* str, const char* type,
-                         const char* sourceDescription)
-{
-  // TODO: Log a warning to the console.
-  return true;
-}
-
-template<>
-inline bool
-EnumValueNotFound<true>(JSContext* cx, JSString* str, const char* type,
-                        const char* sourceDescription)
-{
-  JSAutoByteString deflated(cx, str);
-  if (!deflated) {
-    return false;
-  }
-  return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
-                           deflated.ptr(), type);
-}
-
-template<typename CharT>
-inline int
-FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
-{
-  int i = 0;
-  for (const EnumEntry* value = values; value->value; ++value, ++i) {
-    if (length != value->length) {
-      continue;
-    }
-
-    bool equal = true;
-    const char* val = value->value;
-    for (size_t j = 0; j != length; ++j) {
-      if (unsigned(val[j]) != unsigned(chars[j])) {
-        equal = false;
-        break;
-      }
-    }
-
-    if (equal) {
-      return i;
-    }
-  }
-
-  return -1;
-}
-
-template<bool InvalidValueFatal>
-inline int
-FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
-                    const char* type, const char* sourceDescription, bool* ok)
-{
-  // JS_StringEqualsAscii is slow as molasses, so don't use it here.
-  JSString* str = JS::ToString(cx, v);
-  if (!str) {
-    *ok = false;
-    return 0;
-  }
-
-  {
-    int index;
-    size_t length;
-    JS::AutoCheckCannotGC nogc;
-    if (js::StringHasLatin1Chars(str)) {
-      const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
-                                                                     &length);
-      if (!chars) {
-        *ok = false;
-        return 0;
-      }
-      index = FindEnumStringIndexImpl(chars, length, values);
-    } else {
-      const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
-                                                                &length);
-      if (!chars) {
-        *ok = false;
-        return 0;
-      }
-      index = FindEnumStringIndexImpl(chars, length, values);
-    }
-    if (index >= 0) {
-      *ok = true;
-      return index;
-    }
-  }
-
-  *ok = EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
-  return -1;
-}
-
-inline nsWrapperCache*
-GetWrapperCache(const ParentObject& aParentObject)
-{
-  return aParentObject.mWrapperCache;
-}
-
-template<class T>
-inline T*
-GetParentPointer(T* aObject)
-{
-  return aObject;
-}
-
-inline nsISupports*
-GetParentPointer(const ParentObject& aObject)
-{
-  return aObject.mObject;
-}
-
-template <typename T>
-inline bool
-GetUseXBLScope(T* aParentObject)
-{
-  return false;
-}
-
-inline bool
-GetUseXBLScope(const ParentObject& aParentObject)
-{
-  return aParentObject.mUseXBLScope;
-}
-
-template<class T>
-inline void
-ClearWrapper(T* p, nsWrapperCache* cache)
-{
-  cache->ClearWrapper();
-}
-
-template<class T>
-inline void
-ClearWrapper(T* p, void*)
-{
-  nsWrapperCache* cache;
-  CallQueryInterface(p, &cache);
-  ClearWrapper(p, cache);
-}
-
-template<class T>
-inline void
-UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
-{
-  JS::AutoAssertGCCallback inCallback(obj);
-  cache->UpdateWrapper(obj, old);
-}
-
-template<class T>
-inline void
-UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
-{
-  JS::AutoAssertGCCallback inCallback(obj);
-  nsWrapperCache* cache;
-  CallQueryInterface(p, &cache);
-  UpdateWrapper(p, cache, obj, old);
-}
-
-// Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
-// Return true if we successfully preserved the wrapper, or there is no wrapper
-// to preserve. In the latter case we don't need to preserve the wrapper, because
-// the object can only be obtained by JS once, or they cannot be meaningfully
-// owned from the native side.
-//
-// This operation will return false only for non-nsISupports cycle-collected
-// objects, because we cannot determine if they are wrappercached or not.
-bool
-TryPreserveWrapper(JSObject* obj);
-
-// Can only be called with a DOM JSClass.
-bool
-InstanceClassHasProtoAtDepth(const js::Class* clasp,
-                             uint32_t protoID, uint32_t depth);
-
-// Only set allowNativeWrapper to false if you really know you need it, if in
-// doubt use true. Setting it to false disables security wrappers.
-bool
-XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
-                   xpcObjectHelper& helper, const nsIID* iid,
-                   bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
-
-// Special-cased wrapping for variants
-bool
-VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
-               JS::MutableHandle<JS::Value> aRetval);
-
-// Wrap an object "p" which is not using WebIDL bindings yet.  This _will_
-// actually work on WebIDL binding objects that are wrappercached, but will be
-// much slower than GetOrCreateDOMReflector.  "cache" must either be null or be
-// the nsWrapperCache for "p".
-template<class T>
-inline bool
-WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
-           JS::MutableHandle<JS::Value> rval)
-{
-  if (xpc_FastGetCachedWrapper(cx, cache, rval))
-    return true;
-  qsObjectHelper helper(p, cache);
-  JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
-  return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
-}
-
-// A specialization of the above for nsIVariant, because that needs to
-// do something different.
-template<>
-inline bool
-WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
-                       nsWrapperCache* cache, const nsIID* iid,
-                       JS::MutableHandle<JS::Value> rval)
-{
-  MOZ_ASSERT(iid);
-  MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
-  return VariantToJsval(cx, p, rval);
-}
-
-// Wrap an object "p" which is not using WebIDL bindings yet.  Just like the
-// variant that takes an nsWrapperCache above, but will try to auto-derive the
-// nsWrapperCache* from "p".
-template<class T>
-inline bool
-WrapObject(JSContext* cx, T* p, const nsIID* iid,
-           JS::MutableHandle<JS::Value> rval)
-{
-  return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
-}
-
-// Just like the WrapObject above, but without requiring you to pick which
-// interface you're wrapping as.  This should only be used for objects that have
-// classinfo, for which it doesn't matter what IID is used to wrap.
-template<class T>
-inline bool
-WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
-{
-  return WrapObject(cx, p, nullptr, rval);
-}
-
-// Helper to make it possible to wrap directly out of an nsCOMPtr
-template<class T>
-inline bool
-WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
-           const nsIID* iid, JS::MutableHandle<JS::Value> rval)
-{
-  return WrapObject(cx, p.get(), iid, rval);
-}
-
-// Helper to make it possible to wrap directly out of an nsCOMPtr
-template<class T>
-inline bool
-WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
-           JS::MutableHandle<JS::Value> rval)
-{
-  return WrapObject(cx, p, nullptr, rval);
-}
-
-// Helper to make it possible to wrap directly out of an nsRefPtr
-template<class T>
-inline bool
-WrapObject(JSContext* cx, const RefPtr<T>& p,
-           const nsIID* iid, JS::MutableHandle<JS::Value> rval)
-{
-  return WrapObject(cx, p.get(), iid, rval);
-}
-
-// Helper to make it possible to wrap directly out of an nsRefPtr
-template<class T>
-inline bool
-WrapObject(JSContext* cx, const RefPtr<T>& p,
-           JS::MutableHandle<JS::Value> rval)
-{
-  return WrapObject(cx, p, nullptr, rval);
-}
-
-// Specialization to make it easy to use WrapObject in codegen.
-template<>
-inline bool
-WrapObject<JSObject>(JSContext* cx, JSObject* p,
-                     JS::MutableHandle<JS::Value> rval)
-{
-  rval.set(JS::ObjectOrNullValue(p));
-  return true;
-}
-
-inline bool
-WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
-{
-  rval.set(JS::ObjectValue(p));
-  return true;
-}
-
-// Given an object "p" that inherits from nsISupports, wrap it and return the
-// result.  Null is returned on wrapping failure.  This is somewhat similar to
-// WrapObject() above, but does NOT allow Xrays around the result, since we
-// don't want those for our parent object.
-template<typename T>
-static inline JSObject*
-WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
-{
-  qsObjectHelper helper(ToSupports(p), cache);
-  JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
-  JS::Rooted<JS::Value> v(cx);
-  return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
-         v.toObjectOrNull() :
-         nullptr;
-}
-
-
-// Fallback for when our parent is not a WebIDL binding object.
-template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct WrapNativeFallback
-{
-  static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
-  {
-    return nullptr;
-  }
-};
-
-// Fallback for when our parent is not a WebIDL binding object but _is_ an
-// nsISupports object.
-template<typename T >
-struct WrapNativeFallback<T, true >
-{
-  static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
-  {
-    return WrapNativeISupports(cx, parent, cache);
-  }
-};
-
-// Wrapping of our native parent, for cases when it's a WebIDL object (though
-// possibly preffed off).
-template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
-struct WrapNativeHelper
-{
-  static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
-  {
-    MOZ_ASSERT(cache);
-
-    JSObject* obj;
-    if ((obj = cache->GetWrapper())) {
-      // GetWrapper always unmarks gray.
-      MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
-      return obj;
-    }
-
-    // Inline this here while we have non-dom objects in wrapper caches.
-    if (!CouldBeDOMBinding(parent)) {
-      // WrapNativeFallback never returns a gray thing.
-      obj = WrapNativeFallback<T>::Wrap(cx, parent, cache);
-      MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
-    } else {
-      // WrapObject never returns a gray thing.
-      obj = parent->WrapObject(cx, nullptr);
-      MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
-    }
-
-    return obj;
-  }
-};
-
-// Wrapping of our native parent, for cases when it's not a WebIDL object.  In
-// this case it must be nsISupports.
-template<typename T>
-struct WrapNativeHelper<T, false>
-{
-  static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
-  {
-    JSObject* obj;
-    if (cache && (obj = cache->GetWrapper())) {
-#ifdef DEBUG
-      JS::Rooted<JSObject*> rootedObj(cx, obj);
-      NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
-                   "Unexpected object in nsWrapperCache");
-      obj = rootedObj;
-#endif
-      MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
-      return obj;
-    }
-
-    obj = WrapNativeISupports(cx, parent, cache);
-    MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
-    return obj;
-  }
-};
-
-// Finding the associated global for an object.
-template<typename T>
-static inline JSObject*
-FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
-                     bool useXBLScope = false)
-{
-  if (!p) {
-    return JS::CurrentGlobalOrNull(cx);
-  }
-
-  JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
-  if (!obj) {
-    return nullptr;
-  }
-  MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
-
-  obj = js::GetGlobalForObjectCrossCompartment(obj);
-
-  if (!useXBLScope) {
-    return obj;
-  }
-
-  // If useXBLScope is true, it means that the canonical reflector for this
-  // native object should live in the content XBL scope. Note that we never put
-  // anonymous content inside an add-on scope.
-  if (xpc::IsInContentXBLScope(obj)) {
-    return obj;
-  }
-  JS::Rooted<JSObject*> rootedObj(cx, obj);
-  JSObject* xblScope = xpc::GetXBLScope(cx, rootedObj);
-  MOZ_ASSERT_IF(xblScope, JS_IsGlobalObject(xblScope));
-  MOZ_ASSERT_IF(xblScope, !JS::ObjectIsMarkedGray(xblScope));
-  return xblScope;
-}
-
-// Finding of the associated global for an object, when we don't want to
-// explicitly pass in things like the nsWrapperCache for it.
-template<typename T>
-static inline JSObject*
-FindAssociatedGlobal(JSContext* cx, const T& p)
-{
-  return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
-}
-
-// Specialization for the case of nsIGlobalObject, since in that case
-// we can just get the JSObject* directly.
-template<>
-inline JSObject*
-FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
-{
-  if (!p) {
-    return JS::CurrentGlobalOrNull(cx);
-  }
-
-  JSObject* global = p->GetGlobalJSObject();
-  if (!global) {
-    return nullptr;
-  }
-
-  MOZ_ASSERT(JS_IsGlobalObject(global));
-  // This object could be gray if the nsIGlobalObject is the only thing keeping
-  // it alive.
-  JS::ExposeObjectToActiveJS(global);
-  return global;
-}
-
-template<typename T,
-         bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
-struct FindAssociatedGlobalForNative
-{
-  static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
-  {
-    MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
-    T* native = UnwrapDOMObject<T>(obj);
-    return FindAssociatedGlobal(cx, native->GetParentObject());
-  }
-};
-
-template<typename T>
-struct FindAssociatedGlobalForNative<T, false>
-{
-  static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
-  {
-    MOZ_CRASH();
-    return nullptr;
-  }
-};
-
-// Helper for calling GetOrCreateDOMReflector with smart pointers
-// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
-template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
-struct GetOrCreateDOMReflectorHelper
-{
-  static inline bool GetOrCreate(JSContext* cx, const T& value,
-                                 JS::Handle<JSObject*> givenProto,
-                                 JS::MutableHandle<JS::Value> rval)
-  {
-    return GetOrCreateDOMReflector(cx, value.get(), rval, givenProto);
-  }
-};
-
-template <class T>
-struct GetOrCreateDOMReflectorHelper<T, false>
-{
-  static inline bool GetOrCreate(JSContext* cx, T& value,
-                                 JS::Handle<JSObject*> givenProto,
-                                 JS::MutableHandle<JS::Value> rval)
-  {
-    static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
-    return GetOrCreateDOMReflector(cx, &value, rval, givenProto);
-  }
-};
-
-template<class T>
-inline bool
-GetOrCreateDOMReflector(JSContext* cx, T& value,
-                        JS::MutableHandle<JS::Value> rval,
-                        JS::Handle<JSObject*> givenProto = nullptr)
-{
-  return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, givenProto,
-                                                       rval);
-}
-
-// Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
-// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
-template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
-struct GetOrCreateDOMReflectorNoWrapHelper
-{
-  static inline bool GetOrCreate(JSContext* cx, const T& value,
-                                 JS::MutableHandle<JS::Value> rval)
-  {
-    return GetOrCreateDOMReflectorNoWrap(cx, value.get(), rval);
-  }
-};
-
-template <class T>
-struct GetOrCreateDOMReflectorNoWrapHelper<T, false>
-{
-  static inline bool GetOrCreate(JSContext* cx, T& value,
-                                 JS::MutableHandle<JS::Value> rval)
-  {
-    return GetOrCreateDOMReflectorNoWrap(cx, &value, rval);
-  }
-};
-
-template<class T>
-inline bool
-GetOrCreateDOMReflectorNoWrap(JSContext* cx, T& value,
-                              JS::MutableHandle<JS::Value> rval)
-{
-  return
-    GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
-}
-
-template <class T>
-inline JSObject*
-GetCallbackFromCallbackObject(T* aObj)
-{
-  return aObj->Callback();
-}
-
-// Helper for getting the callback JSObject* of a smart ptr around a
-// CallbackObject or a reference to a CallbackObject or something like
-// that.
-template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
-struct GetCallbackFromCallbackObjectHelper
-{
-  static inline JSObject* Get(const T& aObj)
-  {
-    return GetCallbackFromCallbackObject(aObj.get());
-  }
-};
-
-template <class T>
-struct GetCallbackFromCallbackObjectHelper<T, false>
-{
-  static inline JSObject* Get(T& aObj)
-  {
-    return GetCallbackFromCallbackObject(&aObj);
-  }
-};
-
-template<class T>
-inline JSObject*
-GetCallbackFromCallbackObject(T& aObj)
-{
-  return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
-}
-
-static inline bool
-AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
-{
-  if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
-    id = INTERNED_STRING_TO_JSID(cx, str);
-    return true;
-  }
-  return false;
-}
-
-// Spec needs a name property
-template <typename Spec>
-static bool
-InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
-{
-  MOZ_ASSERT(prefableSpecs);
-  MOZ_ASSERT(prefableSpecs->specs);
-  do {
-    // We ignore whether the set of ids is enabled and just intern all the IDs,
-    // because this is only done once per application runtime.
-    Spec* spec = prefableSpecs->specs;
-    do {
-      if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
-        return false;
-      }
-    } while (++ids, (++spec)->name);
-
-    // We ran out of ids for that pref.  Put a JSID_VOID in on the id
-    // corresponding to the list terminator for the pref.
-    *ids = JSID_VOID;
-    ++ids;
-  } while ((++prefableSpecs)->specs);
-
-  return true;
-}
-
-bool
-QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
-
-template <class T>
-struct
-WantsQueryInterface
-{
-  static_assert(IsBaseOf<nsISupports, T>::value,
-                "QueryInterface can't work without an nsISupports.");
-  static bool Enabled(JSContext* aCx, JSObject* aGlobal)
-  {
-    return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
-  }
-};
-
-void
-GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
-                 nsWrapperCache* aCache, nsIJSID* aIID,
-                 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
-
-template<class T>
-void
-GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
-             JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
-{
-  GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
-}
-
-bool
-UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-ThrowConstructorWithoutNew(JSContext* cx, const char* name);
-
-bool
-GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
-                       bool* found, JS::MutableHandle<JS::Value> vp);
-
-//
-bool
-HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::Handle<jsid> id, bool* has);
-
-
-// Append the property names in "names" to "props". If
-// shadowPrototypeProperties is false then skip properties that are also
-// present on the proto chain of proxy.  If shadowPrototypeProperties is true,
-// then the "proxy" argument is ignored.
-bool
-AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       nsTArray<nsString>& names,
-                       bool shadowPrototypeProperties, JS::AutoIdVector& props);
-
-namespace binding_detail {
-
 // A struct that has the same layout as an nsString but much faster
 // constructor and destructor behavior. FakeString uses inline storage
 // for small strings and a nsStringBuffer for longer strings.
 struct FakeString {
   FakeString() :
     mFlags(nsString::F_TERMINATED)
   {
   }
@@ -2034,1340 +148,13 @@ private:
                       offsetof(StringAsserter, mLength),
                     "Offset of mLength should match");
       static_assert(offsetof(FakeString, mFlags) ==
                       offsetof(StringAsserter, mFlags),
                     "Offset of mFlags should match");
     }
   };
 };
-
-class FastErrorResult :
-    public mozilla::binding_danger::TErrorResult<
-      mozilla::binding_danger::JustAssertCleanupPolicy>
-{
-};
-
 } // namespace binding_detail
-
-enum StringificationBehavior {
-  eStringify,
-  eEmpty,
-  eNull
-};
-
-template<typename T>
-static inline bool
-ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
-                       StringificationBehavior nullBehavior,
-                       StringificationBehavior undefinedBehavior,
-                       T& result)
-{
-  JSString *s;
-  if (v.isString()) {
-    s = v.toString();
-  } else {
-    StringificationBehavior behavior;
-    if (v.isNull()) {
-      behavior = nullBehavior;
-    } else if (v.isUndefined()) {
-      behavior = undefinedBehavior;
-    } else {
-      behavior = eStringify;
-    }
-
-    if (behavior != eStringify) {
-      if (behavior == eEmpty) {
-        result.Truncate();
-      } else {
-        result.SetIsVoid(true);
-      }
-      return true;
-    }
-
-    s = JS::ToString(cx, v);
-    if (!s) {
-      return false;
-    }
-  }
-
-  return AssignJSString(cx, result, s);
-}
-
-void
-NormalizeUSVString(JSContext* aCx, nsAString& aString);
-
-void
-NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString);
-
-template<typename T>
-inline bool
-ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
-{
-  if (MOZ_LIKELY(JSID_IS_STRING(id))) {
-    if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
-      return false;
-    }
-  } else if (JSID_IS_SYMBOL(id)) {
-    isSymbol = true;
-    return true;
-  } else {
-    JS::RootedValue nameVal(cx, js::IdToValue(id));
-    if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
-      return false;
-    }
-  }
-  isSymbol = false;
-  return true;
-}
-
-bool
-ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
-                           bool nullable, nsACString& result);
-
-template<typename T>
-void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
-template<typename T>
-void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
-
-// Class for simple sequence arguments, only used internally by codegen.
-namespace binding_detail {
-
-template<typename T>
-class AutoSequence : public AutoTArray<T, 16>
-{
-public:
-  AutoSequence() : AutoTArray<T, 16>()
-  {}
-
-  // Allow converting to const sequences as needed
-  operator const Sequence<T>&() const {
-    return *reinterpret_cast<const Sequence<T>*>(this);
-  }
-};
-
-} // namespace binding_detail
-
-// Class used to trace sequences, with specializations for various
-// sequence types.
-template<typename T,
-         bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
-         bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
-         bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
-class SequenceTracer
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-};
-
-// sequence<object> or sequence<object?>
-template<>
-class SequenceTracer<JSObject*, false, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
-    for (; objp != end; ++objp) {
-      JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
-    }
-  }
-};
-
-// sequence<any>
-template<>
-class SequenceTracer<JS::Value, false, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
-    for (; valp != end; ++valp) {
-      JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
-    }
-  }
-};
-
-// sequence<sequence<T>>
-template<typename T>
-class SequenceTracer<Sequence<T>, false, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
-    for (; seqp != end; ++seqp) {
-      DoTraceSequence(trc, *seqp);
-    }
-  }
-};
-
-// sequence<sequence<T>> as return value
-template<typename T>
-class SequenceTracer<nsTArray<T>, false, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
-    for (; seqp != end; ++seqp) {
-      DoTraceSequence(trc, *seqp);
-    }
-  }
-};
-
-// sequence<someDictionary>
-template<typename T>
-class SequenceTracer<T, true, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
-    for (; dictp != end; ++dictp) {
-      dictp->TraceDictionary(trc);
-    }
-  }
-};
-
-// sequence<SomeTypedArray>
-template<typename T>
-class SequenceTracer<T, false, true, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
-    for (; arrayp != end; ++arrayp) {
-      arrayp->TraceSelf(trc);
-    }
-  }
-};
-
-// sequence<SomeOwningUnion>
-template<typename T>
-class SequenceTracer<T, false, false, true>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
-    for (; arrayp != end; ++arrayp) {
-      arrayp->TraceUnion(trc);
-    }
-  }
-};
-
-// sequence<T?> with T? being a Nullable<T>
-template<typename T>
-class SequenceTracer<Nullable<T>, false, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
-                            Nullable<T>* end) {
-    for (; seqp != end; ++seqp) {
-      if (!seqp->IsNull()) {
-        // Pretend like we actually have a length-one sequence here so
-        // we can do template instantiation correctly for T.
-        T& val = seqp->Value();
-        T* ptr = &val;
-        SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
-      }
-    }
-  }
-};
-
-template<typename T>
-static void
-TraceMozMapValue(T* aValue, void* aClosure)
-{
-  JSTracer* trc = static_cast<JSTracer*>(aClosure);
-  // Act like it's a one-element sequence to leverage all that infrastructure.
-  SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1);
-}
-
-template<typename T>
-void TraceMozMap(JSTracer* trc, MozMap<T>& map)
-{
-  map.EnumerateValues(TraceMozMapValue<T>, trc);
-}
-
-// sequence<MozMap>
-template<typename T>
-class SequenceTracer<MozMap<T>, false, false, false>
-{
-  explicit SequenceTracer() = delete; // Should never be instantiated
-
-public:
-  static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) {
-    for (; seqp != end; ++seqp) {
-      seqp->EnumerateValues(TraceMozMapValue<T>, trc);
-    }
-  }
-};
-
-template<typename T>
-void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
-{
-  SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
-                                   seq.Elements() + seq.Length());
-}
-
-template<typename T>
-void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
-{
-  SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
-                                   seq.Elements() + seq.Length());
-}
-
-// Rooter class for sequences; this is what we mostly use in the codegen
-template<typename T>
-class MOZ_RAII SequenceRooter final : private JS::CustomAutoRooter
-{
-public:
-  SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
-                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
-      mFallibleArray(aSequence),
-      mSequenceType(eFallibleArray)
-  {
-  }
-
-  SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
-                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
-      mInfallibleArray(aSequence),
-      mSequenceType(eInfallibleArray)
-  {
-  }
-
-  SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
-                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
-      mNullableArray(aSequence),
-      mSequenceType(eNullableArray)
-  {
-  }
-
- private:
-  enum SequenceType {
-    eInfallibleArray,
-    eFallibleArray,
-    eNullableArray
-  };
-
-  virtual void trace(JSTracer *trc) override
-  {
-    if (mSequenceType == eFallibleArray) {
-      DoTraceSequence(trc, *mFallibleArray);
-    } else if (mSequenceType == eInfallibleArray) {
-      DoTraceSequence(trc, *mInfallibleArray);
-    } else {
-      MOZ_ASSERT(mSequenceType == eNullableArray);
-      if (!mNullableArray->IsNull()) {
-        DoTraceSequence(trc, mNullableArray->Value());
-      }
-    }
-  }
-
-  union {
-    InfallibleTArray<T>* mInfallibleArray;
-    FallibleTArray<T>* mFallibleArray;
-    Nullable<nsTArray<T> >* mNullableArray;
-  };
-
-  SequenceType mSequenceType;
-};
-
-// Rooter class for MozMap; this is what we mostly use in the codegen.
-template<typename T>
-class MOZ_RAII MozMapRooter final : private JS::CustomAutoRooter
-{
-public:
-  MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
-               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
-      mMozMap(aMozMap),
-      mMozMapType(eMozMap)
-  {
-  }
-
-  MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap
-                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
-      mNullableMozMap(aMozMap),
-      mMozMapType(eNullableMozMap)
-  {
-  }
-
-private:
-  enum MozMapType {
-    eMozMap,
-    eNullableMozMap
-  };
-
-  virtual void trace(JSTracer *trc) override
-  {
-    if (mMozMapType == eMozMap) {
-      TraceMozMap(trc, *mMozMap);
-    } else {
-      MOZ_ASSERT(mMozMapType == eNullableMozMap);
-      if (!mNullableMozMap->IsNull()) {
-        TraceMozMap(trc, mNullableMozMap->Value());
-      }
-    }
-  }
-
-  union {
-    MozMap<T>* mMozMap;
-    Nullable<MozMap<T>>* mNullableMozMap;
-  };
-
-  MozMapType mMozMapType;
-};
-
-template<typename T>
-class MOZ_RAII RootedUnion : public T,
-                             private JS::CustomAutoRooter
-{
-public:
-  explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
-    T(),
-    JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
-  {
-  }
-
-  virtual void trace(JSTracer *trc) override
-  {
-    this->TraceUnion(trc);
-  }
-};
-
-template<typename T>
-class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
-                                            private JS::CustomAutoRooter
-{
-public:
-  explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
-    Nullable<T>(),
-    JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
-  {
-  }
-
-  virtual void trace(JSTracer *trc) override
-  {
-    if (!this->IsNull()) {
-      this->Value().TraceUnion(trc);
-    }
-  }
-};
-
-inline bool
-IdEquals(jsid id, const char* string)
-{
-  return JSID_IS_STRING(id) &&
-         JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
-}
-
-inline bool
-AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
-{
-  return vector.growBy(1) &&
-         AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(), name);
-}
-
-// Implementation of the bits that XrayWrapper needs
-
-/**
- * This resolves operations, attributes and constants of the interfaces for obj.
- *
- * wrapper is the Xray JS object.
- * obj is the target object of the Xray, a binding's instance object or a
- *     interface or interface prototype object.
- */
-bool
-XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                       JS::Handle<JSObject*> obj,
-                       JS::Handle<jsid> id,
-                       JS::MutableHandle<JS::PropertyDescriptor> desc,
-                       bool& cacheOnHolder);
-
-/**
- * Define a property on obj through an Xray wrapper.
- *
- * wrapper is the Xray JS object.
- * obj is the target object of the Xray, a binding's instance object or a
- *     interface or interface prototype object.
- * id and desc are the parameters for the property to be defined.
- * result is the out-parameter indicating success (read it only if
- *     this returns true and also sets *defined to true).
- * defined will be set to true if a property was set as a result of this call.
- */
-bool
-XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                   JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                   JS::Handle<JS::PropertyDescriptor> desc,
-                   JS::ObjectOpResult &result,
-                   bool *defined);
-
-/**
- * Add to props the property keys of all indexed or named properties of obj and
- * operations, attributes and constants of the interfaces for obj.
- *
- * wrapper is the Xray JS object.
- * obj is the target object of the Xray, a binding's instance object or a
- *     interface or interface prototype object.
- * flags are JSITER_* flags.
- */
-bool
-XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                    JS::Handle<JSObject*> obj,
-                    unsigned flags, JS::AutoIdVector& props);
-
-/**
- * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
- * compartment. This always returns the prototype that would be used for a DOM
- * object if we ignore any changes that might have been done to the prototype
- * chain by JS, the XBL code or plugins.
- *
- * cx should be in the Xray's compartment.
- * obj is the target object of the Xray, a binding's instance object or an
- *     interface or interface prototype object.
- */
-inline bool
-XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
-                   JS::MutableHandle<JSObject*> protop)
-{
-  JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
-  {
-    JSAutoCompartment ac(cx, global);
-    const DOMJSClass* domClass = GetDOMClass(obj);
-    if (domClass) {
-      ProtoHandleGetter protoGetter = domClass->mGetProto;
-      if (protoGetter) {
-        protop.set(protoGetter(cx));
-      } else {
-        protop.set(JS::GetRealmObjectPrototype(cx));
-      }
-    } else {
-      const js::Class* clasp = js::GetObjectClass(obj);
-      MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
-      ProtoGetter protoGetter =
-        DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
-      protop.set(protoGetter(cx));
-    }
-  }
-
-  return JS_WrapObject(cx, protop);
-}
-
-extern NativePropertyHooks sEmptyNativePropertyHooks;
-
-extern const js::ClassOps sBoringInterfaceObjectClassClassOps;
-
-extern const js::ObjectOps sInterfaceObjectClassObjectOps;
-
-// We use one constructor JSNative to represent all DOM interface objects (so
-// we can easily detect when we need to wrap them in an Xray wrapper). We store
-// the real JSNative in the mNative member of a JSNativeHolder in the
-// CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
-// specific interface object. We also store the NativeProperties in the
-// JSNativeHolder.
-// Note that some interface objects are not yet a JSFunction but a normal
-// JSObject with a DOMJSClass, those do not use these slots.
-
-enum {
-  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
-};
-
-bool
-Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
-
-inline bool
-UseDOMXray(JSObject* obj)
-{
-  const js::Class* clasp = js::GetObjectClass(obj);
-  return IsDOMClass(clasp) ||
-         JS_IsNativeFunction(obj, Constructor) ||
-         IsDOMIfaceAndProtoClass(clasp);
-}
-
-#ifdef DEBUG
-inline bool
-HasConstructor(JSObject* obj)
-{
-  return JS_IsNativeFunction(obj, Constructor) ||
-         js::GetObjectClass(obj)->getConstruct();
-}
- #endif
-
-// Helpers for creating a const version of a type.
-template<typename T>
-const T& Constify(T& arg)
-{
-  return arg;
-}
-
-// Helper for turning (Owning)NonNull<T> into T&
-template<typename T>
-T& NonNullHelper(T& aArg)
-{
-  return aArg;
-}
-
-template<typename T>
-T& NonNullHelper(NonNull<T>& aArg)
-{
-  return aArg;
-}
-
-template<typename T>
-const T& NonNullHelper(const NonNull<T>& aArg)
-{
-  return aArg;
-}
-
-template<typename T>
-T& NonNullHelper(OwningNonNull<T>& aArg)
-{
-  return aArg;
-}
-
-template<typename T>
-const T& NonNullHelper(const OwningNonNull<T>& aArg)
-{
-  return aArg;
-}
-
-inline
-void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
-{
-  // This overload is here to make sure that we never end up applying
-  // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
-  // try to, it should fail to compile, since presumably the caller will try to
-  // use our nonexistent return value.
-}
-
-inline
-void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
-{
-  // This overload is here to make sure that we never end up applying
-  // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
-  // try to, it should fail to compile, since presumably the caller will try to
-  // use our nonexistent return value.
-}
-
-inline
-void NonNullHelper(binding_detail::FakeString& aArg)
-{
-  // This overload is here to make sure that we never end up applying
-  // NonNullHelper to a FakeString before we've constified it.  If we
-  // try to, it should fail to compile, since presumably the caller will try to
-  // use our nonexistent return value.
-}
-
-MOZ_ALWAYS_INLINE
-const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
-{
-  return aArg;
-}
-
-// Reparent the wrapper of aObj to whatever its native now thinks its
-// parent should be.
-nsresult
-ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
-
-/**
- * Used to implement the Symbol.hasInstance property of an interface object.
- */
-bool
-InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
-                     JS::Handle<JSObject*> instance,
-                     bool* bp);
-
-// Helper for lenient getters/setters to report to console.  If this
-// returns false, we couldn't even get a global.
-bool
-ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
-
-// Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
-// interface, get the nsIGlobalObject corresponding to the content side, if any.
-// A false return means an exception was thrown.
-bool
-GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
-                                       nsIGlobalObject** global);
-
-void
-ConstructJSImplementation(const char* aContractId,
-                          nsIGlobalObject* aGlobal,
-                          JS::MutableHandle<JSObject*> aObject,
-                          ErrorResult& aRv);
-
-already_AddRefed<nsIGlobalObject>
-ConstructJSImplementation(const char* aContractId,
-                          const GlobalObject& aGlobal,
-                          JS::MutableHandle<JSObject*> aObject,
-                          ErrorResult& aRv);
-
-/**
- * Convert an nsCString to jsval, returning true on success.
- * These functions are intended for ByteString implementations.
- * As such, the string is not UTF-8 encoded.  Any UTF8 strings passed to these
- * methods will be mangled.
- */
-bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
-                              JS::MutableHandle<JS::Value> rval);
-inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
-                              JS::MutableHandle<JS::Value> rval)
-{
-    if (str.IsVoid()) {
-        rval.setNull();
-        return true;
-    }
-    return NonVoidByteStringToJsval(cx, str, rval);
-}
-
-template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct PreserveWrapperHelper
-{
-  static void PreserveWrapper(T* aObject)
-  {
-    aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
-  }
-};
-
-template<class T>
-struct PreserveWrapperHelper<T, true>
-{
-  static void PreserveWrapper(T* aObject)
-  {
-    aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
-  }
-};
-
-template<class T>
-void PreserveWrapper(T* aObject)
-{
-  PreserveWrapperHelper<T>::PreserveWrapper(aObject);
-}
-
-template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct CastingAssertions
-{
-  static bool ToSupportsIsCorrect(T*)
-  {
-    return true;
-  }
-  static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
-  {
-    return true;
-  }
-};
-
-template<class T>
-struct CastingAssertions<T, true>
-{
-  static bool ToSupportsIsCorrect(T* aObject)
-  {
-    return ToSupports(aObject) ==  reinterpret_cast<nsISupports*>(aObject);
-  }
-  static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
-                                                    nsWrapperCache* aCache)
-  {
-    return reinterpret_cast<void*>(aObject) != aCache;
-  }
-};
-
-template<class T>
-bool
-ToSupportsIsCorrect(T* aObject)
-{
-  return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
-}
-
-template<class T>
-bool
-ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
-{
-  return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
-                                                                     aCache);
-}
-
-// The BindingJSObjectCreator class is supposed to be used by a caller that
-// wants to create and initialise a binding JSObject. After initialisation has
-// been successfully completed it should call ForgetObject().
-// The BindingJSObjectCreator object will root the JSObject until ForgetObject()
-// is called on it. If the native object for the binding is refcounted it will
-// also hold a strong reference to it, that reference is transferred to the
-// JSObject (which holds the native in a slot) when ForgetObject() is called. If
-// the BindingJSObjectCreator object is destroyed and ForgetObject() was never
-// called on it then the JSObject's slot holding the native will be set to
-// undefined, and for a refcounted native the strong reference will be released.
-template<class T>
-class MOZ_STACK_CLASS BindingJSObjectCreator
-{
-public:
-  explicit BindingJSObjectCreator(JSContext* aCx)
-    : mReflector(aCx)
-  {
-  }
-
-  ~BindingJSObjectCreator()
-  {
-    if (mReflector) {
-      js::SetReservedOrProxyPrivateSlot(mReflector, DOM_OBJECT_SLOT,
-                                        JS::UndefinedValue());
-    }
-  }
-
-  void
-  CreateProxyObject(JSContext* aCx, const js::Class* aClass,
-                    const DOMProxyHandler* aHandler,
-                    JS::Handle<JSObject*> aProto, T* aNative,
-                    JS::MutableHandle<JSObject*> aReflector)
-  {
-    js::ProxyOptions options;
-    options.setClass(aClass);
-    JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aNative));
-    aReflector.set(js::NewProxyObject(aCx, aHandler, proxyPrivateVal, aProto,
-                                      options));
-    if (aReflector) {
-      mNative = aNative;
-      mReflector = aReflector;
-    }
-  }
-
-  void
-  CreateObject(JSContext* aCx, const JSClass* aClass,
-               JS::Handle<JSObject*> aProto,
-               T* aNative, JS::MutableHandle<JSObject*> aReflector)
-  {
-    aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
-    if (aReflector) {
-      js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
-      mNative = aNative;
-      mReflector = aReflector;
-    }
-  }
-
-  void
-  InitializationSucceeded()
-  {
-    void* dummy;
-    mNative.forget(&dummy);
-    mReflector = nullptr;
-  }
-
-private:
-  struct OwnedNative
-  {
-    // Make sure the native objects inherit from NonRefcountedDOMObject so
-    // that we log their ctor and dtor.
-    static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
-                  "Non-refcounted objects with DOM bindings should inherit "
-                  "from NonRefcountedDOMObject.");
-
-    OwnedNative&
-    operator=(T* aNative)
-    {
-      return *this;
-    }
-
-    // This signature sucks, but it's the only one that will make a nsRefPtr
-    // just forget about its pointer without warning.
-    void
-    forget(void**)
-    {
-    }
-  };
-
-  JS::Rooted<JSObject*> mReflector;
-  typename Conditional<IsRefcounted<T>::value, RefPtr<T>, OwnedNative>::Type mNative;
-};
-
-template<class T>
-struct DeferredFinalizerImpl
-{
-  typedef typename Conditional<IsSame<T, nsISupports>::value,
-                               nsCOMPtr<T>,
-                               typename Conditional<IsRefcounted<T>::value,
-                                                    RefPtr<T>,
-                                                    nsAutoPtr<T>>::Type>::Type SmartPtr;
-  typedef SegmentedVector<SmartPtr> SmartPtrArray;
-
-  static_assert(IsSame<T, nsISupports>::value || !IsBaseOf<nsISupports, T>::value,
-                "nsISupports classes should all use the nsISupports instantiation");
-
-  static inline void
-  AppendAndTake(SegmentedVector<nsCOMPtr<nsISupports>>& smartPtrArray, nsISupports* ptr)
-  {
-    smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
-  }
-  template<class U>
-  static inline void
-  AppendAndTake(SegmentedVector<RefPtr<U>>& smartPtrArray, U* ptr)
-  {
-    smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
-  }
-  template<class U>
-  static inline void
-  AppendAndTake(SegmentedVector<nsAutoPtr<U>>& smartPtrArray, U* ptr)
-  {
-    smartPtrArray.InfallibleAppend(ptr);
-  }
-
-  static void*
-  AppendDeferredFinalizePointer(void* aData, void* aObject)
-  {
-    SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
-    if (!pointers) {
-      pointers = new SmartPtrArray();
-    }
-    AppendAndTake(*pointers, static_cast<T*>(aObject));
-    return pointers;
-  }
-  static bool
-  DeferredFinalize(uint32_t aSlice, void* aData)
-  {
-    MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
-    SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
-    uint32_t oldLen = pointers->Length();
-    if (oldLen < aSlice) {
-      aSlice = oldLen;
-    }
-    uint32_t newLen = oldLen - aSlice;
-    pointers->PopLastN(aSlice);
-    if (newLen == 0) {
-      delete pointers;
-      return true;
-    }
-    return false;
-  }
-};
-
-template<class T,
-         bool isISupports=IsBaseOf<nsISupports, T>::value>
-struct DeferredFinalizer
-{
-  static void
-  AddForDeferredFinalization(T* aObject)
-  {
-    typedef DeferredFinalizerImpl<T> Impl;
-    DeferredFinalize(Impl::AppendDeferredFinalizePointer,
-                     Impl::DeferredFinalize, aObject);
-  }
-};
-
-template<class T>
-struct DeferredFinalizer<T, true>
-{
-  static void
-  AddForDeferredFinalization(T* aObject)
-  {
-    DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
-  }
-};
-
-template<class T>
-static void
-AddForDeferredFinalization(T* aObject)
-{
-  DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
-}
-
-// This returns T's CC participant if it participates in CC or null if it
-// doesn't. This also returns null for classes that don't inherit from
-// nsISupports (QI should be used to get the participant for those).
-template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
-class GetCCParticipant
-{
-  // Helper for GetCCParticipant for classes that participate in CC.
-  template<class U>
-  static constexpr nsCycleCollectionParticipant*
-  GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
-  {
-    return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
-  }
-  // Helper for GetCCParticipant for classes that don't participate in CC.
-  template<class U>
-  static constexpr nsCycleCollectionParticipant*
-  GetHelper(double)
-  {
-    return nullptr;
-  }
-
-public:
-  static constexpr nsCycleCollectionParticipant*
-  Get()
-  {
-    // Passing int() here will try to call the GetHelper that takes an int as
-    // its firt argument. If T doesn't participate in CC then substitution for
-    // the second argument (with a default value) will fail and because of
-    // SFINAE the next best match (the variant taking a double) will be called.
-    return GetHelper<T>(int());
-  }
-};
-
-template<class T>
-class GetCCParticipant<T, true>
-{
-public:
-  static constexpr nsCycleCollectionParticipant*
-  Get()
-  {
-    return nullptr;
-  }
-};
-
-void
-FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
-
-bool
-ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
-              JS::Handle<jsid> aId, bool* aResolvedp);
-
-bool
-MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
-
-bool
-EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
-
-template <class T>
-struct CreateGlobalOptions
-{
-  static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
-    ProtoAndIfaceCache::NonWindowLike;
-  static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
-  {
-    mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
-  }
-  static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
-  {
-    MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
-
-    return true;
-  }
-};
-
-template <>
-struct CreateGlobalOptions<nsGlobalWindow>
-{
-  static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
-    ProtoAndIfaceCache::WindowLike;
-  static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
-  static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
-};
-
-nsresult
-RegisterDOMNames();
-
-// The return value is true if we created and successfully performed our part of
-// the setup for the global, false otherwise.
-//
-// Typically this method's caller will want to ensure that
-// xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
-// called after, this method, to ensure that this global object and its
-// compartment are consistent with other global objects.
-template <class T, ProtoHandleGetter GetProto>
-bool
-CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
-             const JSClass* aClass, JS::CompartmentOptions& aOptions,
-             JSPrincipals* aPrincipal, bool aInitStandardClasses,
-             JS::MutableHandle<JSObject*> aGlobal)
-{
-  aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
-  if (xpc::SharedMemoryEnabled()) {
-    aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
-  }
-
-  aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
-                                 JS::DontFireOnNewGlobalHook, aOptions));
-  if (!aGlobal) {
-    NS_WARNING("Failed to create global");
-    return false;
-  }
-
-  JSAutoCompartment ac(aCx, aGlobal);
-
-  {
-    js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
-    NS_ADDREF(aNative);
-
-    aCache->SetWrapper(aGlobal);
-
-    dom::AllocateProtoAndIfaceCache(aGlobal,
-                                    CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
-
-    if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
-      return false;
-    }
-  }
-
-  if (aInitStandardClasses &&
-      !JS_InitStandardClasses(aCx, aGlobal)) {
-    NS_WARNING("Failed to init standard classes");
-    return false;
-  }
-
-  JS::Handle<JSObject*> proto = GetProto(aCx);
-  if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
-    NS_WARNING("Failed to set proto");
-    return false;
-  }
-
-  bool succeeded;
-  if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
-    return false;
-  }
-  MOZ_ASSERT(succeeded,
-             "making a fresh global object's [[Prototype]] immutable can "
-             "internally fail, but it should never be unsuccessful");
-
-  return true;
-}
-
-/*
- * Holds a jsid that is initialized to a pinned string, with automatic
- * conversion to Handle<jsid>, as it is held live forever by pinning.
- */
-class PinnedStringId
-{
-  jsid id;
-
- public:
-  PinnedStringId() : id(JSID_VOID) {}
-
-  bool init(JSContext *cx, const char *string) {
-    JSString* str = JS_AtomizeAndPinString(cx, string);
-    if (!str)
-      return false;
-    id = INTERNED_STRING_TO_JSID(cx, str);
-    return true;
-  }
-
-  operator const jsid& () {
-    return id;
-  }
-
-  operator JS::Handle<jsid> () {
-    /* This is safe because we have pinned the string. */
-    return JS::Handle<jsid>::fromMarkedLocation(&id);
-  }
-};
-
-bool
-GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
-
-bool
-StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
-
-// ConvertExceptionToPromise should only be called when we have an error
-// condition (e.g. returned false from a JSAPI method).  Note that there may be
-// no exception on cx, in which case this is an uncatchable failure that will
-// simply be propagated.  Otherwise this method will attempt to convert the
-// exception to a Promise rejected with the exception that it will store in
-// rval.
-//
-// promiseScope should be the scope in which the Promise should be created.
-bool
-ConvertExceptionToPromise(JSContext* cx,
-                          JSObject* promiseScope,
-                          JS::MutableHandle<JS::Value> rval);
-
-#ifdef DEBUG
-void
-AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
-                               JS::Handle<JS::Value> aValue);
-#endif
-
-// This function is called by the bindings layer for methods/getters/setters
-// that are not safe to be called in prerendering mode.  It checks to make sure
-// that the |this| object is not running in a global that is in prerendering
-// mode.  Otherwise, it aborts execution of timers and event handlers, and
-// returns false which gets converted to an uncatchable exception by the
-// bindings layer.
-bool
-EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj);
-
-// Handles the violation of a blacklisted action in prerendering mode by
-// aborting the scripts, and preventing timers and event handlers from running
-// in the window in the future.
-void
-HandlePrerenderingViolation(nsPIDOMWindowInner* aWindow);
-
-bool
-CallerSubsumes(JSObject* aObject);
-
-MOZ_ALWAYS_INLINE bool
-CallerSubsumes(JS::Handle<JS::Value> aValue)
-{
-  if (!aValue.isObject()) {
-    return true;
-  }
-  return CallerSubsumes(&aValue.toObject());
-}
-
-template<class T>
-inline bool
-WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
-{
-  nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
-  if (!wrappedObj) {
-    return false;
-  }
-
-  JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
-  if (!obj) {
-    return false;
-  }
-
-  JSAutoCompartment ac(aCx, obj);
-  JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
-  return aDictionary.Init(aCx, v);
-}
-
-template<class T>
-inline bool
-WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
-{
-  nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
-  NS_ENSURE_TRUE(wrappedObj, false);
-  JS::Rooted<JSObject*> obj(RootingCx(), wrappedObj->GetJSObject());
-  NS_ENSURE_TRUE(obj, false);
-
-  nsIGlobalObject* global = xpc::NativeGlobal(obj);
-  NS_ENSURE_TRUE(global, false);
-
-  // we need this AutoEntryScript here because the spec requires us to execute
-  // getters when parsing a dictionary
-  AutoEntryScript aes(global, "WebIDL dictionary creation");
-
-  JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
-  return aDictionary.Init(aes.cx(), v);
-}
-
-
-template<class T, class S>
-inline RefPtr<T>
-StrongOrRawPtr(already_AddRefed<S>&& aPtr)
-{
-  return aPtr.template downcast<T>();
-}
-
-template<class T,
-         class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
-                                               nsAutoPtr<T>>::Type>
-inline ReturnType
-StrongOrRawPtr(T* aPtr)
-{
-  return ReturnType(aPtr);
-}
-
-template<class T, template<typename> class SmartPtr, class S>
-inline void
-StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
-
-template<class T>
-struct StrongPtrForMember
-{
-  typedef typename Conditional<IsRefcounted<T>::value,
-                               RefPtr<T>, nsAutoPtr<T>>::Type Type;
-};
-
-namespace binding_detail {
-inline
-JSObject*
-GetHackedNamespaceProtoObject(JSContext* aCx)
-{
-  return JS_NewPlainObject(aCx);
-}
-} // namespace binding_detail
-
-// Resolve an id on the given global object that wants to be included in
-// Exposed=System webidl annotations.  False return value means exception
-// thrown.
-bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
-                         JS::Handle<jsid> id, bool* resolvedp);
-
-// Enumerate all ids on the given global object that wants to be included in
-// Exposed=System webidl annotations.  False return value means exception
-// thrown.
-bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
-
-// Slot indexes for maplike/setlike forEach functions
-#define FOREACH_CALLBACK_SLOT 0
-#define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
-
-// Backing function for running .forEach() on maplike/setlike interfaces.
-// Unpacks callback and maplike/setlike object from reserved slots, then runs
-// callback for each key (and value, for maplikes)
-bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
-
-// Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
-// for a maplike/setlike interface. If backing object does not exist, creates
-// backing object in the compartment of the reflector involved, making this safe
-// to use across compartments/via xrays. Return values of these methods will
-// always be in the context compartment.
-bool GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                             size_t aSlotIndex,
-                             JS::MutableHandle<JSObject*> aBackingObj,
-                             bool* aBackingObjCreated);
-bool GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                             size_t aSlotIndex,
-                             JS::MutableHandle<JSObject*> aBackingObj,
-                             bool* aBackingObjCreated);
-
-// Get the desired prototype object for an object construction from the given
-// CallArgs.  Null is returned if the default prototype should be used.
-bool
-GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
-                JS::MutableHandle<JSObject*> aDesiredProto);
-
-void
-SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
-                             UseCounter aUseCounter);
-
-// Warnings
-void
-DeprecationWarning(JSContext* aCx, JSObject* aObject,
-                   nsIDocument::DeprecatedOperations aOperation);
-
-// A callback to perform funToString on an interface object
-JSString*
-InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
-                        unsigned /* indent */);
-
-namespace binding_detail {
-// Get a JS global object that can be used for some temporary allocations.  The
-// idea is that this should be used for situations when you need to operate in
-// _some_ compartment but don't care which one.  A typical example is when you
-// have non-JS input, non-JS output, but have to go through some sort of JS
-// representation in the middle, so need a compartment to allocate things in.
-//
-// It's VERY important that any consumers of this function only do things that
-// are guaranteed to be side-effect-free, even in the face of a script
-// environment controlled by a hostile adversary.  This is because in the worker
-// case the global is in fact the worker global, so it and its standard objects
-// are controlled by the worker script.  This is why this function is in the
-// binding_detail namespace.  Any use of this function MUST be very carefully
-// reviewed by someone who is sufficiently devious and has a very good
-// understanding of all the code that will run while we're using the return
-// value, including the SpiderMonkey parts.
-JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
-} // namespace binding_detail
-
 } // namespace dom
 } // namespace mozilla
 
-#endif /* mozilla_dom_BindingUtils_h__ */
+#endif /* mozilla_dom_FakeString_h__ */
\ No newline at end of file
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -24,16 +24,17 @@ EXPORTS.mozilla.dom += [
     'CallbackInterface.h',
     'CallbackObject.h',
     'Date.h',
     'DOMJSClass.h',
     'DOMJSProxyHandler.h',
     'DOMString.h',
     'Errors.msg',
     'Exceptions.h',
+    'FakeString.h',
     'IterableIterator.h',
     'JSSlots.h',
     'MozMap.h',
     'NonRefcountedDOMObject.h',
     'Nullable.h',
     'PrimitiveConversions.h',
     'RootedDictionary.h',
     'SimpleGlobalObject.h',
--- a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
@@ -147,17 +147,17 @@ BluetoothMapSmsManager::Uninit()
     mMasSocket = nullptr;
   }
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (NS_WARN_IF(!obs)) {
     return;
   }
 
-  NS_WARN_IF(NS_FAILED(
+  Unused << NS_WARN_IF(NS_FAILED(
     obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
 }
 
 // static
 void
 BluetoothMapSmsManager::InitMapSmsInterface(BluetoothProfileResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
@@ -154,17 +154,17 @@ BluetoothPbapManager::Uninit()
     mSocket = nullptr;
   }
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (NS_WARN_IF(!obs)) {
     return;
   }
 
-  NS_WARN_IF(NS_FAILED(
+  Unused << NS_WARN_IF(NS_FAILED(
     obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
 }
 
 // static
 void
 BluetoothPbapManager::InitPbapInterface(BluetoothProfileResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/bluetooth/bluez/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluez/BluetoothSocket.cpp
@@ -4,20 +4,21 @@
  * 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 "BluetoothSocket.h"
 #include <fcntl.h>
 #include "BluetoothSocketObserver.h"
 #include "BluetoothUnixSocketConnector.h"
 #include "BluetoothUtils.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/Unused.h"
 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
 #include "nsXULAppAPI.h"
-#include "mozilla/Unused.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 static const size_t MAX_READ_SIZE = 1 << 16;
 
 //
@@ -237,17 +238,17 @@ BluetoothSocket::BluetoothSocketIO::List
       FireSocketError();
       return;
     }
     SetFd(fd);
 
     // calls OnListening on success, or OnError otherwise
     rv = UnixSocketWatcher::Listen(
       reinterpret_cast<struct sockaddr*>(&mAddress), mAddressLength);
-    NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Listen failed");
   }
 }
 
 void
 BluetoothSocket::BluetoothSocketIO::Connect()
 {
   MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
   MOZ_ASSERT(mConnector);
@@ -261,19 +262,19 @@ BluetoothSocket::BluetoothSocketIO::Conn
     if (NS_WARN_IF(NS_FAILED(rv))) {
       FireSocketError();
       return;
     }
     SetFd(fd);
   }
 
   // calls OnConnected() on success, or OnError() otherwise
-  nsresult rv = UnixSocketWatcher::Connect(
+  DebugOnly<nsresult> rv = UnixSocketWatcher::Connect(
     reinterpret_cast<struct sockaddr*>(&mAddress), mAddressLength);
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Connect failed");
 }
 
 void
 BluetoothSocket::BluetoothSocketIO::Send(UnixSocketIOBuffer* aBuffer)
 {
   EnqueueData(aBuffer);
   AddWatchers(WRITE_WATCHER, false);
 }
--- a/dom/bluetooth/common/BluetoothUtils.cpp
+++ b/dom/bluetooth/common/BluetoothUtils.cpp
@@ -774,61 +774,61 @@ DispatchReplySuccess(BluetoothReplyRunna
                      const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aRunnable);
   MOZ_ASSERT(aValue.type() != BluetoothValue::T__None);
 
   BluetoothReply* reply = new BluetoothReply(BluetoothReplySuccess(aValue));
 
   aRunnable->SetReply(reply); // runnable will delete reply after Run()
-  NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
+  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
 }
 
 void
 DispatchReplyError(BluetoothReplyRunnable* aRunnable,
                    const nsAString& aErrorStr)
 {
   MOZ_ASSERT(aRunnable);
   MOZ_ASSERT(!aErrorStr.IsEmpty());
 
   // Reply will be deleted by the runnable after running on main thread
   BluetoothReply* reply =
     new BluetoothReply(BluetoothReplyError(STATUS_FAIL, nsString(aErrorStr)));
 
   aRunnable->SetReply(reply);
-  NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
+  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
 }
 
 void
 DispatchReplyError(BluetoothReplyRunnable* aRunnable,
                    const enum BluetoothStatus aStatus)
 {
   MOZ_ASSERT(aRunnable);
   MOZ_ASSERT(aStatus != STATUS_SUCCESS);
 
   // Reply will be deleted by the runnable after running on main thread
   BluetoothReply* reply =
     new BluetoothReply(BluetoothReplyError(aStatus, EmptyString()));
 
   aRunnable->SetReply(reply);
-  NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
+  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
 }
 
 void
 DispatchReplyError(BluetoothReplyRunnable* aRunnable,
                    const enum BluetoothGattStatus aGattStatus)
 {
   MOZ_ASSERT(aRunnable);
 
   // Reply will be deleted by the runnable after running on main thread
   BluetoothReply* reply =
     new BluetoothReply(BluetoothReplyError(aGattStatus, EmptyString()));
 
   aRunnable->SetReply(reply);
-  NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
+  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
 }
 
 void
 DispatchStatusChangedEvent(const nsAString& aType,
                            const BluetoothAddress& aAddress,
                            bool aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/cache/test/mochitest/test_cache_orphaned_body.html
+++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html
@@ -38,16 +38,42 @@ function storageUsage() {
     var principal = SpecialPowers.wrap(document).nodePrincipal;
     var cb = SpecialPowers.wrapCallback(function(request) {
       resolve(request.usage, request.fileUsage);
     });
     qms.getUsageForPrincipal(principal, cb);
   });
 }
 
+function groupUsage() {
+  return new Promise(function(resolve, reject) {
+   navigator.storage.estimate().then(storageEstimation => {
+     resolve(storageEstimation.usage, 0);
+   });
+  });
+}
+
+function workerGroupUsage() {
+  return new Promise(function(resolve, reject) {
+    function workerScript() {
+      navigator.storage.estimate().then(storageEstimation => {
+        postMessage(storageEstimation.usage);
+      });
+    }
+
+    let url =
+      URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
+
+    let worker = new Worker(url);
+    worker.onmessage = function (e) {
+      resolve(e.data, 0);
+    };
+  });
+}
+
 function resetStorage() {
   return new Promise(function(resolve, reject) {
     var qms = SpecialPowers.Services.qms;
     var request = qms.reset();
     var cb = SpecialPowers.wrapCallback(resolve);
     request.callback = cb;
   });
 }
@@ -137,16 +163,36 @@ SpecialPowers.pushPrefEnv({
     return resetStorage();
   }).then(function() {
     return storageUsage();
   }).then(function(usage) {
     fullUsage = usage;
     ok(fullUsage > initialUsage, 'disk usage should have grown');
   })
 
+  // Test groupUsage()
+  .then(function() {
+    return resetStorage();
+  }).then(function() {
+    return groupUsage();
+  }).then(function(usage) {
+    fullUsage = usage;
+    ok(fullUsage > initialUsage, 'disk group usage should have grown');
+  })
+
+  // Test workerGroupUsage()
+  .then(function() {
+    return resetStorage();
+  }).then(function() {
+    return workerGroupUsage();
+  }).then(function(usage) {
+    fullUsage = usage;
+    ok(fullUsage > initialUsage, 'disk group usage on worker should have grown');
+  })
+
   // Now perform a new Cache operation that will reopen the origin.  This
   // should clean up the orphaned body.
   .then(function() {
     return caches.match(url);
   }).then(function(r) {
     ok(!r, 'response should not exist in storage');
   })
 
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -1444,20 +1444,20 @@ nsGonkCameraControl::OnAutoFocusMoving(b
     {
       ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
       if (mAutoFocusCompleteTimer) {
         mAutoFocusCompleteTimer->Cancel();
 
         if (!mAutoFocusPending) {
           RefPtr<nsITimerCallback> timerCb = new AutoFocusMovingTimerCallback(this);
-          nsresult rv = mAutoFocusCompleteTimer->InitWithCallback(timerCb,
-                                                                  kAutoFocusCompleteTimeoutMs,
-                                                                  nsITimer::TYPE_ONE_SHOT);
-          NS_WARN_IF(NS_FAILED(rv));
+          DebugOnly<nsresult> rv =
+            mAutoFocusCompleteTimer->InitWithCallback(
+              timerCb, kAutoFocusCompleteTimeoutMs, nsITimer::TYPE_ONE_SHOT);
+          NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "InitWithCallback failed");
         }
         return;
       }
 
       if (!mAutoFocusPending) {
         expiredCount = mAutoFocusCompleteExpired;
       }
     }
--- a/dom/camera/TestGonkCameraHardware.cpp
+++ b/dom/camera/TestGonkCameraHardware.cpp
@@ -17,16 +17,17 @@
 #include "TestGonkCameraHardware.h"
 #include "CameraPreferences.h"
 #include "nsThreadUtils.h"
 #include "mozilla/dom/EventListenerBinding.h"
 #include "mozilla/dom/BlobEvent.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/CameraFacesDetectedEvent.h"
 #include "mozilla/dom/CameraStateChangeEvent.h"
+#include "mozilla/DebugOnly.h"
 #include "nsNetUtil.h"
 #include "DOMCameraDetectedFace.h"
 #include "nsServiceManagerUtils.h"
 #include "nsICameraTestHardware.h"
 
 using namespace android;
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -240,18 +241,18 @@ public:
   {
     if (NS_WARN_IF(!mTestHw)) {
       return NS_ERROR_INVALID_ARG;
     }
 
     MutexAutoLock lock(mTestHw->mMutex);
 
     mTestHw->mStatus = RunInline();
-    nsresult rv = mTestHw->mCondVar.Notify();
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = mTestHw->mCondVar.Notify();
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Notify failed");
     return NS_OK;
   }
 
   nsresult
   RunInline()
   {
     if (NS_WARN_IF(!mTestHw)) {
       return NS_ERROR_INVALID_ARG;
@@ -308,25 +309,25 @@ TestGonkCameraHardware::~TestGonkCameraH
     { }
 
   protected:
     NS_IMETHOD
     RunImpl() override
     {
       if (mTestHw->mDomListener) {
         mTestHw->mDomListener = nullptr;
-        nsresult rv = mJSTestWrapper->SetHandler(nullptr);
-        NS_WARN_IF(NS_FAILED(rv));
+        DebugOnly<nsresult> rv = mJSTestWrapper->SetHandler(nullptr);
+        NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetHandler failed");
       }
       return NS_OK;
     }
   };
 
-  nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
   DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraHardware =====^\n");
 }
 
 nsresult
 TestGonkCameraHardware::WaitWhileRunningOnMainThread(RefPtr<ControlMessage> aRunnable)
 {
   MutexAutoLock lock(mMutex);
 
@@ -380,18 +381,18 @@ TestGonkCameraHardware::Init()
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       return NS_OK;
     }
   };
 
-  nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
   return rv;
 }
 
 int
 TestGonkCameraHardware::AutoFocus()
 {
   class Delegate : public ControlMessage
   {
@@ -534,18 +535,18 @@ TestGonkCameraHardware::CancelTakePictur
     NS_IMETHOD
     RunImpl() override
     {
       return mJSTestWrapper->CancelTakePicture();
     }
   };
 
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
-  nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
 }
 
 int
 TestGonkCameraHardware::StartPreview()
 {
   class Delegate : public ControlMessage
   {
   public:
@@ -583,18 +584,18 @@ TestGonkCameraHardware::StopPreview()
     NS_IMETHOD
     RunImpl() override
     {
       return mJSTestWrapper->StopPreview();
     }
   };
 
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
-  nsresult rv = WaitWhileRunningOnMainThread(new Delegate(this));
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = WaitWhileRunningOnMainThread(new Delegate(this));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WaitWhileRunningOnMainThread failed");
 }
 
 class TestGonkCameraHardware::PushParametersDelegate : public ControlMessage
 {
 public:
   PushParametersDelegate(TestGonkCameraHardware* aTestHw, String8* aParams)
     : ControlMessage(aTestHw)
     , mParams(aParams)
--- a/dom/canvas/test/test_bitmaprenderer.html
+++ b/dom/canvas/test/test_bitmaprenderer.html
@@ -71,18 +71,18 @@ function runTest(canvasWidth, canvasHeig
     var snapshotRef = snapshotWindow(window);
 
     // bitmaprenderers use an ImageLayer whereas a normal 2d canvas uses a canvas layer. This
     // can result in some anti-aliasing differences on the edge. We consider slight AA differences
     // to be reasonable when using different codepaths so fuzz a little bit.
     var fuzz = { numDifferentPixels:  0,
                  maxDifference: 0 };
     if (SpecialPowers.Services.appinfo.widgetToolkit == "android") {
-      fuzz.maxDifference = 14;
-      fuzz.numDifferentPixels = 130;
+      fuzz.maxDifference = 2;
+      fuzz.numDifferentPixels = 131;
     }
     var results = compareSnapshots(snapshot, snapshotRef, true, fuzz);
     ok(results[0], "Screenshots should be the same");
 
     document.body.removeChild(canvasRef);
     document.body.removeChild(canvas2);
 
     nextTest();
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -1376,17 +1376,17 @@ Console::MethodInternal(JSContext* aCx, 
     return;
   }
 
   // We do this only in workers for now.
   NotifyHandler(aCx, aData, callData);
 
   RefPtr<ConsoleCallDataRunnable> runnable =
     new ConsoleCallDataRunnable(this, callData);
-  NS_WARN_IF(!runnable->Dispatch(aCx));
+  Unused << NS_WARN_IF(!runnable->Dispatch(aCx));
 }
 
 // We store information to lazily compute the stack in the reserved slots of
 // LazyStackGetter.  The first slot always stores a JS object: it's either the
 // JS wrapper of the nsIStackFrame or the actual reified stack representation.
 // The second slot is a PrivateValue() holding an nsIStackFrame* when we haven't
 // reified the stack yet, or an UndefinedValue() otherwise.
 enum {
@@ -1473,18 +1473,18 @@ Console::ProcessCallData(JSContext* aCx,
     innerID = aData->mInnerIDString;
   } else {
     MOZ_ASSERT(aData->mIDType == ConsoleCallData::eNumber);
     outerID.AppendInt(aData->mOuterIDNumber);
     innerID.AppendInt(aData->mInnerIDNumber);
   }
 
   if (aData->mMethodName == MethodClear) {
-    nsresult rv = mStorage->ClearEvents(innerID);
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = mStorage->ClearEvents(innerID);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ClearEvents failed");
   }
 
   if (NS_FAILED(mStorage->RecordEvent(innerID, outerID, eventValue))) {
     NS_WARNING("Failed to record a console event.");
   }
 }
 
 bool
--- a/dom/events/DataTransferItem.cpp
+++ b/dom/events/DataTransferItem.cpp
@@ -421,17 +421,17 @@ DataTransferItem::GetAsString(FunctionSt
                 const nsAString& aStringData)
       : mCallback(aCallback), mStringData(aStringData)
     {}
 
     NS_IMETHOD Run() override
     {
       ErrorResult rv;
       mCallback->Call(mStringData, rv);
-      NS_WARN_IF(rv.Failed());
+      NS_WARNING_ASSERTION(!rv.Failed(), "callback failed");
       return rv.StealNSResult();
     }
   private:
     RefPtr<FunctionStringCallback> mCallback;
     nsString mStringData;
   };
 
   RefPtr<GASRunnable> runnable = new GASRunnable(aCallback, stringData);
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -27,16 +27,19 @@ PointerEvent::PointerEvent(EventTarget* 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->mTime = PR_Now();
     mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
     mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
   }
+  // 5.2 Pointer Event types, for all pointer events, |detail| attribute SHOULD
+  // be 0.
+  mDetail = 0;
 }
 
 static uint16_t
 ConvertStringToPointerType(const nsAString& aPointerTypeArg)
 {
   if (aPointerTypeArg.EqualsLiteral("mouse")) {
     return nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
   }
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -3,17 +3,16 @@ skip-if = (toolkit == 'gonk') || (os == 
 support-files =
   mochitest_support_external.js
   mochitest_support_internal.js
   pointerevent_styles.css
   pointerevent_support.js
 
 [test_pointerevent_attributes_mouse-manual.html]
   support-files = pointerevent_attributes_mouse-manual.html
-  disabled = should be investigated
 [test_pointerevent_capture_mouse-manual.html]
   support-files = pointerevent_capture_mouse-manual.html
 [test_pointerevent_capture_suppressing_mouse-manual.html]
   support-files = pointerevent_capture_suppressing_mouse-manual.html
 [test_pointerevent_change-touch-action-onpointerdown_touch-manual.html]
   support-files = pointerevent_change-touch-action-onpointerdown_touch-manual.html
   disabled = disabled
 [test_pointerevent_constructor.html]
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -602,17 +602,17 @@ FetchDriver::OnStartRequest(nsIRequest* 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailWithNetworkError();
     // Cancel request.
     return rv;
   }
 
   // Try to retarget off main thread.
   if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
-    NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts)));
+    Unused << NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts)));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FetchDriver::OnDataAvailable(nsIRequest* aRequest,
                              nsISupports* aContext,
                              nsIInputStream* aInputStream,
--- a/dom/filehandle/ActorsChild.cpp
+++ b/dom/filehandle/ActorsChild.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "MutableFileBase.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsString.h"
 #include "xpcpublic.h"
+#include "mozilla/dom/BindingUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 /*******************************************************************************
  * Helpers
  ******************************************************************************/
 
--- a/dom/filesystem/CreateDirectoryTask.cpp
+++ b/dom/filesystem/CreateDirectoryTask.cpp
@@ -95,17 +95,17 @@ CreateDirectoryTaskChild::SetSuccessRequ
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
 
   const FileSystemDirectoryResponse& r =
     aValue.get_FileSystemDirectoryResponse();
 
   aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(r.realPath()), true,
                               getter_AddRefs(mTargetPath));
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "NS_NewNativeLocalFile failed");
 }
 
 void
 CreateDirectoryTaskChild::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mFileSystem->IsShutdown()) {
     mPromise = nullptr;
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/dom/DeviceStorageFileSystem.h"
 
 #include "DeviceStorage.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemUtils.h"
+#include "mozilla/Unused.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDeviceStorage.h"
 #include "nsIFile.h"
 #include "nsPIDOMWindow.h"
 #include "nsGlobalWindow.h"
 
 namespace mozilla {
@@ -35,27 +36,29 @@ DeviceStorageFileSystem::DeviceStorageFi
     } else {
       mPermissionCheckType = ePermissionCheckRequired;
     }
   } else {
     AssertIsOnBackgroundThread();
   }
 
   // Get the permission name required to access the file system.
-  nsresult rv =
+  DebugOnly<nsresult> rv =
     DeviceStorageTypeChecker::GetPermissionForType(mStorageType, mPermission);
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetPermissionForType failed");
 
   // Get the local path of the file system root.
   nsCOMPtr<nsIFile> rootFile;
   DeviceStorageFile::GetRootDirectoryForType(aStorageType,
                                              aStorageName,
                                              getter_AddRefs(rootFile));
 
-  NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalOrDeviceStorageRootPath)));
+  Unused <<
+    NS_WARN_IF(!rootFile ||
+               NS_FAILED(rootFile->GetPath(mLocalOrDeviceStorageRootPath)));
 
   if (!XRE_IsParentProcess()) {
     return;
   }
 
   // DeviceStorageTypeChecker is a singleton object and must be initialized on
   // the main thread. We initialize it here so that we can use it on the worker
   // thread.
@@ -135,17 +138,17 @@ DeviceStorageFileSystem::GetDirectoryNam
   }
 
   if (equal) {
     aRetval = mStorageName;
     return;
   }
 
   FileSystemBase::GetDirectoryName(aFile, aRetval, aRv);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "GetDirectoryName failed");
 }
 
 bool
 DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
 {
   MOZ_ASSERT(XRE_IsParentProcess(), "Should be on parent process!");
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aFile);
--- a/dom/filesystem/FileSystemBase.cpp
+++ b/dom/filesystem/FileSystemBase.cpp
@@ -115,17 +115,17 @@ FileSystemBase::IsSafeDirectory(Director
 void
 FileSystemBase::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
                                  ErrorResult& aRv) const
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aFile);
 
   aRv = aFile->GetLeafName(aRetval);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "GetLeafName failed");
 }
 
 void
 FileSystemBase::GetDOMPath(nsIFile* aFile,
                            nsAString& aRetval,
                            ErrorResult& aRv) const
 {
   AssertIsOnOwningThread();
--- a/dom/filesystem/FileSystemTaskBase.cpp
+++ b/dom/filesystem/FileSystemTaskBase.cpp
@@ -130,18 +130,18 @@ FileSystemTaskChildBase::GetFileSystem()
 void
 FileSystemTaskChildBase::Start()
 {
   mFileSystem->AssertIsOnOwningThread();
 
   if (HasError()) {
     // In this case we don't want to use IPC at all.
     RefPtr<ErrorRunnable> runnable = new ErrorRunnable(this);
-    nsresult rv = NS_DispatchToCurrentThread(runnable);
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
     return;
   }
 
   if (mFileSystem->IsShutdown()) {
     return;
   }
 
   nsAutoString serialization;
@@ -230,23 +230,23 @@ FileSystemTaskParentBase::~FileSystemTas
 
 void
 FileSystemTaskParentBase::Start()
 {
   AssertIsOnBackgroundThread();
   mFileSystem->AssertIsOnOwningThread();
 
   if (NeedToGoToMainThread()) {
-    nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
     return;
   }
 
-  nsresult rv = DispatchToIOThread(this);
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = DispatchToIOThread(this);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchToIOThread failed");
 }
 
 void
 FileSystemTaskParentBase::HandleResult()
 {
   AssertIsOnBackgroundThread();
   mFileSystem->AssertIsOnOwningThread();
 
--- a/dom/filesystem/compat/CallbackRunnables.cpp
+++ b/dom/filesystem/compat/CallbackRunnables.cpp
@@ -7,16 +7,17 @@
 #include "CallbackRunnables.h"
 #include "mozilla/dom/DirectoryBinding.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/FileSystemDirectoryReaderBinding.h"
 #include "mozilla/dom/FileSystemFileEntry.h"
 #include "mozilla/dom/Promise.h"
+#include "mozilla/Unused.h"
 #include "nsIGlobalObject.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 EntryCallbackRunnable::EntryCallbackRunnable(FileSystemEntryCallback* aCallback,
                                              FileSystemEntry* aEntry)
@@ -136,34 +137,34 @@ GetEntryHelper::RejectedCallback(JSConte
 void
 GetEntryHelper::Error(nsresult aError)
 {
   MOZ_ASSERT(NS_FAILED(aError));
 
   if (mErrorCallback) {
     RefPtr<ErrorCallbackRunnable> runnable =
       new ErrorCallbackRunnable(mGlobal, mErrorCallback, aError);
-    nsresult rv = NS_DispatchToMainThread(runnable);
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
   }
 }
 
 NS_IMPL_ISUPPORTS0(GetEntryHelper);
 
 /* static */ void
 ErrorCallbackHelper::Call(nsIGlobalObject* aGlobal,
                           const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
                           nsresult aError)
 {
   MOZ_ASSERT(aGlobal);
   MOZ_ASSERT(NS_FAILED(aError));
 
   if (aErrorCallback.WasPassed()) {
     RefPtr<ErrorCallbackRunnable> runnable =
       new ErrorCallbackRunnable(aGlobal, &aErrorCallback.Value(), aError);
-    nsresult rv = NS_DispatchToMainThread(runnable);
-    NS_WARN_IF(NS_FAILED(rv));
+    DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
   }
 }
 
 } // dom namespace
 } // mozilla namespace
 
--- a/dom/filesystem/compat/FileSystemDirectoryReader.cpp
+++ b/dom/filesystem/compat/FileSystemDirectoryReader.cpp
@@ -93,18 +93,18 @@ public:
 
   virtual void
   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   {
     if (mErrorCallback) {
       RefPtr<ErrorCallbackRunnable> runnable =
         new ErrorCallbackRunnable(mGlobal, mErrorCallback,
                                   NS_ERROR_DOM_INVALID_STATE_ERR);
-      nsresult rv = NS_DispatchToMainThread(runnable);
-      NS_WARN_IF(NS_FAILED(rv));
+      DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
     }
   }
 
 private:
   ~PromiseHandler() {}
 
   nsCOMPtr<nsIGlobalObject> mGlobal;
   RefPtr<FileSystem> mFileSystem;
@@ -155,17 +155,17 @@ FileSystemDirectoryReader::ReadEntries(F
                                        ErrorResult& aRv)
 {
   MOZ_ASSERT(mDirectory);
 
   if (mAlreadyRead) {
     RefPtr<EmptyEntriesCallbackRunnable> runnable =
       new EmptyEntriesCallbackRunnable(&aSuccessCallback);
     aRv = NS_DispatchToMainThread(runnable);
-    NS_WARN_IF(aRv.Failed());
+    NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed");
     return;
   }
 
   // This object can be used only once.
   mAlreadyRead = true;
 
   ErrorResult rv;
   RefPtr<Promise> promise = mDirectory->GetFilesAndDirectories(rv);
--- a/dom/filesystem/compat/FileSystemFileEntry.cpp
+++ b/dom/filesystem/compat/FileSystemFileEntry.cpp
@@ -98,14 +98,14 @@ FileSystemFileEntry::CreateWriter(VoidCa
 }
 
 void
 FileSystemFileEntry::GetFile(BlobCallback& aSuccessCallback,
                              const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const
 {
   RefPtr<BlobCallbackRunnable> runnable =
     new BlobCallbackRunnable(&aSuccessCallback, mFile);
-  nsresult rv = NS_DispatchToMainThread(runnable);
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp
+++ b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp
@@ -111,18 +111,18 @@ FileSystemRootDirectoryEntry::GetInterna
       ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
                                 NS_ERROR_DOM_TYPE_MISMATCH_ERR);
       return;
     }
 
     if (aSuccessCallback.WasPassed()) {
       RefPtr<EntryCallbackRunnable> runnable =
         new EntryCallbackRunnable(&aSuccessCallback.Value(), entry);
-      nsresult rv = NS_DispatchToMainThread(runnable);
-      NS_WARN_IF(NS_FAILED(rv));
+      DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
     }
     return;
   }
 
   // Subdirectories, but this is a file.
   if (entry->IsFile()) {
     ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
                               NS_ERROR_DOM_NOT_FOUND_ERR);
--- a/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp
+++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp
@@ -74,23 +74,23 @@ void
 FileSystemRootDirectoryReader::ReadEntries(FileSystemEntriesCallback& aSuccessCallback,
                                            const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
                                            ErrorResult& aRv)
 {
   if (mAlreadyRead) {
     RefPtr<EmptyEntriesCallbackRunnable> runnable =
       new EmptyEntriesCallbackRunnable(&aSuccessCallback);
     aRv = NS_DispatchToMainThread(runnable);
-    NS_WARN_IF(aRv.Failed());
+    NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed");
     return;
   }
 
   // This object can be used only once.
   mAlreadyRead = true;
 
   RefPtr<EntriesCallbackRunnable> runnable =
     new EntriesCallbackRunnable(&aSuccessCallback, mEntries);
   aRv = NS_DispatchToMainThread(runnable);
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed");
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/flyweb/FlyWebService.cpp
+++ b/dom/flyweb/FlyWebService.cpp
@@ -319,22 +319,22 @@ FlyWebMDNSService::OnDiscoveryStarted(co
   LOG_I("===========================================");
 
   // Clear the new service array.
   mNewServiceSet.Clear();
 
   // If service discovery is inactive, then stop network discovery immediately.
   if (!mDiscoveryActive) {
     // Set the stop timer to fire immediately.
-    NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
+    Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
     return NS_OK;
   }
 
   // Otherwise, set the stop timer to fire in 5 seconds.
-  NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT)));
+  Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT)));
 
   return NS_OK;
 }
 
 nsresult
 FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType)
 {
   LOG_I("///////////////////////////////////////////");
@@ -358,17 +358,17 @@ FlyWebMDNSService::OnDiscoveryStopped(co
       iter.Remove();
     }
   }
 
   // Notify FlyWebService of changed service list.
   mService->NotifyDiscoveredServicesChanged();
 
   // Start discovery again immediately.
-  NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
+  Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
 
   return NS_OK;
 }
 
 nsresult
 FlyWebMDNSService::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
 {
   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceFound");
@@ -400,32 +400,32 @@ FlyWebMDNSService::OnStartDiscoveryFaile
   LOG_E("MDNSService::OnStartDiscoveryFailed(%s): %d", PromiseFlatCString(aServiceType).get(), (int) aErrorCode);
 
   MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
   mDiscoveryState = DISCOVERY_IDLE;
   mNumConsecutiveStartDiscoveryFailures++;
 
   // If discovery is active, and the number of consecutive failures is < 3, try starting again.
   if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) {
-    NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
+    Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
   }
 
   return NS_OK;
 }
 
 nsresult
 FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
 {
   LOG_E("MDNSService::OnStopDiscoveryFailed(%s)", PromiseFlatCString(aServiceType).get());
   MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
   mDiscoveryState = DISCOVERY_IDLE;
 
   // If discovery is active, start discovery again immediately.
   if (mDiscoveryActive) {
-    NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
+    Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
   }
 
   return NS_OK;
 }
 
 static bool
 IsAcceptableServiceAddress(const nsCString& addr)
 {
--- a/dom/gamepad/ipc/GamepadEventChannelChild.cpp
+++ b/dom/gamepad/ipc/GamepadEventChannelChild.cpp
@@ -27,16 +27,16 @@ class GamepadUpdateRunnable final : publ
 };
 
 } // namespace
 
 bool
 GamepadEventChannelChild::RecvGamepadUpdate(
                                        const GamepadChangeEvent& aGamepadEvent)
 {
-  nsresult rv;
-  rv = NS_DispatchToMainThread(new GamepadUpdateRunnable(aGamepadEvent));
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv =
+    NS_DispatchToMainThread(new GamepadUpdateRunnable(aGamepadEvent));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/grid/Grid.cpp
+++ b/dom/grid/Grid.cpp
@@ -26,63 +26,73 @@ Grid::Grid(nsISupports* aParent,
            nsGridContainerFrame* aFrame)
   : mParent(do_QueryInterface(aParent))
   , mRows(new GridDimension(this))
   , mCols(new GridDimension(this))
 {
   MOZ_ASSERT(aFrame,
     "Should never be instantiated with a null nsGridContainerFrame");
 
-  const ComputedGridTrackInfo* rowTrackInfo =
-    aFrame->GetComputedTemplateRows();
-  const ComputedGridLineInfo* rowLineInfo =
-    aFrame->GetComputedTemplateRowLines();
-  mRows->SetTrackInfo(rowTrackInfo);
-  mRows->SetLineInfo(rowTrackInfo, rowLineInfo);
+  // Construct areas first, because lines may need to reference them
+  // to extract additional names for boundary lines.
 
-  const ComputedGridTrackInfo* columnTrackInfo =
-    aFrame->GetComputedTemplateColumns();
-  const ComputedGridLineInfo* columnLineInfo =
-    aFrame->GetComputedTemplateColumnLines();
-  mCols->SetTrackInfo(columnTrackInfo);
-  mCols->SetLineInfo(columnTrackInfo, columnLineInfo);
-
-  // Add implicit areas first.
+  // Add implicit areas first. Track the names that we add here, because
+  // we will ignore future explicit areas with the same name.
+  nsTHashtable<nsStringHashKey> namesSeen;
   nsGridContainerFrame::ImplicitNamedAreas* implicitAreas =
     aFrame->GetImplicitNamedAreas();
   if (implicitAreas) {
     for (auto iter = implicitAreas->Iter(); !iter.Done(); iter.Next()) {
-      nsStringHashKey* entry = iter.Get();
-
-      GridArea* area = new GridArea(this,
-                                    nsString(entry->GetKey()),
-                                    GridDeclaration::Implicit,
-                                    0,
-                                    0,
-                                    0,
-                                    0);
-      mAreas.AppendElement(area);
-    }
-  }
-
-  // Add explicit areas next.
-  nsGridContainerFrame::ExplicitNamedAreas* explicitAreas =
-    aFrame->GetExplicitNamedAreas();
-  if (explicitAreas) {
-    for (auto areaInfo : *explicitAreas) {
+      auto& areaInfo = iter.Data();
+      namesSeen.PutEntry(areaInfo.mName);
       GridArea* area = new GridArea(this,
                                     areaInfo.mName,
-                                    GridDeclaration::Explicit,
+                                    GridDeclaration::Implicit,
                                     areaInfo.mRowStart,
                                     areaInfo.mRowEnd,
                                     areaInfo.mColumnStart,
                                     areaInfo.mColumnEnd);
       mAreas.AppendElement(area);
     }
   }
+
+  // Add explicit areas next, as long as they don't have the same name
+  // as the implicit areas, because the implicit values override what was
+  // initially available in the explicit areas.
+  nsGridContainerFrame::ExplicitNamedAreas* explicitAreas =
+    aFrame->GetExplicitNamedAreas();
+  if (explicitAreas) {
+    for (auto& areaInfo : *explicitAreas) {
+      if (!namesSeen.Contains(areaInfo.mName)) {
+        GridArea* area = new GridArea(this,
+                                      areaInfo.mName,
+                                      GridDeclaration::Explicit,
+                                      areaInfo.mRowStart,
+                                      areaInfo.mRowEnd,
+                                      areaInfo.mColumnStart,
+                                      areaInfo.mColumnEnd);
+        mAreas.AppendElement(area);
+      }
+    }
+  }
+
+  // Now construct the tracks and lines.
+  const ComputedGridTrackInfo* rowTrackInfo =
+    aFrame->GetComputedTemplateRows();
+  const ComputedGridLineInfo* rowLineInfo =
+    aFrame->GetComputedTemplateRowLines();
+  mRows->SetTrackInfo(rowTrackInfo);
+  mRows->SetLineInfo(rowTrackInfo, rowLineInfo, mAreas, true);
+
+  const ComputedGridTrackInfo* columnTrackInfo =
+    aFrame->GetComputedTemplateColumns();
+  const ComputedGridLineInfo* columnLineInfo =
+    aFrame->GetComputedTemplateColumnLines();
+  mCols->SetTrackInfo(columnTrackInfo);
+  mCols->SetLineInfo(columnTrackInfo, columnLineInfo, mAreas, false);
 }
 
 Grid::~Grid()
 {
 }
 
 JSObject*
 Grid::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/grid/GridDimension.cpp
+++ b/dom/grid/GridDimension.cpp
@@ -56,15 +56,17 @@ GridDimension::Tracks() const
 void
 GridDimension::SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo)
 {
   mTracks->SetTrackInfo(aTrackInfo);
 }
 
 void
 GridDimension::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
-                           const ComputedGridLineInfo* aLineInfo)
+                           const ComputedGridLineInfo* aLineInfo,
+                           const nsTArray<RefPtr<GridArea>>& aAreas,
+                           bool aIsRow)
 {
-  mLines->SetLineInfo(aTrackInfo, aLineInfo);
+  mLines->SetLineInfo(aTrackInfo, aLineInfo, aAreas, aIsRow);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/grid/GridDimension.h
+++ b/dom/grid/GridDimension.h
@@ -38,17 +38,19 @@ public:
     return mParent;
   }
 
   GridLines* Lines() const;
   GridTracks* Tracks() const;
 
   void SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo);
   void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
-                   const ComputedGridLineInfo* aLineInfo);
+                   const ComputedGridLineInfo* aLineInfo,
+                   const nsTArray<RefPtr<GridArea>>& aAreas,
+                   bool aIsRow);
 
 protected:
   RefPtr<Grid> mParent;
   RefPtr<GridLines> mLines;
   RefPtr<GridTracks> mTracks;
 };
 
 } // namespace dom
--- a/dom/grid/GridLines.cpp
+++ b/dom/grid/GridLines.cpp
@@ -59,17 +59,19 @@ GridLines::IndexedGetter(uint32_t aIndex
   if (!aFound) {
     return nullptr;
   }
   return mLines[aIndex];
 }
 
 void
 GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
-                       const ComputedGridLineInfo* aLineInfo)
+                       const ComputedGridLineInfo* aLineInfo,
+                       const nsTArray<RefPtr<GridArea>>& aAreas,
+                       bool aIsRow)
 {
   mLines.Clear();
 
   if (!aTrackInfo) {
     return;
   }
 
   uint32_t trackCount = aTrackInfo->mEndFragmentTrack -
@@ -79,34 +81,64 @@ GridLines::SetLineInfo(const ComputedGri
   // than the number of tracks.
   if (trackCount > 0) {
     double endOfLastTrack = 0.0;
     double startOfNextTrack;
 
     for (uint32_t i = aTrackInfo->mStartFragmentTrack;
          i < aTrackInfo->mEndFragmentTrack + 1;
          i++) {
+      uint32_t line1Index = i + 1;
+
       startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ?
                          aTrackInfo->mPositions[i] :
                          endOfLastTrack;
 
       GridLine* line = new GridLine(this);
       mLines.AppendElement(line);
 
       nsTArray<nsString> lineNames;
       if (aLineInfo) {
         lineNames = aLineInfo->mNames.SafeElementAt(i, nsTArray<nsString>());
       }
 
+      // Add in names from grid areas where this line is used as a boundary.
+      for (auto area : aAreas) {
+        bool haveNameToAdd = false;
+        nsAutoString nameToAdd;
+        area->GetName(nameToAdd);
+        if (aIsRow) {
+          if (area->RowStart() == line1Index) {
+            haveNameToAdd = true;
+            nameToAdd.AppendLiteral("-start");
+          } else if (area->RowEnd() == line1Index) {
+            haveNameToAdd = true;
+            nameToAdd.AppendLiteral("-end");
+          }
+        } else {
+          if (area->ColumnStart() == line1Index) {
+            haveNameToAdd = true;
+            nameToAdd.AppendLiteral("-start");
+          } else if (area->ColumnEnd() == line1Index) {
+            haveNameToAdd = true;
+            nameToAdd.AppendLiteral("-end");
+          }
+        }
+
+        if (haveNameToAdd && !lineNames.Contains(nameToAdd)) {
+          lineNames.AppendElement(nameToAdd);
+        }
+      }
+
       line->SetLineValues(
         lineNames,
         nsPresContext::AppUnitsToDoubleCSSPixels(endOfLastTrack),
         nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
                                                  endOfLastTrack),
-        i + 1,
+        line1Index,
         (
           // Implicit if there are no explicit tracks, or if the index
           // is before the first explicit track, or after
           // a track beyond the last explicit track.
           (aTrackInfo->mNumExplicitTracks == 0) ||
           (i < aTrackInfo->mNumLeadingImplicitTracks) ||
           (i > aTrackInfo->mNumLeadingImplicitTracks +
                aTrackInfo->mNumExplicitTracks) ?
--- a/dom/grid/GridLines.h
+++ b/dom/grid/GridLines.h
@@ -35,17 +35,19 @@ public:
     return mParent;
   }
 
   uint32_t Length() const;
   GridLine* Item(uint32_t aIndex);
   GridLine* IndexedGetter(uint32_t aIndex, bool& aFound);
 
   void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
-                   const ComputedGridLineInfo* aLineInfo);
+                   const ComputedGridLineInfo* aLineInfo,
+                   const nsTArray<RefPtr<GridArea>>& aAreas,
+                   bool aIsRow);
 
 protected:
   RefPtr<GridDimension> mParent;
   nsTArray<RefPtr<GridLine>> mLines;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/grid/test/chrome/test_grid_areas.html
+++ b/dom/grid/test/chrome/test_grid_areas.html
@@ -57,31 +57,78 @@ function runTests() {
 			is(grid.areas[1].name, "areaB", "Area 1 has proper name.");
 			is(grid.areas[2].name, "areaC", "Area 2 has proper name.");
 
 			// test area types
 			is(grid.areas[0].type, "explicit", "Area 0 is explicit.");
 			is(grid.areas[1].type, "explicit", "Area 1 is explicit.");
 			is(grid.areas[2].type, "explicit", "Area 2 is explicit.");
 
-			// test start and end lines
+			// test numbers of start and end lines
 			is(grid.areas[0].rowStart, 1, "Area 0 has start row line of 1.");
 			is(grid.areas[0].rowEnd, 2, "Area 0 has end row line of 2.");
 			is(grid.areas[0].columnStart, 1, "Area 0 has start column line of 1.");
 			is(grid.areas[0].columnEnd, 3, "Area 0 has end column line of 3.");
 
 			is(grid.areas[1].rowStart, 2, "Area 1 has start row line of 2.");
 			is(grid.areas[1].rowEnd, 4, "Area 1 has end row line of 4.");
 			is(grid.areas[1].columnStart, 1, "Area 1 has start column line of 1.");
 			is(grid.areas[1].columnEnd, 2, "Area 1 has end column line of 2.");
 
 			is(grid.areas[2].rowStart, 2, "Area 2 has start row line of 2.");
 			is(grid.areas[2].rowEnd, 4, "Area 2 has end row line of 4.");
 			is(grid.areas[2].columnStart, 2, "Area 2 has start column line of 2.");
 			is(grid.areas[2].columnEnd, 4, "Area 2 has end column line of 4.");
+			
+			// test names of all the row lines
+			isnot(grid.rows.lines[0].names.indexOf("areaA-start"), -1,
+				"Grid row line 1 has the name 'areaA-start'."
+			);
+			
+			isnot(grid.rows.lines[1].names.indexOf("areaA-end"), -1,
+				"Grid row line 2 has the name 'areaA-end'."
+			);
+			isnot(grid.rows.lines[1].names.indexOf("areaB-start"), -1,
+				"Grid row line 2 has the name 'areaB-start'."
+			);
+			isnot(grid.rows.lines[1].names.indexOf("areaC-start"), -1,
+				"Grid row line 2 has the name 'areaC-start'."
+			);
+			
+			is(grid.rows.lines[2].names.length, 0, "Grid row line 3 has no names.");
+			
+			isnot(grid.rows.lines[3].names.indexOf("areaB-end"), -1,
+				"Grid row line 4 has the name 'areaB-end'."
+			);
+			isnot(grid.rows.lines[3].names.indexOf("areaC-end"), -1,
+				"Grid row line 4 has the name 'areaC-end'."
+			);
+			
+			// test names of all the column lines
+			isnot(grid.cols.lines[0].names.indexOf("areaA-start"), -1,
+				"Grid column line 1 has the name 'areaA-start'."
+			);
+			isnot(grid.cols.lines[0].names.indexOf("areaB-start"), -1,
+				"Grid column line 1 has the name 'areaB-start'."
+			);
+			
+			isnot(grid.cols.lines[1].names.indexOf("areaB-end"), -1,
+				"Grid column line 2 has the name 'areaB-end'."
+			);
+			isnot(grid.cols.lines[1].names.indexOf("areaC-start"), -1,
+				"Grid column line 2 has the name 'areaC-start'."
+			);
+			
+			isnot(grid.cols.lines[2].names.indexOf("areaA-end"), -1,
+				"Grid column line 3 has the name 'areaA-end'."
+			);
+			
+			isnot(grid.cols.lines[3].names.indexOf("areaC-end"), -1,
+				"Grid column line 4 has the name 'areaC-end'."
+			);
 		}
 	}
 
 	SimpleTest.finish();
 }
 </script>
 </head>
 <body onLoad="runTests();">
--- a/dom/grid/test/chrome/test_grid_implicit.html
+++ b/dom/grid/test/chrome/test_grid_implicit.html
@@ -6,124 +6,245 @@
 <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 <style>
 body {
 	margin: 40px;
 }
 .wrapper {
 	display: grid;
 	grid-gap: 10px;
-	grid-template-columns: 100px 50px 100px;
-	grid-template-rows: 50px [areaD-start] 50px [areaD-end];
-	grid-template-areas: "areaA areaA ....."
-						 "..... areaC areaC";
 	grid-auto-columns: 20px;
 	grid-auto-rows: 20px;
 	background-color: #f00;
 }
+
+.template1 {
+	grid-template-columns: 100px 50px 100px;
+	grid-template-rows: 50px [areaD-start middle] 50px [areaD-end];
+	grid-template-areas: "areaA areaA ....."
+						 "..... areaC areaC";
+}
+
+.template2 {
+	grid-template-areas: "..... areaA ......";
+    grid-template-columns: [areaA-start] 50px 50px 50px;
+}
+
+.template3 {
+	grid-template-columns: [areaA-start areaB-end areaC-end areaD-start] 50px [areaA-end areaB-start areaC-start areaD-end];
+	grid-template-rows: [areaA-end areaB-start areaC-end] 50px [areaA-start areaB-end areaC-start];
+}
+
 .box {
 	background-color: #444;
 	color: #fff;
 }
 .a {
 	grid-area: areaA;
 }
 .b {
-	grid-row: span 2 / 2;
+	grid-row: span got-this-name-implicitly / 2;
 	grid-column: areaA-end / span 2;
 }
 .c {
 	grid-area: areaC;
 }
 .d {
 	grid-area: areaD;
 }
 </style>
 
 <script>
 'use strict';
 
 SimpleTest.waitForExplicitFinish();
 
 function runTests() {
-	var wrapper = document.getElementById("wrapper");
-	var grid = wrapper.getGridFragments()[0];
-	var boxA = document.getElementById("boxA");
-	var boxB = document.getElementById("boxB");
-	var boxC = document.getElementById("boxC");
-
+	// test the first grid wrapper
+	let wrapper = document.getElementById("wrapper1");
+	let grid = wrapper.getGridFragments()[0];
+	
 	// test column and row line counts
 	is(grid.cols.lines.length, 6,
 		"Grid.cols.lines property has length that respects implicit expansion."
 	);
 	is(grid.rows.lines.length, 4,
 		"Grid.rows.lines property has length that respects implicit expansion."
 	);
 
-	if((grid.cols.lines.length == 6) &&
-	   (grid.rows.lines.length == 4)) {
+	if ((grid.cols.lines.length == 6) &&
+	    (grid.rows.lines.length == 4)) {
 
 		// test explicit / implicit lines
 		is(grid.cols.lines[0].type, "explicit", "Grid column line 1 is explicit.");
 		is(grid.cols.lines[4].type, "implicit", "Grid column line 5 is implicit.");
 		is(grid.cols.lines[5].type, "implicit", "Grid column line 6 is implicit.");
-
+		
 		is(grid.rows.lines[0].type, "implicit", "Grid row line 1 is implicit.");
 		is(grid.rows.lines[1].type, "explicit", "Grid row line 2 is explicit.");
 		is(grid.rows.lines[3].type, "explicit", "Grid row line 4 is explicit.");
+		
+		// test that row line 1 gets the name forced on it by placement of item B
+		todo_isnot(grid.rows.lines[0].names.indexOf("got-this-name-implicitly"), -1,
+			"Grid row line 1 has the name 'got-this-name-implicitly'."
+		);
+		
+		// test that row line 3 gets its explicit name
+		isnot(grid.rows.lines[2].names.indexOf("middle"), -1,
+			"Grid row line 3 has the name 'middle'."
+		);
+		
+		// test the names of the implicit column lines that were created for area 'areaD'
+		isnot(grid.cols.lines[4].names.indexOf("areaD-start"), -1,
+			"Grid column line 5 has the name 'areaD-start'."
+		);
+		isnot(grid.cols.lines[5].names.indexOf("areaD-end"), -1,
+			"Grid column line 6 has the name 'areaD-end'."
+		);
 	}
 
 	// test column and row track counts
 	is(grid.cols.tracks.length, 5,
 		"Grid.cols.tracks property has length that respects implicit expansion."
 	);
 	is(grid.rows.tracks.length, 3,
 		"Grid.rows.tracks property has length that respects implicit expansion."
 	);
 
-	if((grid.cols.tracks.length == 5) &&
-	   (grid.rows.tracks.length == 3)) {
+	if ((grid.cols.tracks.length == 5) &&
+	    (grid.rows.tracks.length == 3)) {
 
 		// test explicit / implicit tracks
 		is(grid.cols.tracks[0].type, "explicit", "Grid column track 1 is explicit.");
 		is(grid.cols.tracks[3].type, "implicit", "Grid column track 4 is implicit.");
 		is(grid.cols.tracks[4].type, "implicit", "Grid column track 5 is implicit.");
 
 		is(grid.rows.tracks[0].type, "implicit", "Grid row track 1 is implicit.");
 		is(grid.rows.tracks[1].type, "explicit", "Grid row track 2 is explicit.");
 		is(grid.rows.tracks[2].type, "explicit", "Grid row track 3 is explicit.");
 	}
 
 	// test area count
 	is(grid.areas.length, 3,
 		"Grid.areas property has length that respects implicit expansion."
 	);
 
-	for(var i = 0; i < grid.areas.length; i++) {
+	for (var i = 0; i < grid.areas.length; i++) {
 		var area = grid.areas[i];
-		if(area.name == "areaD") {
+		if (area.name == "areaD") {
+			is(area.type, "implicit", area.name + " is implicit.");
+
+			// test lines of implicit areas
+			is(area.rowStart, 3, area.name + " has start row line of 3.");
+			is(area.rowEnd, 4, area.name + " has end row line of 4.");
+			is(area.columnStart, 5, area.name + " has start column line of 5.");
+			is(area.columnEnd, 6, area.name + " has end column line of 6.");
+		} else {
+			is(area.type, "explicit", area.name + " is explicit.");
+		}
+	}
+	
+	
+	// test the second grid wrapper
+	wrapper = document.getElementById("wrapper2");
+	grid = wrapper.getGridFragments()[0];
+	
+	// test column and row line counts
+	is(grid.cols.lines.length, 4,
+		"Grid.cols.lines property doesn't expand due to an explicit line declaration."
+	);
+	is(grid.rows.lines.length, 2,
+		"Grid.rows.lines property has length that respects implicit expansion."
+	);
+	
+	// test area count
+	is(grid.areas.length, 1,
+		"Grid.areas property has length that respects implicit expansion."
+	);
+	
+	for (var i = 0; i < grid.areas.length; i++) {
+		var area = grid.areas[i];
+		if (area.name == "areaA") {
 			is(area.type, "implicit", area.name + " is implicit.");
 
 			// test lines of implicit areas
-			todo_is(area.rowStart, 2, area.name + " has start row line of 2.");
-			todo_is(area.rowEnd, 3, area.name + " has end row line of 3.");
-			todo_is(area.columnStart, 4, area.name + " has start column line of 4.");
-			todo_is(area.columnEnd, 5, area.name + " has end column line of 5.");
-		} else {
-			is(area.type, "explicit", area.name + " is explicit.");
+			is(area.rowStart, 1, area.name + " has start row line of 1.");
+			is(area.rowEnd, 2, area.name + " has end row line of 2.");
+			is(area.columnStart, 1, area.name + " has start column line of 1.");
+			is(area.columnEnd, 3, area.name + " has end column line of 3.");
+		}
+	}
+	
+	
+	// test the third grid wrapper
+	wrapper = document.getElementById("wrapper3");
+	grid = wrapper.getGridFragments()[0];
+	
+	// test column and row line counts
+	is(grid.cols.lines.length, 2,
+		"Grid.cols.lines property doesn't expand due to an explicit line declaration."
+	);
+	is(grid.rows.lines.length, 2,
+		"Grid.rows.lines property doesn't expand due to an explicit line declaration."
+	);
+	
+	if (grid.cols.lines.length == 2 && grid.rows.lines.length == 2) {
+		// check that areaC gets both the explicit line names and the implicit line names
+		isnot(grid.cols.lines[0].names.indexOf("areaC-start"), -1,
+			"Grid row line 1 has the name 'areaC-start'."
+		);
+		
+		isnot(grid.cols.lines[0].names.indexOf("areaC-end"), -1,
+			"Grid row line 1 has the name 'areaC-end'."
+		);
+		
+		isnot(grid.cols.lines[1].names.indexOf("areaC-start"), -1,
+			"Grid row line 2 has the name 'areaC-start'."
+		);
+		
+		isnot(grid.cols.lines[1].names.indexOf("areaC-end"), -1,
+			"Grid row line 2 has the name 'areaC-end'."
+		);
+	}
+	
+	// test area count
+	is(grid.areas.length, 4,
+		"Grid.areas property reports 4 areas."
+	);
+	
+	for (var i = 0; i < grid.areas.length; i++) {
+		var area = grid.areas[i];
+		if (area.name == "areaC") {
+			// test lines of implicit area
+			is(area.rowStart, 1, area.name + " has start row line of 1.");
+			is(area.rowEnd, 2, area.name + " has end row line of 2.");
+			is(area.columnStart, 1, area.name + " has start column line of 1.");
+			is(area.columnEnd, 2, area.name + " has end column line of 2.");
 		}
 	}
 
 	SimpleTest.finish();
 }
 </script>
 </head>
 <body onLoad="runTests();">
 
-	<div id="wrapper" class="wrapper">
+	<div id="wrapper1" class="wrapper template1">
 		<div id="boxA" class="box a">A</div>
 		<div id="boxB" class="box b">B</div>
 		<div id="boxC" class="box c">C</div>
 		<div id="boxD" class="box d">D</div>
 	</div>
+	
+	<br/>
+	
+	<div id="wrapper2" class="wrapper template2">
+		<div id="boxA" class="box a">A</div>
+	</div>
+	
+	<br/>
+	
+	<div id="wrapper3" class="wrapper template3">
+		<div id="boxC" class="box c">C</div>
+	</div>
 
 </body>
 </html>
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -248,28 +248,28 @@ public:
   {
     nsTArray<OwningFileOrDirectory> array;
     for (uint32_t i = 0; i < aFiles.Length(); ++i) {
       OwningFileOrDirectory* element = array.AppendElement();
       element->SetAsFile() = aFiles[i];
     }
 
     mInputElement->SetFilesOrDirectories(array, true);
-    NS_WARN_IF(NS_FAILED(DispatchEvents()));
+    Unused << NS_WARN_IF(NS_FAILED(DispatchEvents()));
   }
 
   nsresult
   DispatchEvents()
   {
     nsresult rv = NS_OK;
     rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
                                               static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),
                                               NS_LITERAL_STRING("input"), true,
                                               false);
-    NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed");
 
     rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
                                               static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),
                                               NS_LITERAL_STRING("change"), true,
                                               false);
 
     return rv;
   }
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -231,17 +231,17 @@ public:
 
   Node* mStack;
   int32_t mStackSize;
   int32_t mStackPos;
 };
 
 nsresult
 NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
-                  FromParser aFromParser, nsAString* aIs)
+                  FromParser aFromParser, const nsAString* aIs)
 {
   *aResult = nullptr;
 
   RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
 
   nsIParserService* parserService = nsContentUtils::GetParserService();
   if (!parserService)
     return NS_ERROR_OUT_OF_MEMORY;
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -91,16 +91,17 @@ support-files =
   unit/test_rename_objectStore.js
   unit/test_rename_objectStore_errors.js
   unit/test_request_readyState.js
   unit/test_setVersion.js
   unit/test_setVersion_abort.js
   unit/test_setVersion_events.js
   unit/test_setVersion_exclusion.js
   unit/test_setVersion_throw.js
+  unit/test_storage_manager_estimate.js
   unit/test_success_events_after_abort.js
   unit/test_table_locks.js
   unit/test_table_rollback.js
   unit/test_temporary_storage.js
   unit/test_traffic_jam.js
   unit/test_transaction_abort.js
   unit/test_transaction_abort_hang.js
   unit/test_transaction_duplicate_store_names.js
@@ -350,16 +351,18 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_setVersion_abort.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_setVersion_events.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_setVersion_exclusion.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_setVersion_throw.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+[test_storage_manager_estimate.html]
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_success_events_after_abort.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_table_locks.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_table_rollback.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_third_party.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_storage_manager_estimate.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 Test for StorageManager</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_storage_manager_estimate.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_storage_manager_estimate.js
@@ -0,0 +1,56 @@
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const name = this.window ? window.location.pathname :
+	       "test_storage_manager_estimate.js";
+  const objectStoreName = "storagesManager";
+  const arraySize = 1e6;
+
+  ok('estimate' in navigator.storage, 'Has estimate function');
+  is(typeof navigator.storage.estimate, 'function', 'estimate is function');
+  ok(navigator.storage.estimate() instanceof Promise,
+     'estimate() method exists and returns a Promise');
+
+  navigator.storage.estimate().then(estimation => {
+    testGenerator.send(estimation.usage);
+  });
+
+  let before = yield undefined;
+
+  let request = indexedDB.open(name, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = continueToNextStep;
+  let event = yield undefined;
+
+  let db = event.target.result;
+  db.onerror = errorHandler;
+
+  let objectStore = db.createObjectStore(objectStoreName, { });
+  yield undefined;
+
+  navigator.storage.estimate().then(estimation => {
+    testGenerator.send(estimation.usage);
+  });
+  let usageAfterCreate = yield undefined;
+  ok(usageAfterCreate > before, 'estimated usage must increase after createObjectStore');
+
+  let txn = db.transaction(objectStoreName, "readwrite");
+  objectStore = txn.objectStore(objectStoreName);
+  objectStore.put(new Uint8Array(arraySize), 'k');
+  txn.oncomplete = continueToNextStep;
+  txn.onabort = errorHandler;
+  txn.onerror = errorHandler;
+  event = yield undefined;
+
+  navigator.storage.estimate().then(estimation => {
+    testGenerator.send(estimation.usage);
+  });
+  let usageAfterPut = yield undefined;
+  ok(usageAfterPut > usageAfterCreate, 'estimated usage must increase after putting large object');
+  db.close();
+
+  finishTest();
+  yield undefined;
+}
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -15,16 +15,17 @@
 #include "GeckoProfiler.h"
 #include "TabChild.h"
 #include "HandlerServiceChild.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
+#include "mozilla/Unused.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
@@ -508,16 +509,17 @@ private:
 NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback)
 
 ContentChild* ContentChild::sSingleton;
 
 ContentChild::ContentChild()
  : mID(uint64_t(-1))
  , mCanOverrideProcessName(true)
  , mIsAlive(true)
+ , mShuttingDown(false)
 {
   // This process is a content process, so it's clearly running in
   // multiprocess mode!
   nsDebugImpl::SetMultiprocessMode("Child");
 }
 
 ContentChild::~ContentChild()
 {
@@ -858,16 +860,22 @@ ContentChild::GetProcessName(nsAString& 
 }
 
 bool
 ContentChild::IsAlive() const
 {
   return mIsAlive;
 }
 
+bool
+ContentChild::IsShuttingDown() const
+{
+  return mShuttingDown;
+}
+
 void
 ContentChild::GetProcessName(nsACString& aName) const
 {
   aName.Assign(NS_ConvertUTF16toUTF8(mProcessName));
 }
 
 /* static */ void
 ContentChild::AppendProcessId(nsACString& aName)
@@ -1040,29 +1048,29 @@ ContentChild::RecvPMemoryReportRequestCo
   PMemoryReportRequestChild* aChild,
   const uint32_t& aGeneration,
   const bool& aAnonymize,
   const bool& aMinimizeMemoryUsage,
   const MaybeFileDesc& aDMDFile)
 {
   MemoryReportRequestChild *actor =
     static_cast<MemoryReportRequestChild*>(aChild);
-  nsresult rv;
+  DebugOnly<nsresult> rv;
 
   if (aMinimizeMemoryUsage) {
     nsCOMPtr<nsIMemoryReporterManager> mgr =
       do_GetService("@mozilla.org/memory-reporter-manager;1");
     rv = mgr->MinimizeMemoryUsage(actor);
     // mgr will eventually call actor->Run()
   } else {
     rv = actor->Run();
   }
 
   // Bug 1295622: don't kill the process just because this failed.
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "actor operation failed");
   return true;
 }
 
 NS_IMETHODIMP MemoryReportRequestChild::Run()
 {
   ContentChild *child = static_cast<ContentChild*>(Manager());
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
@@ -1077,17 +1085,18 @@ NS_IMETHODIMP MemoryReportRequestChild::
     new HandleReportCallback(this, process);
   RefPtr<FinishReportingCallback> finishReporting =
     new FinishReportingCallback(this);
 
   nsresult rv =
     mgr->GetReportsForThisProcessExtended(handleReport, nullptr, mAnonymize,
                                           FileDescriptorToFILE(mDMDFile, "wb"),
                                           finishReporting, nullptr);
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                       "GetReportsForThisProcessExtended failed");
   return rv;
 }
 
 bool
 ContentChild::DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor)
 {
   static_cast<MemoryReportRequestChild*>(actor)->Release();
   return true;
@@ -1598,35 +1607,35 @@ ContentChild::DeallocPFlyWebPublishedSer
 }
 
 bool
 ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
                                                      const nsString& aSessionId)
 {
   nsCOMPtr<nsIDocShell> docShell =
     do_GetInterface(static_cast<TabChild*>(aIframe)->WebNavigation());
-  NS_WARN_IF(!docShell);
+  NS_WARNING_ASSERTION(docShell, "WebNavigation failed");
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
-  NS_WARN_IF(!service);
-
-  NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->MonitorResponderLoading(aSessionId, docShell)));
+  NS_WARNING_ASSERTION(service, "presentation service is missing");
+
+  Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->MonitorResponderLoading(aSessionId, docShell)));
 
   return true;
 }
 
 bool
 ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
 {
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
-  NS_WARN_IF(!service);
-
-  NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER)));
+  NS_WARNING_ASSERTION(service, "presentation service is missing");
+
+  Unused << NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER)));
 
   return true;
 }
 
 bool
 ContentChild::RecvNotifyGMPsChanged()
 {
   GMPDecoderModule::UpdateUsableCodecs();
@@ -2983,16 +2992,18 @@ ContentChild::RecvShutdown()
       // time (100ms) in the hopes that the event loop will have finished by
       // then.
       MessageLoop::current()->PostDelayedTask(
         NewRunnableMethod(this, &ContentChild::RecvShutdown), 100);
       return true;
     }
   }
 
+  mShuttingDown = true;
+
   if (mPolicy) {
     mPolicy->Deactivate();
     mPolicy = nullptr;
   }
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->NotifyObservers(static_cast<nsIContentChild*>(this),
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -111,16 +111,18 @@ public:
   void SetProcessName(const nsAString& aName, bool aDontOverride = false);
 
   void GetProcessName(nsAString& aName) const;
 
   void GetProcessName(nsACString& aName) const;
 
   bool IsAlive() const;
 
+  bool IsShuttingDown() const;
+
   static void AppendProcessId(nsACString& aName);
 
   ContentBridgeParent* GetLastBridge()
   {
     MOZ_ASSERT(mLastBridge);
     ContentBridgeParent* parent = mLastBridge;
     mLastBridge = nullptr;
     return parent;
@@ -677,17 +679,19 @@ private:
   static ContentChild* sSingleton;
 
   nsCOMPtr<nsIDomainPolicy> mPolicy;
   nsCOMPtr<nsITimer> mForceKillTimer;
 
   // Hashtable to keep track of the pending GetFilesHelper objects.
   // This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
   // received.
- nsRefPtrHashtable<nsIDHashKey, GetFilesHelperChild> mGetFilesPendingRequests;
+  nsRefPtrHashtable<nsIDHashKey, GetFilesHelperChild> mGetFilesPendingRequests;
+
+  bool mShuttingDown;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 uint64_t
 NextWindowID();
 
 } // namespace dom
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -353,17 +353,17 @@ private:
   }
 };
 
 MemoryReportRequestParent::MemoryReportRequestParent(uint32_t aGeneration)
   : mGeneration(aGeneration)
 {
   MOZ_COUNT_CTOR(MemoryReportRequestParent);
   mReporterManager = nsMemoryReporterManager::GetOrCreate();
-  NS_WARN_IF(!mReporterManager);
+  NS_WARNING_ASSERTION(mReporterManager, "GetOrCreate failed");
 }
 
 bool
 MemoryReportRequestParent::RecvReport(const MemoryReport& aReport)
 {
   if (mReporterManager) {
     mReporterManager->HandleChildReport(mGeneration, aReport);
   }
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -44,20 +44,20 @@ SetTmpEnvironmentVariable(nsIFile* aValu
   // Save the TMP environment variable so that is is picked up by GetTempPath().
   // Note that we specifically write to the TMP variable, as that is the first
   // variable that is checked by GetTempPath() to determine its output.
   nsAutoString fullTmpPath;
   nsresult rv = aValue->GetPath(fullTmpPath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
-  NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get()));
+  Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get()));
   // We also set TEMP in case there is naughty third-party code that is
   // referencing the environment variable directly.
-  NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get()));
+  Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get()));
 }
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
 static bool
 IsSandboxTempDirRequired()
 {
   // On OSX, use the sandbox-writable temp when the pref level >= 1.
@@ -67,17 +67,17 @@ IsSandboxTempDirRequired()
 static void
 SetTmpEnvironmentVariable(nsIFile* aValue)
 {
   nsAutoCString fullTmpPath;
   nsresult rv = aValue->GetNativePath(fullTmpPath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
-  NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0);
+  Unused << NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0);
 }
 #endif
 
 #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
 static void
 SetUpSandboxEnvironment()
 {
   MOZ_ASSERT(nsDirectoryService::gService,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1978,18 +1978,19 @@ TabParent::RecvOnEventNeedingAckHandled(
   mContentCache.OnEventNeedingAckHandled(widget, aMessage);
   return true;
 }
 
 void
 TabParent::HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
                                          bool aIsConsumed)
 {
-  bool ok = SendHandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
-  NS_WARN_IF(!ok);
+  DebugOnly<bool> ok =
+    SendHandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
+  NS_WARNING_ASSERTION(ok, "SendHandledWindowedPluginKeyEvent failed");
 }
 
 bool
 TabParent::RecvOnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (NS_WARN_IF(!widget)) {
     // Notifies the plugin process of the key event being not consumed by us.
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -525,17 +525,18 @@ AudioStream::GetUnprocessed(AudioBufferW
     auto timeStretcher = mTimeStretcher;
     aWriter.Write([timeStretcher] (AudioDataValue* aPtr, uint32_t aFrames) {
       return timeStretcher->receiveSamples(aPtr, aFrames);
     }, aWriter.Available());
 
     // TODO: There might be still unprocessed samples in the stretcher.
     // We should either remove or flush them so they won't be in the output
     // next time we switch a playback rate other than 1.0.
-    NS_WARN_IF(mTimeStretcher->numUnprocessedSamples() > 0);
+    NS_WARNING_ASSERTION(
+      mTimeStretcher->numUnprocessedSamples() == 0, "no samples");
   }
 
   while (aWriter.Available() > 0) {
     UniquePtr<Chunk> c = mDataSource.PopFrames(aWriter.Available());
     if (c->Frames() == 0) {
       break;
     }
     MOZ_ASSERT(c->Frames() <= aWriter.Available());
--- a/dom/media/MediaSegment.h
+++ b/dom/media/MediaSegment.h
@@ -396,16 +396,24 @@ public:
     return amount;
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
+  Chunk* GetLastChunk()
+  {
+    if (mChunks.IsEmpty()) {
+      return nullptr;
+    }
+    return &mChunks[mChunks.Length() - 1];
+  }
+
 protected:
   explicit MediaSegmentBase(Type aType) : MediaSegment(aType) {}
 
   /**
    * Appends the contents of aSource to this segment, clearing aSource.
    */
   void AppendFromInternal(MediaSegmentBase<C, Chunk>* aSource)
   {
@@ -443,24 +451,16 @@ protected:
   {
     MOZ_ASSERT(aDuration >= 0);
     Chunk* c = mChunks.AppendElement();
     c->mDuration = aDuration;
     mDuration += aDuration;
     return c;
   }
 
-  Chunk* GetLastChunk()
-  {
-    if (mChunks.IsEmpty()) {
-      return nullptr;
-    }
-    return &mChunks[mChunks.Length() - 1];
-  }
-
   void RemoveLeading(StreamTime aDuration, uint32_t aStartIndex)
   {
     NS_ASSERTION(aDuration >= 0, "Can't remove negative duration");
     StreamTime t = aDuration;
     uint32_t chunksToRemove = 0;
     for (uint32_t i = aStartIndex; i < mChunks.Length() && t > 0; ++i) {
       Chunk* c = &mChunks[i];
       if (c->GetDuration() > t) {
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2606,17 +2606,17 @@ MediaStream::AddMainThreadListener(MainT
 
   private:
     ~NotifyRunnable() {}
 
     RefPtr<MediaStream> mStream;
   };
 
   nsCOMPtr<nsIRunnable> runnable = new NotifyRunnable(this);
-  NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget())));
+  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget())));
 }
 
 SourceMediaStream::SourceMediaStream() :
   MediaStream(),
   mMutex("mozilla::media::SourceMediaStream"),
   mUpdateKnownTracksTime(0),
   mPullEnabled(false),
   mUpdateFinished(false),
@@ -2884,17 +2884,35 @@ SourceMediaStream::AddDirectTrackListene
     // The track might be removed from mUpdateTrack but still exist in
     // mTracks.
     auto streamTrack = FindTrack(aTrackID);
     bool foundTrack = !!streamTrack;
     if (foundTrack) {
       MediaStreamVideoSink* videoSink = listener->AsMediaStreamVideoSink();
       // Re-send missed VideoSegment to new added MediaStreamVideoSink.
       if (streamTrack->GetType() == MediaSegment::VIDEO && videoSink) {
-        videoSink->SetCurrentFrames(*(static_cast<VideoSegment*>(streamTrack->GetSegment())));
+        VideoSegment videoSegment;
+        if (mTracks.GetForgottenDuration() < streamTrack->GetSegment()->GetDuration()) {
+          videoSegment.AppendSlice(*streamTrack->GetSegment(),
+                                   mTracks.GetForgottenDuration(),
+                                   streamTrack->GetSegment()->GetDuration());
+        } else {
+          VideoSegment* streamTrackSegment = static_cast<VideoSegment*>(streamTrack->GetSegment());
+          VideoChunk* lastChunk = streamTrackSegment->GetLastChunk();
+          if (lastChunk) {
+            StreamTime startTime = streamTrackSegment->GetDuration() - lastChunk->GetDuration();
+            videoSegment.AppendSlice(*streamTrackSegment,
+                                     startTime,
+                                     streamTrackSegment->GetDuration());
+          }
+        }
+        if (found) {
+          videoSegment.AppendSlice(*data->mData, 0, data->mData->GetDuration());
+        }
+        videoSink->SetCurrentFrames(videoSegment);
       }
     }
 
     if (found && (isAudio || isVideo)) {
       for (auto entry : mDirectTrackListeners) {
         if (entry.mListener == listener &&
             (entry.mTrackID == TRACK_ANY || entry.mTrackID == aTrackID)) {
           listener->NotifyDirectListenerInstalled(
--- a/dom/media/TextTrackList.cpp
+++ b/dom/media/TextTrackList.cpp
@@ -183,17 +183,17 @@ TextTrackList::CreateAndDispatchTrackEve
   RefPtr<TrackEvent> event =
     TrackEvent::Constructor(this, aEventName, eventInit);
 
   // Dispatch the TrackEvent asynchronously.
   rv = thread->Dispatch(do_AddRef(new TrackEventRunner(this, event)),
                         NS_DISPATCH_NORMAL);
 
   // If we are shutting down this can file but it's still ok.
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Dispatch failed");
 }
 
 HTMLMediaElement*
 TextTrackList::GetMediaElement()
 {
   if (mTextTrackManager) {
     return mTextTrackManager->mMediaElement;
   }
--- a/dom/media/VideoSegment.h
+++ b/dom/media/VideoSegment.h
@@ -89,17 +89,17 @@ struct VideoChunk {
     // - mFrame
     return 0;
   }
 
   PrincipalHandle GetPrincipalHandle() const { return mFrame.GetPrincipalHandle(); }
 
   StreamTime mDuration;
   VideoFrame mFrame;
-  mozilla::TimeStamp mTimeStamp;
+  TimeStamp mTimeStamp;
 };
 
 class VideoSegment : public MediaSegmentBase<VideoSegment, VideoChunk> {
 public:
   typedef mozilla::layers::Image Image;
   typedef mozilla::gfx::IntSize IntSize;
 
   VideoSegment();
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -274,16 +274,21 @@ D3D9DXVA2Manager::Init(nsACString& aFail
     return E_FAIL;
   }
 
   // Create D3D9Ex.
   HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
   NS_ENSURE_TRUE(d3d9lib, E_FAIL);
   decltype(Direct3DCreate9Ex)* d3d9Create =
     (decltype(Direct3DCreate9Ex)*) GetProcAddress(d3d9lib, "Direct3DCreate9Ex");
+  if (!d3d9Create) {
+    NS_WARNING("Couldn't find Direct3DCreate9Ex symbol in d3d9.dll");
+    aFailureReason.AssignLiteral("Couldn't find Direct3DCreate9Ex symbol in d3d9.dll");
+    return E_FAIL;
+  }
   RefPtr<IDirect3D9Ex> d3d9Ex;
   HRESULT hr = d3d9Create(D3D_SDK_VERSION, getter_AddRefs(d3d9Ex));
   if (!d3d9Ex) {
     NS_WARNING("Direct3DCreate9 failed");
     aFailureReason.AssignLiteral("Direct3DCreate9 failed");
     return E_FAIL;
   }
 
--- a/dom/media/webrtc/MediaTrackConstraints.h
+++ b/dom/media/webrtc/MediaTrackConstraints.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/MediaTrackConstraintSetBinding.h"
 #include "mozilla/dom/MediaTrackSupportedConstraintsBinding.h"
 
 #include <map>
 #include <set>
+#include <vector>
 
 namespace mozilla {
 
 template<class EnumValuesStrings, class Enum>
 static const char* EnumToASCII(const EnumValuesStrings& aStrings, Enum aValue) {
   return aStrings[uint32_t(aValue)].value;
 }
 
--- a/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h
+++ b/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_mobileconnection_MobileConnectionIPCSerialiser_h
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/dom/mobileconnection/MobileCallForwardingOptions.h"
 #include "mozilla/dom/MobileCellInfo.h"
 #include "mozilla/dom/MobileConnectionInfo.h"
 #include "mozilla/dom/MobileNetworkInfo.h"
 #include "mozilla/dom/MozMobileConnectionBinding.h"
+#include "mozilla/dom/ScriptSettings.h"
 
 using mozilla::AutoJSContext;
 using mozilla::dom::mobileconnection::MobileCallForwardingOptions;
 using mozilla::dom::MobileNetworkInfo;
 using mozilla::dom::MobileCellInfo;
 using mozilla::dom::MobileConnectionInfo;
 
 typedef nsIMobileCellInfo* nsMobileCellInfo;
--- a/dom/mobilemessage/MmsMessage.cpp
+++ b/dom/mobilemessage/MmsMessage.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MmsMessage.h"
 
 #include "MmsMessageInternal.h"
 #include "mozilla/dom/MmsMessageBinding.h"
+#include "nsPIDOMWindow.h"
 
 using namespace mozilla::dom::mobilemessage;
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MmsMessage, mWindow, mMessage)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MmsMessage)
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -763,17 +763,17 @@ TCPSocket::MaybeReportErrorAndCloseIfOpe
           errName.AssignLiteral("NetworkInterruptError");
           break;
         default:
           errName.AssignLiteral("NetworkError");
           break;
       }
     }
 
-    NS_WARN_IF(NS_FAILED(FireErrorEvent(errName, errorType)));
+    Unused << NS_WARN_IF(NS_FAILED(FireErrorEvent(errName, errorType)));
   }
 
   return FireEvent(NS_LITERAL_STRING("close"));
 }
 
 void
 TCPSocket::Close()
 {
--- a/dom/network/UDPSocket.cpp
+++ b/dom/network/UDPSocket.cpp
@@ -225,25 +225,25 @@ UDPSocket::JoinMulticastGroup(const nsAS
   MOZ_ASSERT(mSocket || mSocketChild);
 
   NS_ConvertUTF16toUTF8 address(aMulticastGroupAddress);
 
   if (mSocket) {
     MOZ_ASSERT(!mSocketChild);
 
     aRv = mSocket->JoinMulticast(address, EmptyCString());
-    NS_WARN_IF(aRv.Failed());
+    NS_WARNING_ASSERTION(!aRv.Failed(), "JoinMulticast failed");
 
     return;
   }
 
   MOZ_ASSERT(mSocketChild);
 
   aRv = mSocketChild->JoinMulticast(address, EmptyCString());
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "JoinMulticast failed");
 }
 
 void
 UDPSocket::LeaveMulticastGroup(const nsAString& aMulticastGroupAddress,
                                ErrorResult& aRv)
 {
   if (mReadyState == SocketReadyState::Closed) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
@@ -258,24 +258,24 @@ UDPSocket::LeaveMulticastGroup(const nsA
 
   MOZ_ASSERT(mSocket || mSocketChild);
 
   nsCString address = NS_ConvertUTF16toUTF8(aMulticastGroupAddress);
   if (mSocket) {
     MOZ_ASSERT(!mSocketChild);
 
     aRv = mSocket->LeaveMulticast(address, EmptyCString());
-    NS_WARN_IF(aRv.Failed());
+    NS_WARNING_ASSERTION(!aRv.Failed(), "mSocket->LeaveMulticast failed");
     return;
   }
 
   MOZ_ASSERT(mSocketChild);
 
   aRv = mSocketChild->LeaveMulticast(address, EmptyCString());
-  NS_WARN_IF(aRv.Failed());
+  NS_WARNING_ASSERTION(!aRv.Failed(), "mSocketChild->LeaveMulticast failed");
 }
 
 nsresult
 UDPSocket::DoPendingMcastCommand()
 {
   MOZ_ASSERT(mReadyState == SocketReadyState::Open, "Multicast command can only be executed after socket opened");
 
   for (uint32_t i = 0; i < mPendingMcastCommands.Length(); ++i) {
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -288,42 +288,44 @@ static void CheckSTSThread()
 
 
 // Proxy the Connect() request to the STS thread, since it may block and
 // should be done there.
 bool
 UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo)
 {
   nsCOMPtr<nsIEventTarget> thread(NS_GetCurrentThread());
-  NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable(
-                                                  this,
-                                                  &UDPSocketParent::DoConnect,
-                                                  mSocket,
-                                                  thread,
-                                                  aAddressInfo),
-                                                NS_DISPATCH_NORMAL)));
+  Unused <<
+    NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable(
+                                                    this,
+                                                    &UDPSocketParent::DoConnect,
+                                                    mSocket,
+                                                    thread,
+                                                    aAddressInfo),
+                                                  NS_DISPATCH_NORMAL)));
   return true;
 }
 
 void
 UDPSocketParent::DoSendConnectResponse(const UDPAddressInfo& aAddressInfo)
 {
   // can't use directly with WrapRunnable due to warnings
   mozilla::Unused << SendCallbackConnected(aAddressInfo);
 }
 
 void
 UDPSocketParent::SendConnectResponse(nsIEventTarget *aThread,
                                      const UDPAddressInfo& aAddressInfo)
 {
-  NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
-                                           this,
-                                           &UDPSocketParent::DoSendConnectResponse,
-                                           aAddressInfo),
-                                         NS_DISPATCH_NORMAL)));
+  Unused <<
+    NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
+                                             this,
+                                             &UDPSocketParent::DoSendConnectResponse,
+                                             aAddressInfo),
+                                           NS_DISPATCH_NORMAL)));
 }
 
 // Runs on STS thread
 void
 UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
                            nsCOMPtr<nsIEventTarget>& aReturnThread,
                            const UDPAddressInfo& aAddressInfo)
 {
@@ -618,17 +620,18 @@ UDPSocketParent::FireInternalError(uint3
                                        NS_LITERAL_CSTRING(__FILE__), aLineNo);
 }
 
 void
 UDPSocketParent::SendInternalError(nsIEventTarget *aThread,
                                    uint32_t aLineNo)
 {
   UDPSOCKET_LOG(("SendInternalError: %u", aLineNo));
-  NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
-                                           this,
-                                           &UDPSocketParent::FireInternalError,
-                                           aLineNo),
-                                         NS_DISPATCH_NORMAL)));
+  Unused <<
+    NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
+                                             this,
+                                             &UDPSocketParent::FireInternalError,
+                                             aLineNo),
+                                           NS_DISPATCH_NORMAL)));
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1802,17 +1802,17 @@ nsNPAPIPluginInstance::GetOrCreateAudioC
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted)
 {
   // We just support mute/unmute
   nsresult rv = SetMuted(aMuted);
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
   return rv;
 }
 
 NS_IMETHODIMP
 nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend)
 {
   // It doesn't support suspended, so we just do something like mute/unmute.
   WindowVolumeChanged(1.0, /* useless */
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -980,19 +980,19 @@ nsPluginInstanceOwner::RequestCommitOrCa
 void
 nsPluginInstanceOwner::HandledWindowedPluginKeyEvent(
                          const NativeEventData& aKeyEventData,
                          bool aIsConsumed)
 {
   if (NS_WARN_IF(!mInstance)) {
     return;
   }
-  nsresult rv =
+  DebugOnly<nsresult> rv =
     mInstance->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
-  NS_WARN_IF(NS_FAILED(rv));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HandledWindowedPluginKeyEvent fail");
 }
 
 void
 nsPluginInstanceOwner::OnWindowedPluginKeyEvent(
                          const NativeEventData& aKeyEventData)
 {
   if (NS_WARN_IF(!mPluginFrame)) {
     // Notifies the plugin process of the key event being not consumed by us.
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -1672,17 +1672,18 @@ PluginInstanceChild::PluginWindowProcInt
             }
             break;
         }
 
         case WM_SETFOCUS:
             // If this gets focus, ensure that there is no pending key events.
             // Even if there were, we should ignore them for performance reason.
             // Although, such case shouldn't occur.
-            NS_WARN_IF(self->mPostingKeyEvents > 0);
+            NS_WARNING_ASSERTION(self->mPostingKeyEvents == 0,
+                                 "pending events");
             self->mPostingKeyEvents = 0;
             self->mLastKeyEventConsumed = false;
             break;
 
         case WM_KEYDOWN:
         case WM_SYSKEYDOWN:
         case WM_KEYUP:
         case WM_SYSKEYUP:
--- a/dom/plugins/ipc/PluginWidgetChild.cpp
+++ b/dom/plugins/ipc/PluginWidgetChild.cpp
@@ -38,17 +38,17 @@ PluginWidgetChild::~PluginWidgetChild()
 bool
 PluginWidgetChild::RecvSetScrollCaptureId(const uint64_t& aScrollCaptureId,
                                           const uintptr_t& aPluginInstanceId)
 {
 #if defined(XP_WIN)
   PluginInstanceParent* instance =
     PluginInstanceParent::LookupPluginInstanceByID(aPluginInstanceId);
   if (instance) {
-    NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(aScrollCaptureId)));
+    Unused << NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(aScrollCaptureId)));
   }
 
   return true;
 #else
   MOZ_ASSERT_UNREACHABLE(
     "PluginWidgetChild::RecvSetScrollCaptureId calls not expected.");
   return false;
 #endif
--- a/dom/presentation/PresentationAvailability.cpp
+++ b/dom/presentation/PresentationAvailability.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PresentationAvailability.h"
 
 #include "mozilla/dom/PresentationAvailabilityBinding.h"
 #include "mozilla/dom/Promise.h"
+#include "mozilla/Unused.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPresentationDeviceManager.h"
 #include "nsIPresentationService.h"
 #include "nsServiceManagerUtils.h"
 #include "PresentationLog.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -95,18 +96,18 @@ void PresentationAvailability::Shutdown(
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return;
   }
 
-  nsresult rv = service->UnregisterAvailabilityListener(this);
-  NS_WARN_IF(NS_FAILED(rv));
+  Unused <<
+    NS_WARN_IF(NS_FAILED(service->UnregisterAvailabilityListener(this)));
 }
 
 /* virtual */ void
 PresentationAvailability::DisconnectFromOwner()
 {
   Shutdown();
   DOMEventTargetHelper::DisconnectFromOwner();
 }
@@ -181,11 +182,12 @@ PresentationAvailability::UpdateAvailabi
       }
       // more promises may have been added to mPromises, at least in theory
     } while (!mPromises.IsEmpty());
 
     return;
   }
 
   if (isChanged) {
-    NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
+    Unused <<
+      NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
   }
 }
--- a/dom/presentation/PresentationConnection.cpp
+++ b/dom/presentation/PresentationConnection.cpp
@@ -8,16 +8,17 @@
 
 #include "ControllerConnectionCollection.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/PresentationConnectionClosedEvent.h"
 #include "mozilla/ErrorNames.h"
+#include "mozilla/DebugOnly.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPresentationService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringStream.h"
 #include "PresentationConnectionList.h"
 #include "PresentationLog.h"
 
@@ -119,32 +120,32 @@ PresentationConnection::Shutdown()
              NS_ConvertUTF16toUTF8(mId).get(), mRole);
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return;
   }
 
-  nsresult rv = service->UnregisterSessionListener(mId, mRole);
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv = service->UnregisterSessionListener(mId, mRole);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "UnregisterSessionListener failed");
 
-  rv = RemoveFromLoadGroup();
-  NS_WARN_IF(NS_FAILED(rv));
+  DebugOnly<nsresult> rv2 = RemoveFromLoadGroup();
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv2), "RemoveFromLoadGroup failed");
 
   if (mRole == nsIPresentationService::ROLE_CONTROLLER) {
     ControllerConnectionCollection::GetSingleton()->RemoveConnection(this,
                                                                      mRole);
   }
 }
 
 /* virtual */ void
 PresentationConnection::DisconnectFromOwner()
 {
-  NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway()));
+  Unused << NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway()));
   DOMEventTargetHelper::DisconnectFromOwner();
 }
 
 /* virtual */ JSObject*
 PresentationConnection::WrapObject(JSContext* aCx,
                                    JS::Handle<JSObject*> aGivenProto)
 {
   return PresentationConnectionBinding::Wrap(aCx, this, aGivenProto);
@@ -202,17 +203,17 @@ PresentationConnection::Close(ErrorResul
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
-  NS_WARN_IF(NS_FAILED(
+  Unused << NS_WARN_IF(NS_FAILED(
     service->CloseSession(mId,
                           mRole,
                           nsIPresentationService::CLOSED_REASON_CLOSED)));
 }
 
 void
 PresentationConnection::Terminate(ErrorResult& aRv)
 {
@@ -223,17 +224,17 @@ PresentationConnection::Terminate(ErrorR
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
-  NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
+  Unused << NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
 }
 
 bool
 PresentationConnection::Equals(uint64_t aWindowId,
                                const nsAString& aId)
 {
   return GetOwner() &&
          aWindowId == GetOwner()->WindowID() &&
@@ -314,25 +315,26 @@ PresentationConnection::ProcessStateChan
                                                          name,
                                                          message))) {
           mozilla::GetErrorName(aReason, message);
           message.InsertLiteral("Internal error: ", 0);
         }
         CopyUTF8toUTF16(message, errorMsg);
       }
 
-      NS_WARN_IF(NS_FAILED(DispatchConnectionClosedEvent(reason, errorMsg)));
+      Unused <<
+        NS_WARN_IF(NS_FAILED(DispatchConnectionClosedEvent(reason, errorMsg)));
 
       return RemoveFromLoadGroup();
     }
     case PresentationConnectionState::Terminated: {
       // Ensure onterminate event is fired.
       RefPtr<AsyncEventDispatcher> asyncDispatcher =
         new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
-      NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
+      Unused << NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
 
       nsCOMPtr<nsIPresentationService> service =
         do_GetService(PRESENTATION_SERVICE_CONTRACTID);
       if (NS_WARN_IF(!service)) {
         return NS_ERROR_NOT_AVAILABLE;
       }
 
       nsresult rv = service->UnregisterSessionListener(mId, mRole);
--- a/dom/presentation/PresentationReceiver.cpp
+++ b/dom/presentation/PresentationReceiver.cpp
@@ -71,18 +71,18 @@ void PresentationReceiver::Shutdown()
 
   // Unregister listener for incoming sessions.
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return;
   }
 
-  nsresult rv = service->UnregisterRespondingListener(mWindowId);
-  NS_WARN_IF(NS_FAILED(rv));
+  Unused <<
+    NS_WARN_IF(NS_FAILED(service->UnregisterRespondingListener(mWindowId)));
 }
 
 /* virtual */ JSObject*
 PresentationReceiver::WrapObject(JSContext* aCx,
                                  JS::Handle<JSObject*> aGivenProto)
 {
   return PresentationReceiverBinding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -604,17 +604,18 @@ PresentationService::HandleReconnectRequ
 }
 
 void
 PresentationService::NotifyAvailableChange(bool aIsAvailable)
 {
   nsTObserverArray<nsCOMPtr<nsIPresentationAvailabilityListener>>::ForwardIterator iter(mAvailabilityListeners);
   while (iter.HasMore()) {
     nsCOMPtr<nsIPresentationAvailabilityListener> listener = iter.GetNext();
-    NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aIsAvailable)));
+    Unused <<
+      NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aIsAvailable)));
   }
 }
 
 bool
 PresentationService::IsAppInstalled(nsIURI* aUri)
 {
   nsAutoCString prePath;
   nsresult rv = aUri->GetPrePath(prePath);
@@ -872,17 +873,18 @@ PresentationService::RegisterAvailabilit
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mAvailabilityListeners.Contains(aListener)) {
     mAvailabilityListeners.AppendElement(aListener);
   }
 
   // Leverage availablility change notification to assign
   // the initial value of availability object.
-  NS_WARN_IF(NS_FAILED(aListener->NotifyAvailableChange(mIsAvailable)));
+  Unused <<
+    NS_WARN_IF(NS_FAILED(aListener->NotifyAvailableChange(mIsAvailable)));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::UnregisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -932,17 +934,17 @@ PresentationService::UnregisterSessionLi
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
              aRole == nsIPresentationService::ROLE_RECEIVER);
 
   RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (info) {
     // When content side decide not handling this session anymore, simply
     // close the connection. Session info is kept for reconnection.
-    NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED)));
+    Unused << NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED)));
     return info->SetListener(nullptr);
   }
   return NS_OK;
 }
 
 nsresult
 PresentationService::RegisterTransportBuilder(const nsAString& aSessionId,
                                               uint8_t aRole,
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -220,40 +220,40 @@ PresentationSessionInfo::Init(nsIPresent
 }
 
 /* virtual */ void
 PresentationSessionInfo::Shutdown(nsresult aReason)
 {
   PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
              NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
 
-  NS_WARN_IF(NS_FAILED(aReason));
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(aReason), "bad reason");
 
   // Close the control channel if any.
   if (mControlChannel) {
-    NS_WARN_IF(NS_FAILED(mControlChannel->Disconnect(aReason)));
+    Unused << NS_WARN_IF(NS_FAILED(mControlChannel->Disconnect(aReason)));
   }
 
   // Close the data transport channel if any.
   if (mTransport) {
     // |mIsTransportReady| will be unset once |NotifyTransportClosed| is called.
-    NS_WARN_IF(NS_FAILED(mTransport->Close(aReason)));
+    Unused << NS_WARN_IF(NS_FAILED(mTransport->Close(aReason)));
   }
 
   mIsResponderReady = false;
   mIsOnTerminating = false;
 
   SetBuilder(nullptr);
 }
 
 nsresult
 PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
 {
   if (mListener && aListener) {
-    NS_WARN_IF(NS_FAILED(mListener->NotifyReplaced()));
+    Unused << NS_WARN_IF(NS_FAILED(mListener->NotifyReplaced()));
   }
 
   mListener = aListener;
 
   if (mListener) {
     // Enable data notification for the transport channel if it's available.
     if (mTransport) {
       nsresult rv = mTransport->EnableDataNotification();
@@ -601,17 +601,17 @@ PresentationControllingInfo::Init(nsIPre
 
 void
 PresentationControllingInfo::Shutdown(nsresult aReason)
 {
   PresentationSessionInfo::Shutdown(aReason);
 
   // Close the server socket if any.
   if (mServerSocket) {
-    NS_WARN_IF(NS_FAILED(mServerSocket->Close()));
+    Unused << NS_WARN_IF(NS_FAILED(mServerSocket->Close()));
     mServerSocket = nullptr;
   }
 
   mIsReconnecting = false;
 }
 
 nsresult
 PresentationControllingInfo::GetAddress()
@@ -874,17 +874,17 @@ PresentationControllingInfo::NotifyDisco
              NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
 
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
       builder = do_QueryInterface(mBuilder);
     if (builder) {
-      NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
+      Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
     }
   }
 
   // Unset control channel here so it won't try to re-close it in potential
   // subsequent |Shutdown| calls.
   SetControlChannel(nullptr);
 
   if (NS_WARN_IF(NS_FAILED(aReason) || !mIsResponderReady)) {
@@ -1147,17 +1147,17 @@ PresentationPresentingInfo::OnSessionTra
   if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
     // Prepare and send the answer.
     // In the current implementation of |PresentationSessionTransport|,
     // |GetSelfAddress| cannot return the real info when it's initialized via
     // |buildTCPReceiverTransport|. Yet this deficiency only affects the channel
     // description for the answer, which is not actually checked at requester side.
     nsCOMPtr<nsINetAddr> selfAddr;
     rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
-    NS_WARN_IF(NS_FAILED(rv));
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetSelfAddress failed");
 
     nsCString address;
     uint16_t port = 0;
     if (NS_SUCCEEDED(rv)) {
       selfAddr->GetAddress(address);
       selfAddr->GetPort(&port);
     }
     nsCOMPtr<nsIPresentationChannelDescription> description =
@@ -1277,17 +1277,17 @@ PresentationPresentingInfo::InitTranspor
   return NS_ERROR_UNEXPECTED;
 }
 
 nsresult
 PresentationPresentingInfo::UntrackFromService()
 {
   // Remove the OOP responding info (if it has never been used).
   if (mContentParent) {
-    NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId));
+    Unused << NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId));
   }
 
   // Remove the session info (and the in-process responding info if there's any).
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
@@ -1422,17 +1422,17 @@ PresentationPresentingInfo::NotifyDiscon
              NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
 
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
       builder = do_QueryInterface(mBuilder);
     if (builder) {
-      NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
+      Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
     }
   }
 
   // Unset control channel here so it won't try to re-close it in potential
   // subsequent |Shutdown| calls.
   SetControlChannel(nullptr);
 
   if (NS_WARN_IF(NS_FAILED(aReason))) {
@@ -1497,17 +1497,17 @@ PresentationPresentingInfo::ResolvedCall
   }
 
   RefPtr<TabParent> tabParent = TabParent::GetFrom(frameLoader);
   if (tabParent) {
     // OOP frame
     // Notify the content process that a receiver page has launched, so it can
     // start monitoring the loading progress.
     mContentParent = tabParent->Manager();
-    NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
+    Unused << NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
   } else {
     // In-process frame
     nsCOMPtr<nsIDocShell> docShell;
     rv = frameLoader->GetDocShell(getter_AddRefs(docShell));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       ReplyError(NS_ERROR_DOM_OPERATION_ERR);
       return;
     }
--- a/dom/presentation/PresentationSessionInfo.h
+++ b/dom/presentation/PresentationSessionInfo.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_PresentationSessionInfo_h
 #define mozilla_dom_PresentationSessionInfo_h
 
 #include "base/process.h"
 #include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsINetworkInfoService.h"
 #include "nsIPresentationControlChannel.h"
 #include "nsIPresentationDevice.h"
 #include "nsIPresentationListener.h"
 #include "nsIPresentationService.h"
 #include "nsIPresentationSessionTransport.h"
@@ -135,18 +136,19 @@ protected:
       return;
     }
 
     mState = aState;
     mReason = aReason;
 
     // Notify session state change.
     if (mListener) {
-      nsresult rv = mListener->NotifyStateChange(mSessionId, mState, aReason);
-      NS_WARN_IF(NS_FAILED(rv));
+      DebugOnly<nsresult> rv =
+        mListener->NotifyStateChange(mSessionId, mState, aReason);
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NotifyStateChanged");
     }
   }
 
   void ContinueTermination();
 
   // Should be nsIPresentationChannelDescription::TYPE_TCP/TYPE_DATACHANNEL
   uint8_t mTransportType = 0;
 
--- a/dom/presentation/PresentationTCPSessionTransport.cpp
+++ b/dom/presentation/PresentationTCPSessionTransport.cpp
@@ -326,17 +326,17 @@ PresentationTCPSessionTransport::GetCall
 
 NS_IMETHODIMP
 PresentationTCPSessionTransport::SetCallback(nsIPresentationSessionTransportCallback* aCallback)
 {
   mCallback = aCallback;
 
   if (!!mCallback && ReadyState::OPEN == mReadyState) {
     // Notify the transport channel is ready.
-    NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
+    Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationTCPSessionTransport::GetSelfAddress(nsINetAddr** aSelfAddress)
 {
@@ -351,17 +351,17 @@ void
 PresentationTCPSessionTransport::EnsureCopying()
 {
   if (mAsyncCopierActive) {
     return;
   }
 
   mAsyncCopierActive = true;
   RefPtr<CopierCallbacks> callbacks = new CopierCallbacks(this);
-  NS_WARN_IF(NS_FAILED(mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr)));
+  Unused << NS_WARN_IF(NS_FAILED(mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr)));
 }
 
 void
 PresentationTCPSessionTransport::NotifyCopyComplete(nsresult aStatus)
 {
   mAsyncCopierActive = false;
   mMultiplexStream->RemoveStream(0);
   if (NS_WARN_IF(NS_FAILED(aStatus))) {
@@ -453,24 +453,25 @@ PresentationTCPSessionTransport::SetRead
       CreateInputStreamPump();
     }
 
     if (NS_WARN_IF(!mCallback)) {
       return;
     }
 
     // Notify the transport channel is ready.
-    NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
+    Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
   } else if (mReadyState == ReadyState::CLOSED && mCallback) {
     if (NS_WARN_IF(!mCallback)) {
       return;
     }
 
     // Notify the transport channel has been shut down.
-    NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportClosed(mCloseStatus)));
+    Unused <<
+      NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportClosed(mCloseStatus)));
     mCallback = nullptr;
   }
 }
 
 // nsITransportEventSink
 NS_IMETHODIMP
 PresentationTCPSessionTransport::OnTransportStatus(nsITransport* aTransport,
                                                    nsresult aStatus,
--- a/dom/presentation/ipc/PresentationBuilderChild.cpp
+++ b/dom/presentation/ipc/PresentationBuilderChild.cpp
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DCPresentationChannelDescription.h"
 #include "nsComponentManagerUtils.h"
 #include "nsGlobalWindow.h"
 #include "PresentationBuilderChild.h"
 #include "PresentationIPCService.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(PresentationBuilderChild,
                   nsIPresentationSessionTransportBuilderListener)
 
 PresentationBuilderChild::PresentationBuilderChild(const nsString& aSessionId,
@@ -105,20 +106,20 @@ NS_IMETHODIMP
 PresentationBuilderChild::OnSessionTransport(nsIPresentationSessionTransport* aTransport)
 {
   if (NS_WARN_IF(mActorDestroyed || !SendOnSessionTransport())){
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
-  NS_WARN_IF(!service);
+  NS_WARNING_ASSERTION(service, "no presentation service");
   if (service) {
-    NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->
-                           NotifySessionTransport(mSessionId, mRole, aTransport)));
+    Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->
+                                     NotifySessionTransport(mSessionId, mRole, aTransport)));
   }
   mBuilder = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationBuilderChild::OnError(nsresult reason)
 {
--- a/dom/presentation/ipc/PresentationBuilderParent.cpp
+++ b/dom/presentation/ipc/PresentationBuilderParent.cpp
@@ -21,17 +21,17 @@ PresentationBuilderParent::PresentationB
   MOZ_COUNT_CTOR(PresentationBuilderParent);
 }
 
 PresentationBuilderParent::~PresentationBuilderParent()
 {
   MOZ_COUNT_DTOR(PresentationBuilderParent);
 
   if (mNeedDestroyActor) {
-    NS_WARN_IF(!Send__delete__(this));
+    Unused << NS_WARN_IF(!Send__delete__(this));
   }
 }
 
 NS_IMETHODIMP
 PresentationBuilderParent::BuildDataChannelTransport(
                       uint8_t aRole,
                       mozIDOMWindow* aWindow, /* unused */
                       nsIPresentationSessionTransportBuilderListener* aListener)
@@ -147,18 +147,19 @@ PresentationBuilderParent::RecvClose(con
 }
 
 // Delegate to nsIPresentationSessionTransportBuilderListener
 bool
 PresentationBuilderParent::RecvOnSessionTransport()
 {
   // To avoid releasing |this| in this method
   NS_DispatchToMainThread(NS_NewRunnableFunction([this]() -> void {
-    NS_WARN_IF(!mBuilderListener ||
-               NS_FAILED(mBuilderListener->OnSessionTransport(nullptr)));
+    Unused <<
+      NS_WARN_IF(!mBuilderListener ||
+                 NS_FAILED(mBuilderListener->OnSessionTransport(nullptr)));
   }));
 
   nsCOMPtr<nsIPresentationSessionTransportCallback>
     callback(do_QueryInterface(mBuilderListener));
 
   callback->NotifyTransportReady();
   return true;
 }
--- a/dom/presentation/ipc/PresentationChild.cpp
+++ b/dom/presentation/ipc/PresentationChild.cpp
@@ -87,50 +87,50 @@ PresentationChild::DeallocPPresentationB
   return true;
 }
 
 
 bool
 PresentationChild::RecvNotifyAvailableChange(const bool& aAvailable)
 {
   if (mService) {
-    NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailable)));
+    Unused << NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailable)));
   }
   return true;
 }
 
 bool
 PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId,
                                                 const uint16_t& aState,
                                                 const nsresult& aReason)
 {
   if (mService) {
-    NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId,
-                                                            aState,
-                                                            aReason)));
+    Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId,
+                                                                      aState,
+                                                                      aReason)));
   }
   return true;
 }
 
 bool
 PresentationChild::RecvNotifyMessage(const nsString& aSessionId,
                                      const nsCString& aData)
 {
   if (mService) {
-    NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData)));
+    Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData)));
   }
   return true;
 }
 
 bool
 PresentationChild::RecvNotifySessionConnect(const uint64_t& aWindowId,
                                             const nsString& aSessionId)
 {
   if (mService) {
-    NS_WARN_IF(NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId)));
+    Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId)));
   }
   return true;
 }
 
 /*
  * Implementation of PresentationRequestChild
  */
 
@@ -159,21 +159,21 @@ bool
 PresentationRequestChild::Recv__delete__(const nsresult& aResult)
 {
   if (mActorDestroyed) {
     return true;
   }
 
   if (mCallback) {
     if (NS_FAILED(aResult)) {
-      NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult)));
+      Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult)));
     }
   }
 
   return true;
 }
 
 bool
 PresentationRequestChild::RecvNotifyRequestUrlSelected(const nsString& aUrl)
 {
-  NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl)));
+  Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl)));
   return true;
 }
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -33,17 +33,18 @@ NS_IMPL_ISUPPORTS_INHERITED(Presentation
 
 PresentationIPCService::PresentationIPCService()
 {
   ContentChild* contentChild = ContentChild::GetSingleton();
   if (NS_WARN_IF(!contentChild)) {
     return;
   }
   sPresentationChild = new PresentationChild(this);
-  NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
+  Unused <<
+    NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
 }
 
 /* virtual */
 PresentationIPCService::~PresentationIPCService()
 {
   Shutdown();
 
   mAvailabilityListeners.Clear();
@@ -175,105 +176,114 @@ PresentationIPCService::BuildTransport(c
 }
 
 nsresult
 PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
                                     const PresentationIPCRequest& aRequest)
 {
   if (sPresentationChild) {
     PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
-    NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
+    Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::RegisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
   mAvailabilityListeners.AppendElement(aListener);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendRegisterAvailabilityHandler());
+    Unused <<
+      NS_WARN_IF(!sPresentationChild->SendRegisterAvailabilityHandler());
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::UnregisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
   mAvailabilityListeners.RemoveElement(aListener);
   if (mAvailabilityListeners.IsEmpty() && sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler());
+    Unused <<
+      NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler());
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
                                                 uint8_t aRole,
                                                 nsIPresentationSessionListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
   nsCOMPtr<nsIPresentationSessionListener> listener;
   if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) {
-    NS_WARN_IF(NS_FAILED(listener->NotifyReplaced()));
+    Unused << NS_WARN_IF(NS_FAILED(listener->NotifyReplaced()));
     mSessionListeners.Put(aSessionId, aListener);
     return NS_OK;
   }
 
   mSessionListeners.Put(aSessionId, aListener);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsString(aSessionId), aRole));
+    Unused <<
+      NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(
+        nsString(aSessionId), aRole));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId,
                                                   uint8_t aRole)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   UntrackSessionInfo(aSessionId, aRole);
 
   mSessionListeners.Remove(aSessionId);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsString(aSessionId), aRole));
+    Unused <<
+      NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(
+        nsString(aSessionId), aRole));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId,
                                                    nsIPresentationRespondingListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mRespondingListeners.Put(aWindowId, aListener);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId));
+    Unused <<
+      NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mRespondingListeners.Remove(aWindowId);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler(aWindowId));
+    Unused <<
+      NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler(
+        aWindowId));
   }
   return NS_OK;
 }
 
 nsresult
 PresentationIPCService::NotifySessionTransport(const nsString& aSessionId,
                                                const uint8_t& aRole,
                                                nsIPresentationSessionTransport* aTransport)
@@ -334,17 +344,17 @@ PresentationIPCService::NotifyMessage(co
 nsresult
 PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId,
                                               uint8_t aRole,
                                               nsresult aReason)
 {
   if (NS_WARN_IF(!mSessionInfos.Contains(aSessionId))) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason));
+  Unused << NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason));
   return NS_OK;
 }
 
 nsresult
 PresentationIPCService::NotifySessionConnect(uint64_t aWindowId,
                                              const nsAString& aSessionId)
 {
   nsCOMPtr<nsIPresentationRespondingListener> listener;
@@ -356,17 +366,17 @@ PresentationIPCService::NotifySessionCon
 }
 
 nsresult
 PresentationIPCService::NotifyAvailableChange(bool aAvailable)
 {
   nsTObserverArray<nsCOMPtr<nsIPresentationAvailabilityListener>>::ForwardIterator iter(mAvailabilityListeners);
   while (iter.HasMore()) {
     nsIPresentationAvailabilityListener* listener = iter.GetNext();
-    NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aAvailable)));
+    Unused << NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aAvailable)));
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId,
                                             uint64_t aWindowId,
@@ -379,19 +389,19 @@ PresentationIPCService::NotifyReceiverRe
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Track the responding info for an OOP receiver page.
   AddRespondingSessionId(aWindowId,
                          aSessionId,
                          nsIPresentationService::ROLE_RECEIVER);
 
-  NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId),
-                                                          aWindowId,
-                                                          aIsLoading));
+  Unused << NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId),
+                                                                    aWindowId,
+                                                                    aIsLoading));
 
   // Release mCallback after using aSessionId
   // because aSessionId is held by mCallback.
   mCallback = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/presentation/ipc/PresentationParent.cpp
+++ b/dom/presentation/ipc/PresentationParent.cpp
@@ -46,29 +46,31 @@ PresentationParent::Init(ContentParentId
 }
 
 void
 PresentationParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   mActorDestroyed = true;
 
   for (uint32_t i = 0; i < mSessionIdsAtController.Length(); i++) {
-    NS_WARN_IF(NS_FAILED(mService->
-      UnregisterSessionListener(mSessionIdsAtController[i], nsIPresentationService::ROLE_CONTROLLER)));
+    Unused << NS_WARN_IF(NS_FAILED(mService->
+      UnregisterSessionListener(mSessionIdsAtController[i],
+                                nsIPresentationService::ROLE_CONTROLLER)));
   }
   mSessionIdsAtController.Clear();
 
   for (uint32_t i = 0; i < mSessionIdsAtReceiver.Length(); i++) {
-    NS_WARN_IF(NS_FAILED(mService->
+    Unused << NS_WARN_IF(NS_FAILED(mService->
       UnregisterSessionListener(mSessionIdsAtReceiver[i], nsIPresentationService::ROLE_RECEIVER)));
   }
   mSessionIdsAtReceiver.Clear();
 
   for (uint32_t i = 0; i < mWindowIds.Length(); i++) {
-    NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(mWindowIds[i])));
+    Unused << NS_WARN_IF(NS_FAILED(mService->
+      UnregisterRespondingListener(mWindowIds[i])));
   }
   mWindowIds.Clear();
 
   mService->UnregisterAvailabilityListener(this);
   mService = nullptr;
 }
 
 bool
@@ -143,25 +145,25 @@ PresentationParent::Recv__delete__()
 {
   return true;
 }
 
 bool
 PresentationParent::RecvRegisterAvailabilityHandler()
 {
   MOZ_ASSERT(mService);
-  NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener(this)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener(this)));
   return true;
 }
 
 bool
 PresentationParent::RecvUnregisterAvailabilityHandler()
 {
   MOZ_ASSERT(mService);
-  NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(this)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(this)));
   return true;
 }
 
 /* virtual */ bool
 PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId,
                                                const uint8_t& aRole)
 {
   MOZ_ASSERT(mService);
@@ -173,62 +175,62 @@ PresentationParent::RecvRegisterSessionH
     return true;
   }
 
   if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
     mSessionIdsAtController.AppendElement(aSessionId);
   } else {
     mSessionIdsAtReceiver.AppendElement(aSessionId);
   }
-  NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this)));
   return true;
 }
 
 /* virtual */ bool
 PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId,
                                                  const uint8_t& aRole)
 {
   MOZ_ASSERT(mService);
   if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
     mSessionIdsAtController.RemoveElement(aSessionId);
   } else {
     mSessionIdsAtReceiver.RemoveElement(aSessionId);
   }
-  NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole)));
   return true;
 }
 
 /* virtual */ bool
 PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId)
 {
   MOZ_ASSERT(mService);
 
   mWindowIds.AppendElement(aWindowId);
-  NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this)));
   return true;
 }
 
 /* virtual */ bool
 PresentationParent::RecvUnregisterRespondingHandler(const uint64_t& aWindowId)
 {
   MOZ_ASSERT(mService);
   mWindowIds.RemoveElement(aWindowId);
-  NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId)));
   return true;
 }
 
 bool
 PresentationParent::RegisterTransportBuilder(const nsString& aSessionId,
                                              const uint8_t& aRole)
 {
   MOZ_ASSERT(mService);
 
   nsCOMPtr<nsIPresentationSessionTransportBuilder> builder =
     new PresentationBuilderParent(this);
-  NS_WARN_IF(NS_FAILED(static_cast<PresentationService*>(mService.get())->
+  Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationService*>(mService.get())->
                          RegisterTransportBuilder(aSessionId, aRole, builder)));
   return true;
 }
 
 NS_IMETHODIMP
 PresentationParent::NotifyAvailableChange(bool aAvailable)
 {
   if (NS_WARN_IF(mActorDestroyed || !SendNotifyAvailableChange(aAvailable))) {
@@ -284,30 +286,30 @@ PresentationParent::NotifySessionConnect
 bool
 PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId,
                                             const uint64_t& aWindowId,
                                             const bool& aIsLoading)
 {
   MOZ_ASSERT(mService);
 
   RegisterTransportBuilder(aSessionId, nsIPresentationService::ROLE_RECEIVER);
-  NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId,
-                                                     aWindowId,
-                                                     aIsLoading)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId,
+                                                               aWindowId,
+                                                               aIsLoading)));
   return true;
 }
 
 bool
 PresentationParent::RecvNotifyTransportClosed(const nsString& aSessionId,
                                               const uint8_t& aRole,
                                               const nsresult& aReason)
 {
   MOZ_ASSERT(mService);
 
-  NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason)));
+  Unused << NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason)));
   return true;
 }
 
 /*
  * Implementation of PresentationRequestParent
  */
 
 NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback)
@@ -455,17 +457,17 @@ PresentationRequestParent::DoRequest(con
   return SendResponse(NS_OK);
 }
 
 NS_IMETHODIMP
 PresentationRequestParent::NotifySuccess(const nsAString& aUrl)
 {
   if (mNeedRegisterBuilder) {
     RefPtr<PresentationParent> parent = static_cast<PresentationParent*>(Manager());
-    NS_WARN_IF(!parent->RegisterTransportBuilder(
+    Unused << NS_WARN_IF(!parent->RegisterTransportBuilder(
                                       mSessionId,
                                       nsIPresentationService::ROLE_CONTROLLER));
   }
 
   Unused << SendNotifyRequestUrlSelected(nsString(aUrl));
   return SendResponse(NS_OK);
 }
 
--- a/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp
+++ b/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp
@@ -350,30 +350,30 @@ void
 LegacyMDNSDeviceProvider::ClearUnknownDevices()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   size_t i = mDevices.Length();
   while (i > 0) {
     --i;
     if (mDevices[i]->State() == DeviceState::eUnknown) {
-      NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
+      Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
     }
   }
 }
 
 void
 LegacyMDNSDeviceProvider::ClearDevices()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   size_t i = mDevices.Length();
   while (i > 0) {
     --i;
-    NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
+    Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
   }
 }
 
 // nsIPresentationDeviceProvider
 NS_IMETHODIMP
 LegacyMDNSDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
+++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
@@ -561,30 +561,30 @@ void
 MulticastDNSDeviceProvider::ClearUnknownDevices()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   size_t i = mDevices.Length();
   while (i > 0) {
     --i;
     if (mDevices[i]->State() == DeviceState::eUnknown) {
-      NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
+      Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
     }
   }
 }
 
 void
 MulticastDNSDeviceProvider::ClearDevices()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   size_t i = mDevices.Length();
   while (i > 0) {
     --i;
-    NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
+    Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
   }
 }
 
 // nsIPresentationDeviceProvider
 NS_IMETHODIMP
 MulticastDNSDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -735,17 +735,17 @@ NativeHandlerCallback(JSContext* aCx, un
 {
   JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
 
   JS::Rooted<JS::Value> v(aCx,
                           js::GetFunctionNativeReserved(&args.callee(),
                                                         SLOT_NATIVEHANDLER));
   MOZ_ASSERT(v.isObject());
 
-  PromiseNativeHandler* handler;
+  PromiseNativeHandler* handler = nullptr;
   if (NS_FAILED(UNWRAP_OBJECT(PromiseNativeHandler, &v.toObject(),
                               handler))) {
     return Throw(aCx, NS_ERROR_UNEXPECTED);
   }
 
   v = js::GetFunctionNativeReserved(&args.callee(), SLOT_NATIVEHANDLER_TASK);
   NativeHandlerTask task = static_cast<NativeHandlerTask>(v.toInt32());
 
@@ -776,33 +776,93 @@ CreateNativeHandlerFunction(JSContext* a
   js::SetFunctionNativeReserved(obj, SLOT_NATIVEHANDLER,
                                 JS::ObjectValue(*aHolder));
   js::SetFunctionNativeReserved(obj, SLOT_NATIVEHANDLER_TASK,
                                 JS::Int32Value(static_cast<int32_t>(aTask)));
 
   return obj;
 }
 
+namespace {
+
+class PromiseNativeHandlerShim final : public PromiseNativeHandler
+{
+  RefPtr<PromiseNativeHandler> mInner;
+
+  ~PromiseNativeHandlerShim()
+  {
+  }
+
+public:
+  explicit PromiseNativeHandlerShim(PromiseNativeHandler* aInner)
+    : mInner(aInner)
+  {
+    MOZ_ASSERT(mInner);
+  }
+
+  void
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+  {
+    mInner->ResolvedCallback(aCx, aValue);
+    mInner = nullptr;
+  }
+
+  void
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+  {
+    mInner->RejectedCallback(aCx, aValue);
+    mInner = nullptr;
+  }
+
+  bool
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
+             JS::MutableHandle<JSObject*> aWrapper)
+  {
+    return PromiseNativeHandlerBinding::Wrap(aCx, this, aGivenProto, aWrapper);
+  }
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(PromiseNativeHandlerShim)
+};
+
+NS_IMPL_CYCLE_COLLECTION(PromiseNativeHandlerShim, mInner)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PromiseNativeHandlerShim)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PromiseNativeHandlerShim)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PromiseNativeHandlerShim)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+} // anonymous namespace
+
 void
 Promise::AppendNativeHandler(PromiseNativeHandler* aRunnable)
 {
   NS_ASSERT_OWNINGTHREAD(Promise);
 
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
     // Our API doesn't allow us to return a useful error.  Not like this should
     // happen anyway.
     return;
   }
 
+  // The self-hosted promise js may keep the object we pass to it alive
+  // for quite a while depending on when GC runs.  Therefore, pass a shim
+  // object instead.  The shim will free its inner PromiseNativeHandler
+  // after the promise has settled just like our previous c++ promises did.
+  RefPtr<PromiseNativeHandlerShim> shim =
+    new PromiseNativeHandlerShim(aRunnable);
+
   JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> handlerWrapper(cx);
   // Note: PromiseNativeHandler is NOT wrappercached.  So we can't use
   // ToJSValue here, because it will try to do XPConnect wrapping on it, sadly.
-  if (NS_WARN_IF(!aRunnable->WrapObject(cx, nullptr, &handlerWrapper))) {
+  if (NS_WARN_IF(!shim->WrapObject(cx, nullptr, &handlerWrapper))) {
     // Again, no way to report errors.
     jsapi.ClearException();
     return;
   }
 
   JS::Rooted<JSObject*> resolveFunc(cx);
   resolveFunc =
     CreateNativeHandlerFunction(cx, handlerWrapper, NativeHandlerTask::Resolve);
deleted file mode 100644
--- a/dom/promise/PromiseNativeHandler.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
-* License, v. 2.0. If a copy of the MPL was not distributed with this file,
-* You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/PromiseNativeHandler.h"
-#include "mozilla/dom/PromiseBinding.h"
-
-namespace mozilla {
-namespace dom {
-
-#ifdef SPIDERMONKEY_PROMISE
-bool
-PromiseNativeHandler::WrapObject(JSContext* aCx,
-                                       JS::Handle<JSObject*> aGivenProto,
-                                       JS::MutableHandle<JSObject*> aWrapper)
-{
-  return PromiseNativeHandlerBinding::Wrap(aCx, this, aGivenProto, aWrapper);
-}
-#endif // SPIDERMONKEY_PROMISE
-
-} // namespace dom
-} // namespace mozilla
-
-
--- a/dom/promise/PromiseNativeHandler.h
+++ b/dom/promise/PromiseNativeHandler.h
@@ -25,20 +25,14 @@ protected:
   { }
 
 public:
   virtual void
   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) = 0;
 
   virtual void
   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) = 0;
-
-#ifdef SPIDERMONKEY_PROMISE
-  bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
-                  JS::MutableHandle<JSObject*> aWrapper);
-#endif // SPIDERMONKEY_PROMISE
-
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PromiseNativeHandler_h
--- a/dom/promise/moz.build
+++ b/dom/promise/moz.build
@@ -10,17 +10,16 @@ EXPORTS.mozilla.dom += [
     'PromiseNativeHandler.h',
     'PromiseWorkerProxy.h',
 ]
 
 UNIFIED_SOURCES += [
     'Promise.cpp',
     'PromiseCallback.cpp',
     'PromiseDebugging.cpp',
-    'PromiseNativeHandler.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '../base',
     '../ipc',
     '../workers',
 ]
 
--- a/dom/quota/QuotaManagerService.cpp
+++ b/dom/quota/QuotaManagerService.cpp
@@ -498,17 +498,16 @@ NS_IMETHODIMP
 QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal,
                                           nsIQuotaUsageCallback* aCallback,
                                           bool aGetGroupUsage,
                                           nsIQuotaUsageRequest** _retval)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aCallback);
-  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
 
   RefPtr<UsageRequest> request = new UsageRequest(aPrincipal, aCallback);
 
   UsageParams params;
 
   PrincipalInfo& principalInfo = params.principalInfo();
   nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
new file mode 100644
--- /dev/null
+++ b/dom/quota/StorageManager.cpp
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "StorageManager.h"
+
+#include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/dom/quota/QuotaManagerService.h"
+#include "mozilla/dom/StorageManagerBinding.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/ErrorResult.h"
+#include "nsIQuotaCallbacks.h"
+#include "nsIQuotaRequests.h"
+#include "nsPIDOMWindow.h"
+
+using namespace mozilla::dom::workers;
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+// This class is used to get quota usage callback.
+class EstimateResolver final
+  : public nsIQuotaUsageCallback
+{
+  class FinishWorkerRunnable;
+
+  // If this resolver was created for a window then mPromise must be non-null.
+  // Otherwise mProxy must be non-null.
+  RefPtr<Promise> mPromise;
+  RefPtr<PromiseWorkerProxy> mProxy;
+
+  nsresult mResultCode;
+  StorageEstimate mStorageEstimate;
+
+public:
+  explicit EstimateResolver(Promise* aPromise)
+    : mPromise(aPromise)
+    , mResultCode(NS_OK)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aPromise);
+  }
+
+  explicit EstimateResolver(PromiseWorkerProxy* aProxy)
+    : mProxy(aProxy)
+    , mResultCode(NS_OK)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aProxy);
+  }
+
+  void
+  ResolveOrReject(Promise* aPromise);
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  NS_DECL_NSIQUOTAUSAGECALLBACK
+
+private:
+  ~EstimateResolver()
+  { }
+};
+
+// This class is used to return promise on worker thread.
+class EstimateResolver::FinishWorkerRunnable final
+  : public WorkerRunnable
+{
+  RefPtr<EstimateResolver> mResolver;
+
+public:
+  explicit FinishWorkerRunnable(EstimateResolver* aResolver)
+    : WorkerRunnable(aResolver->mProxy->GetWorkerPrivate())
+    , mResolver(aResolver)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aResolver);
+  }
+
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
+};
+
+class EstimateWorkerMainThreadRunnable
+  : public WorkerMainThreadRunnable
+{
+  RefPtr<PromiseWorkerProxy> mProxy;
+
+public:
+  EstimateWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
+                                   PromiseWorkerProxy* aProxy)
+    : WorkerMainThreadRunnable(aWorkerPrivate,
+                               NS_LITERAL_CSTRING("StorageManager :: Estimate"))
+    , mProxy(aProxy)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+    MOZ_ASSERT(aProxy);
+  }
+
+  virtual bool
+  MainThreadRun() override;
+};
+
+nsresult
+GetUsageForPrincipal(nsIPrincipal* aPrincipal,
+                     nsIQuotaUsageCallback* aCallback,
+                     nsIQuotaUsageRequest** aRequest)
+{
+  MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(aCallback);
+  MOZ_ASSERT(aRequest);
+
+  nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
+  if (NS_WARN_IF(!qms)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = qms->GetUsageForPrincipal(aPrincipal, aCallback, true, aRequest);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+};
+
+nsresult
+GetStorageEstimate(nsIQuotaUsageRequest* aRequest,
+                   StorageEstimate& aStorageEstimate)
+{
+  MOZ_ASSERT(aRequest);
+
+  uint64_t usage;
+  nsresult rv = aRequest->GetUsage(&usage);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  uint64_t limit;
+  rv = aRequest->GetLimit(&limit);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  aStorageEstimate.mUsage.Construct() = usage;
+  aStorageEstimate.mQuota.Construct() = limit;
+  return NS_OK;
+}
+
+} // namespace
+
+/*******************************************************************************
+ * Local class implementations
+ ******************************************************************************/
+
+void
+EstimateResolver::ResolveOrReject(Promise* aPromise)
+{
+  MOZ_ASSERT(aPromise);
+
+  if (NS_SUCCEEDED(mResultCode)) {
+    aPromise->MaybeResolve(mStorageEstimate);
+  } else {
+    aPromise->MaybeReject(mResultCode);
+  }
+}
+
+NS_IMPL_ISUPPORTS(EstimateResolver, nsIQuotaUsageCallback)
+
+NS_IMETHODIMP
+EstimateResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRequest);
+
+  nsresult rv = aRequest->GetResultCode(&mResultCode);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    mResultCode = rv;
+  } else if (NS_SUCCEEDED(mResultCode)) {
+    rv = GetStorageEstimate(aRequest, mStorageEstimate);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      mResultCode = rv;
+    }
+  }
+
+  // In a main thread request.
+  if (!mProxy) {
+    MOZ_ASSERT(mPromise);
+
+    ResolveOrReject(mPromise);
+    return NS_OK;
+  }
+
+  // In a worker thread request.
+  MutexAutoLock lock(mProxy->Lock());
+
+  if (NS_WARN_IF(mProxy->CleanedUp())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this);
+  if (NS_WARN_IF(!runnable->Dispatch())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+bool
+EstimateResolver::
+FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+{
+  MOZ_ASSERT(aWorkerPrivate);
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  RefPtr<PromiseWorkerProxy> proxy = mResolver->mProxy;
+  MOZ_ASSERT(proxy);
+
+  RefPtr<Promise> promise = proxy->WorkerPromise();
+  MOZ_ASSERT(promise);
+
+  mResolver->ResolveOrReject(promise);