Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 07 Sep 2016 17:26:11 +0200
changeset 313065 af11902f242f7bdaa7437a497f286e2528af4f31
parent 313064 e6f59b598c177e3b2080f0d33e59de86a318169e (current diff)
parent 312971 95acb9299fafdc69463c49860caf367e4fbcc8e3 (diff)
child 313066 db9dfcdbef4aa204aba5d9b3c384f21ee1c66c61
push id20479
push userkwierso@gmail.com
push dateThu, 08 Sep 2016 01:08:46 +0000
treeherderfx-team@fb7c6b034329 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone51.0a1
Merge mozilla-central to autoland
dom/audiochannel/AudioChannelService.cpp
dom/base/nsContentUtils.cpp
dom/bindings/Codegen.py
dom/html/HTMLInputElement.cpp
dom/promise/PromiseNativeHandler.cpp
dom/webidl/moz.build
layout/generic/nsFrame.cpp
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
--- 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/client/debugger/new/index.html
+++ b/devtools/client/debugger/new/index.html
@@ -3,11 +3,14 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <!DOCTYPE html>
 <html>
   <head>
     <link rel="stylesheet" type="text/css" href="resource://devtools/client/debugger/new/styles.css" />
   </head>
   <body>
     <div id="mount"></div>
+    <script type="text/javascript">
+      var devtoolsRequire = Components.utils.import("resource://devtools/shared/Loader.jsm", {}).require;
+    </script>
     <script type="text/javascript" src="resource://devtools/client/debugger/new/bundle.js"></script>
   </body>
 </html>
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-events.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-events.js
@@ -2,48 +2,118 @@
  * 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";
 
 // Test the eyedropper mouse and keyboard handling.
 
 const HIGHLIGHTER_TYPE = "EyeDropper";
 const ID = "eye-dropper-";
+const TEST_URI = `
+<style>
+  html{width:100%;height:100%;}
+</style>
+<body>eye-dropper test</body>`;
 
 const MOVE_EVENTS_DATA = [
   {type: "mouse", x: 200, y: 100, expected: {x: 200, y: 100}},
   {type: "mouse", x: 100, y: 200, expected: {x: 100, y: 200}},
   {type: "keyboard", key: "VK_LEFT", expected: {x: 99, y: 200}},
   {type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 89, y: 200}},
   {type: "keyboard", key: "VK_RIGHT", expected: {x: 90, y: 200}},
   {type: "keyboard", key: "VK_RIGHT", shift: true, expected: {x: 100, y: 200}},
   {type: "keyboard", key: "VK_DOWN", expected: {x: 100, y: 201}},
   {type: "keyboard", key: "VK_DOWN", shift: true, expected: {x: 100, y: 211}},
   {type: "keyboard", key: "VK_UP", expected: {x: 100, y: 210}},
   {type: "keyboard", key: "VK_UP", shift: true, expected: {x: 100, y: 200}},
+  // Mouse initialization for left and top snapping
+  {type: "mouse", x: 7, y: 7, expected: {x: 7, y: 7}},
+  // Left Snapping
+  {type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 0, y: 7},
+   desc: "Left Snapping to x=0"},
+  // Top Snapping
+  {type: "keyboard", key: "VK_UP", shift: true, expected: {x: 0, y: 0},
+   desc: "Top Snapping to y=0"},
+  // Mouse initialization for right snapping
+  {
+    type: "mouse",
+    x: (width, height) => width - 5,
+    y: 0,
+    expected: {
+      x: (width, height) => width - 5,
+      y: 0
+    }
+  },
+  // Right snapping
+  {
+    type: "keyboard",
+    key: "VK_RIGHT",
+    shift: true,
+    expected: {
+      x: (width, height) => width,
+      y: 0
+    },
+    desc: "Right snapping to x=max window width available"
+  },
+  // Mouse initialization for bottom snapping
+  {
+    type: "mouse",
+    x: 0,
+    y: (width, height) => height - 5,
+    expected: {
+      x: 0,
+      y: (width, height) => height - 5
+    }
+  },
+  // Bottom snapping
+  {
+    type: "keyboard",
+    key: "VK_DOWN",
+    shift: true,
+    expected: {
+      x: 0,
+      y: (width, height) => height
+    },
+    desc: "Bottom snapping to y=max window height available"
+  },
 ];
 
 add_task(function* () {
-  let helper = yield openInspectorForURL("data:text/html;charset=utf-8,eye-dropper test")
-               .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+  let {inspector, testActor} = yield openInspectorForURL(
+    "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
+
   helper.prefix = ID;
 
   yield helper.show("html");
-  yield respondsToMoveEvents(helper);
+  yield respondsToMoveEvents(helper, testActor);
   yield respondsToReturnAndEscape(helper);
 
   helper.finalize();
 });
 
-function* respondsToMoveEvents(helper) {
+function* respondsToMoveEvents(helper, testActor) {
   info("Checking that the eyedropper responds to events from the mouse and keyboard");
   let {mouse} = helper;
+  let {width, height} = yield testActor.getBoundingClientRect("html");
 
-  for (let {type, x, y, key, shift, expected} of MOVE_EVENTS_DATA) {
-    info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
+  for (let {type, x, y, key, shift, expected, desc} of MOVE_EVENTS_DATA) {
+    x = typeof x === "function" ? x(width, height) : x;
+    y = typeof y === "function" ? y(width, height) : y;
+    expected.x = typeof expected.x === "function" ?
+      expected.x(width, height) : expected.x;
+    expected.y = typeof expected.y === "function" ?
+      expected.y(width, height) : expected.y;
+
+    if (typeof desc === "undefined") {
+      info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
+    } else {
+      info(`Simulating ${type} event: ${desc}`);
+    }
+
     if (type === "mouse") {
       yield mouse.move(x, y);
     } else if (type === "keyboard") {
       let options = shift ? {shiftKey: true} : {};
       yield EventUtils.synthesizeKey(key, options);
     }
     yield checkPosition(expected, helper);
   }
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -320,16 +320,21 @@
   visibility: hidden;
 }
 
 .ruleview-expander {
   vertical-align: middle;
   display: inline-block;
 }
 
+.ruleview-expander.theme-twisty:-moz-locale-dir(rtl) {
+  /* for preventing .theme-twisty's wrong direction in rtl; Bug 1296648 */
+  transform: none;
+}
+
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   margin-inline-start: 27px;
 }
 
 .ruleview-namecontainer,
 .ruleview-propertyvaluecontainer,
 .ruleview-propertyname,
--- a/devtools/client/webconsole/test/browser_webconsole_output_06.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_06.js
@@ -106,38 +106,40 @@ var inputTests = [
     variablesViewLabel: "Array[6]"
   },
 
   // 12 - array with long strings as elements
   {
     input: '["' + testStrIn + '", "' + testStrIn + '", "' + testStrIn + '"]',
     output: 'Array [ "' + testStrOut + '", "' + testStrOut + '", "' +
             testStrOut + '" ]',
-    inspectable: false,
+    inspectable: true,
     printOutput: "SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. ESCAPE " +
                  "ALL NEWLINE,SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. " +
                  "ESCAPE ALL NEWLINE,SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\n" +
                  "LINE ONLY. ESCAPE ALL NEWLINE",
     variablesViewLabel: "Array[3]"
   },
 
   // 13
   {
     input: '({0: "a", 1: "b"})',
     output: 'Object [ "a", "b" ]',
     printOutput: "[object Object]",
-    inspectable: false,
+    inspectable: true,
+    variablesViewLabel: "Object[2]",
   },
 
   // 14
   {
     input: '({0: "a", 42: "b"})',
     output: 'Object { 0: "a", 42: "b" }',
     printOutput: "[object Object]",
-    inspectable: false,
+    inspectable: true,
+    variablesViewLabel: "Object",
   },
 
   // 15
   {
     input: '({0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", ' +
            '7: "h", 8: "i", 9: "j", 10: "k", 11: "l"})',
     output: 'Object [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", ' +
             "2 more\u2026 ]",
@@ -160,16 +162,106 @@ var inputTests = [
   // 17
   {
     input: '({" ": "a"})',
     output: 'Object {  : "a" }',
     printOutput: "[object Object]",
     inspectable: true,
     variablesViewLabel: "Object",
   },
+
+  // 18
+  {
+    input: '({})',
+    output: 'Object {  }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 19
+  {
+    input: '({length: 0})',
+    output: 'Object [  ]',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object[0]",
+  },
+
+  // 20
+  {
+    input: '({length: 1})',
+    output: 'Object { length: 1 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 21
+  {
+    input: '({0: "a", 1: "b", length: 1})',
+    output: 'Object { 1: "b", length: 1, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 22
+  {
+    input: '({0: "a", 1: "b", length: 2})',
+    output: 'Object [ "a", "b" ]',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object[2]",
+  },
+
+  // 23
+  {
+    input: '({0: "a", 1: "b", length: 3})',
+    output: 'Object { length: 3, 2 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 24
+  {
+    input: '({0: "a", 2: "b", length: 2})',
+    output: 'Object { 2: "b", length: 2, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 25
+  {
+    input: '({0: "a", 2: "b", length: 3})',
+    output: 'Object { length: 3, 2 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 26
+  {
+    input: '({0: "a", b: "b", length: 1})',
+    output: 'Object { b: "b", length: 1, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 27
+  {
+    input: '({0: "a", b: "b", length: 2})',
+    output: 'Object { b: "b", length: 2, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
 ];
 
 function test() {
   requestLongerTimeout(2);
   Task.spawn(function* () {
     let {tab} = yield loadTab(TEST_URI);
     let hud = yield openConsole(tab);
     return checkOutputForInputs(hud, inputTests);
--- a/devtools/server/actors/highlighters/eye-dropper.js
+++ b/devtools/server/actors/highlighters/eye-dropper.js
@@ -424,18 +424,20 @@ EyeDropper.prototype = {
     if (e.shiftKey) {
       modifier = 10;
     }
 
     offsetY *= modifier;
     offsetX *= modifier;
 
     if (offsetX !== 0 || offsetY !== 0) {
-      this.magnifiedArea.x += offsetX;
-      this.magnifiedArea.y += offsetY;
+      this.magnifiedArea.x = cap(this.magnifiedArea.x + offsetX,
+                                 0, this.win.innerWidth * this.pageZoom);
+      this.magnifiedArea.y = cap(this.magnifiedArea.y + offsetY, 0,
+                                 this.win.innerHeight * this.pageZoom);
 
       this.draw();
 
       this.moveTo(this.magnifiedArea.x / this.pageZoom,
                   this.magnifiedArea.y / this.pageZoom);
 
       e.preventDefault();
     }
@@ -521,8 +523,12 @@ function toColorString(rgb, format) {
  * Produce a hex-formatted color string from rgb values.
  * @param {array} rgb Rgb values of color to stringify.
  * @return {string} Hex formatted string for color, e.g. "#FFEE00".
  */
 function hexString([r, g, b]) {
   let val = (1 << 24) + (r << 16) + (g << 8) + (b << 0);
   return "#" + val.toString(16).substr(-6).toUpperCase();
 }
+
+function cap(value, min, max) {
+  return Math.max(min, Math.min(value, max));
+}
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -1795,23 +1795,37 @@ DebuggerServer.ObjectActorPreviewers.Obj
   function PseudoArray({obj, hooks}, grip, rawObj) {
     let length = 0;
 
     let keys = obj.getOwnPropertyNames();
     if (keys.length == 0) {
       return false;
     }
 
-    // Making sure that all keys are array indices, that is:
-    // `ToString(ToUint32(key)) === key  &&  key !== "4294967295"`.
-    // Also ensuring that the keys are consecutive and start at "0",
-    // this implies checking `key !== "4294967295"` is not necessary.
+    // Pseudo-arrays should only have array indices and, optionally, a "length" property.
+    // Since array indices are sorted first, check if the last property is "length".
+    if(keys[keys.length-1] === "length") {
+      keys.pop();
+      // The value of "length" should equal the number of other properties. If eventually
+      // we allow sparse pseudo-arrays, we should check whether it's a Uint32 instead.
+      if(rawObj.length !== keys.length) {
+        return false;
+      }
+    }
+
+    // Ensure that the keys are consecutive integers starting at "0". If eventually we
+    // allow sparse pseudo-arrays, we should check that they are array indices, that is:
+    // `(key >>> 0) + '' === key && key !== "4294967295"`.
+    // Checking the last property first allows us to avoid useless iterations when
+    // there is any property which is not an array index.
+    if(keys.length && keys[keys.length-1] !== keys.length - 1 + '') {
+      return false;
+    }
     for (let key of keys) {
-      let numKey = key >>> 0; // ToUint32(key)
-      if (numKey + '' != key || numKey != length++) {
+      if (key !== (length++) + '') {
         return false;
       }
     }
 
     grip.preview = {
       kind: "ArrayLike",
       length: length,
     };
--- 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) {
@@ -8533,21 +8540,24 @@ nsDocShell::RestoreFromHistory()
     mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
   }
 
   nsCOMPtr<nsIContentViewer> oldCv(mContentViewer);
   nsCOMPtr<nsIContentViewer> newCv(viewer);
   int32_t minFontSize = 0;
   float textZoom = 1.0f;
   float pageZoom = 1.0f;
+  float overrideDPPX = 0.0f;
+
   bool styleDisabled = false;
   if (oldCv && newCv) {
     oldCv->GetMinFontSize(&minFontSize);
     oldCv->GetTextZoom(&textZoom);
     oldCv->GetFullZoom(&pageZoom);
+    oldCv->GetOverrideDPPX(&overrideDPPX);
     oldCv->GetAuthorStyleDisabled(&styleDisabled);
   }
 
   // Protect against mLSHE going away via a load triggered from
   // pagehide or unload.
   nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
 
   // Make sure to blow away our mLoadingURI just in case.  No loads
@@ -8770,16 +8780,17 @@ nsDocShell::RestoreFromHistory()
   if (++gNumberOfDocumentsLoading == 1) {
     FavorPerformanceHint(true);
   }
 
   if (oldCv && newCv) {
     newCv->SetMinFontSize(minFontSize);
     newCv->SetTextZoom(textZoom);
     newCv->SetFullZoom(pageZoom);
+    newCv->SetOverrideDPPX(overrideDPPX);
     newCv->SetAuthorStyleDisabled(styleDisabled);
   }
 
   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
   uint32_t parentSuspendCount = 0;
   if (document) {
     RefPtr<nsDocShell> parent = GetParentDocshell();
     if (parent) {
@@ -9263,16 +9274,17 @@ nsDocShell::SetupNewViewer(nsIContentVie
   nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
 
   nsAutoCString forceCharset;
   nsAutoCString hintCharset;
   int32_t hintCharsetSource;
   int32_t minFontSize;
   float textZoom;
   float pageZoom;
+  float overrideDPPX;
   bool styleDisabled;
   // |newMUDV| also serves as a flag to set the data from the above vars
   nsCOMPtr<nsIContentViewer> newCv;
 
   if (mContentViewer || parent) {
     nsCOMPtr<nsIContentViewer> oldCv;
     if (mContentViewer) {
       // Get any interesting state from old content viewer
@@ -9304,16 +9316,18 @@ nsDocShell::SetupNewViewer(nsIContentVie
         NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSetSource(&hintCharsetSource),
                           NS_ERROR_FAILURE);
         NS_ENSURE_SUCCESS(oldCv->GetMinFontSize(&minFontSize),
                           NS_ERROR_FAILURE);
         NS_ENSURE_SUCCESS(oldCv->GetTextZoom(&textZoom),
                           NS_ERROR_FAILURE);
         NS_ENSURE_SUCCESS(oldCv->GetFullZoom(&pageZoom),
                           NS_ERROR_FAILURE);
+        NS_ENSURE_SUCCESS(oldCv->GetOverrideDPPX(&overrideDPPX),
+                          NS_ERROR_FAILURE);
         NS_ENSURE_SUCCESS(oldCv->GetAuthorStyleDisabled(&styleDisabled),
                           NS_ERROR_FAILURE);
       }
     }
   }
 
   nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
   // Ensure that the content viewer is destroyed *after* the GC - bug 71515
@@ -9372,16 +9386,18 @@ nsDocShell::SetupNewViewer(nsIContentVie
     NS_ENSURE_SUCCESS(newCv->SetHintCharacterSetSource(hintCharsetSource),
                       NS_ERROR_FAILURE);
     NS_ENSURE_SUCCESS(newCv->SetMinFontSize(minFontSize),
                       NS_ERROR_FAILURE);
     NS_ENSURE_SUCCESS(newCv->SetTextZoom(textZoom),
                       NS_ERROR_FAILURE);
     NS_ENSURE_SUCCESS(newCv->SetFullZoom(pageZoom),
                       NS_ERROR_FAILURE);
+    NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX),
+                      NS_ERROR_FAILURE);
     NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled),
                       NS_ERROR_FAILURE);
   }
 
   // Stuff the bgcolor from the old pres shell into the new
   // pres shell. This improves page load continuity.
   nsCOMPtr<nsIPresShell> shell;
   mContentViewer->GetPresShell(getter_AddRefs(shell));
--- 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
@@ -13287,19 +13287,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
@@ -16355,17 +16359,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