Merge mozilla-central to mozilla-beta a=merge l10n=merge CLOSED TREE DEVEDITION_62_0b3_BUILD1 DEVEDITION_62_0b3_RELEASE FENNEC_62_0b3_BUILD1 FENNEC_62_0b3_RELEASE FIREFOX_62_0b3_BUILD1 FIREFOX_62_0b3_RELEASE
authorCiure Andrei <aciure@mozilla.com>
Mon, 25 Jun 2018 17:11:08 +0300
changeset 810287 1716b76aa7b8df189e74bf87394d3a11e0c5ac12
parent 810286 c73f274c9f2533aa3fd98af11d5ddbf4bd52d055 (current diff)
parent 810123 4f6e597104dabedfecfafa2ab63dc79fd7f8bc7a (diff)
child 810288 eacc6e8233d32eef79956e0970d6fcf41a2e1282
child 810472 262691510bbcb2ff2510c6c64da5246527203457
child 811610 1c808a55d9708518b323e0e877d509969b35d52e
push id113949
push userbmo:mstriemer@mozilla.com
push dateMon, 25 Jun 2018 17:23:48 +0000
reviewersmerge
milestone62.0
Merge mozilla-central to mozilla-beta a=merge l10n=merge CLOSED TREE
devtools/client/inspector/fonts/test/browser_fontinspector_family-unused.js
servo/tests/unit/style/parsing/length.rs
servo/tests/unit/style/parsing/value.rs
servo/tests/unit/style/properties/background.rs
toolkit/themes/windows/global/tree/twisty-preWin10.svg
toolkit/themes/windows/global/tree/twisty.svg
--- a/Makefile.in
+++ b/Makefile.in
@@ -30,17 +30,23 @@ DIST_GARBAGE = config.cache config.log c
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    .mozconfig.mk
 
 ifndef MOZ_PROFILE_USE
 # Automation builds should always have a new buildid, but for the sake of not
 # re-linking libxul on every incremental build we do not enforce this for
 # developer builds.  Tests always need a new buildid as well.
 ifneq (,$(MOZ_AUTOMATION)$(MOZ_BUILD_DATE)$(TEST_MOZBUILD))
-buildid.h source-repo.h: FORCE
+$(MDDEPDIR)/buildid.h.stub $(MDDEPDIR)/source-repo.h.stub: FORCE
+endif
+# Additionally, provide a dummy target during tests, because
+# faster/rules.mk will expect these targets to exist.
+ifdef TEST_MOZBUILD
+source-repo.h: $(MDDEPDIR)/source-repo.h.stub
+buildid.h: $(MDDEPDIR)/buildid.h.stub
 endif
 endif
 
 ifdef JS_STANDALONE
 configure_dir = $(topsrcdir)/js/src
 else
 configure_dir = $(topsrcdir)
 endif
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -941,79 +941,31 @@ var BrowserPageActions = {
   onLocationChange() {
     for (let action of PageActions.actions) {
       action.onLocationChange(window);
     }
   },
 };
 
 
-var BrowserPageActionFeedback = {
-  /**
-   * The feedback page action panel DOM node (DOM node)
-   */
-  get panelNode() {
-    delete this.panelNode;
-    return this.panelNode = document.getElementById("pageActionFeedback");
-  },
-
-  get feedbackAnimationBox() {
-    delete this.feedbackAnimationBox;
-    return this.feedbackAnimationBox = document.getElementById("pageActionFeedbackAnimatableBox");
-  },
-
-  get feedbackLabel() {
-    delete this.feedbackLabel;
-    return this.feedbackLabel = document.getElementById("pageActionFeedbackMessage");
-  },
+/**
+ * Shows the feedback popup for an action.
+ *
+ * @param  action (PageActions.Action, required)
+ *         The action associated with the feedback.
+ * @param  event (DOM event, optional)
+ *         The event that triggered the feedback.
+ * @param  messageId (string, optional)
+ *         Can be used to set a message id that is different from the action id.
+ */
+function showBrowserPageActionFeedback(action, event = null, messageId = null) {
+  let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
 
-  /**
-   * Shows the feedback popup for an action.
-   *
-   * @param  action (PageActions.Action, required)
-   *         The action associated with the feedback.
-   * @param  opts (object, optional)
-   *         An object with the following optional properties:
-   *         - event (DOM event): The event that triggered the feedback.
-   *         - textAttributeOverride (string): Normally the feedback text is
-   *           taken from an attribute on the feedback panel.  The attribute's
-   *           name is `${action.id}Feedback`.  Use this to override the
-   *           action.id part of the name.
-   *         - text (string): The text string.  If not given, an attribute on
-   *           panel is assumed to contain the text, as described above.
-   */
-  show(action, opts = {}) {
-    this.feedbackLabel.textContent =
-      opts.text ||
-      this.panelNode.getAttribute((opts.textAttributeOverride || action.id) +
-                                  "Feedback");
-    this.panelNode.hidden = false;
-
-    let event = opts.event || null;
-    let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
-    PanelMultiView.openPopup(this.panelNode, anchor, {
-      position: "bottomcenter topright",
-      triggerEvent: event,
-    }).catch(Cu.reportError);
-
-    this.panelNode.addEventListener("popupshown", () => {
-      this.feedbackAnimationBox.setAttribute("animate", "true");
-
-      // The timeout value used here allows the panel to stay open for
-      // 1 second after the text transition (duration=120ms) has finished.
-      setTimeout(() => {
-        this.panelNode.hidePopup(true);
-      }, Services.prefs.getIntPref("browser.pageActions.feedbackTimeoutMS", 1120));
-    }, {once: true});
-    this.panelNode.addEventListener("popuphidden", () => {
-      this.feedbackAnimationBox.removeAttribute("animate");
-    }, {once: true});
-  },
-};
-
+  ConfirmationHint.show(anchor, messageId || action.id, {event, hideArrow: true});
+}
 
 // built-in actions below //////////////////////////////////////////////////////
 
 // bookmark
 BrowserPageActions.bookmark = {
   onShowingInPanel(buttonNode) {
     // Update the button label via the bookmark observer.
     BookmarkingUI.updateBookmarkPageMenuItem();
@@ -1033,19 +985,17 @@ BrowserPageActions.copyURL = {
   },
 
   onCommand(event, buttonNode) {
     PanelMultiView.hidePopup(BrowserPageActions.panelNode);
     Cc["@mozilla.org/widget/clipboardhelper;1"]
       .getService(Ci.nsIClipboardHelper)
       .copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
     let action = PageActions.actionForID("copyURL");
-    BrowserPageActionFeedback.show(action, {
-      event,
-    });
+    showBrowserPageActionFeedback(action, event);
   },
 };
 
 // email link
 BrowserPageActions.emailLink = {
   onPlacedInPanel(buttonNode) {
     let action = PageActions.actionForID("emailLink");
     BrowserPageActions.takeActionTitleFromPanel(action);
@@ -1112,21 +1062,18 @@ BrowserPageActions.sendToDevice = {
       item.addEventListener("command", event => {
         if (panelNode) {
           PanelMultiView.hidePopup(panelNode);
         }
         // There are items in the subview that don't represent devices: "Sign
         // in", "Learn about Sync", etc.  Device items will be .sendtab-target.
         if (event.target.classList.contains("sendtab-target")) {
           let action = PageActions.actionForID("sendToDevice");
-          let textAttributeOverride = gSync.offline && "sendToDeviceOffline";
-          BrowserPageActionFeedback.show(action, {
-            event,
-            textAttributeOverride,
-          });
+          let messageId = gSync.offline && "sendToDeviceOffline";
+          showBrowserPageActionFeedback(action, event, messageId);
         }
       });
       return item;
     });
 
     bodyNode.removeAttribute("state");
     // In the first ~10 sec after startup, Sync may not be loaded and the list
     // of devices will be empty.
@@ -1228,19 +1175,17 @@ BrowserPageActions.addSearchEngine = {
     // above.)
     let engine = this.engines[0];
     this._installEngine(engine.uri, engine.icon);
   },
 
   _installEngine(uri, image) {
     Services.search.addEngine(uri, null, image, false, {
       onSuccess: engine => {
-        BrowserPageActionFeedback.show(this.action, {
-          text: this.strings.GetStringFromName("searchAddedFoundEngine2"),
-        });
+        showBrowserPageActionFeedback(this.action);
       },
       onError(errorCode) {
         if (errorCode != Ci.nsISearchInstallCallback.ERROR_DUPLICATE_ENGINE) {
           // Download error is shown by the search service
           return;
         }
         const kSearchBundleURI = "chrome://global/locale/search/search.properties";
         let searchBundle = Services.strings.createBundle(kSearchBundleURI);
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -114,16 +114,17 @@ var StarUI = {
               PlacesTransactions.undo().catch(Cu.reportError);
               break;
             }
             // Remove all bookmarks for the bookmark's url, this also removes
             // the tags for the url.
             PlacesTransactions.Remove(guidsForRemoval)
                               .transact().catch(Cu.reportError);
           } else if (this._isNewBookmark) {
+            this._showConfirmation();
             LibraryUI.triggerLibraryAnimation("bookmark");
           }
 
           if (!removeBookmarksOnPopupHidden) {
             this._storeRecentlyUsedFolder(selectedFolderGuid).catch(console.error);
           }
         }
         break;
@@ -398,16 +399,36 @@ var StarUI = {
       lastUsedFolderGuids.unshift(selectedFolderGuid);
     }
     if (lastUsedFolderGuids.length > 5) {
       lastUsedFolderGuids.pop();
     }
 
     await PlacesUtils.metadata.set(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY,
                                    lastUsedFolderGuids);
+  },
+
+  _showConfirmation() {
+    let anchor;
+    if (window.toolbar.visible) {
+      for (let id of ["library-button", "bookmarks-menu-button"]) {
+        let element = document.getElementById(id);
+        if (element &&
+            element.getAttribute("cui-areatype") != "menu-panel" &&
+            element.getAttribute("overflowedItem") != "true") {
+          anchor = element;
+          break;
+        }
+      }
+    }
+    if (!anchor) {
+      anchor = document.getElementById("PanelUI-menu-button");
+    }
+
+    ConfirmationHint.show(anchor, "pageBookmarked");
   }
 };
 
 var PlacesCommandHook = {
   /**
    * Adds a bookmark to the page loaded in the given browser.
    *
    * @param aBrowser
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8517,8 +8517,76 @@ TabModalPromptBox.prototype = {
   get browser() {
     let browser = this._weakBrowserRef.get();
     if (!browser) {
       throw "Stale promptbox! The associated browser is gone.";
     }
     return browser;
   },
 };
+
+var ConfirmationHint = {
+  /**
+   * Shows a transient, non-interactive confirmation hint anchored to an
+   * element, usually used in response to a user action to reaffirm that it was
+   * successful and potentially provide extra context. Examples for such hints:
+   * - "Saved to Library!" after bookmarking a page
+   * - "Sent!" after sending a tab to another device
+   * - "Queued (offline)" when attempting to send a tab to another device
+   *   while offline
+   *
+   * @param  anchor (DOM node, required)
+   *         The anchor for the panel.
+   * @param  messageId (string, required)
+   *         For getting the message string from browser.properties:
+   *         confirmationHint.<messageId>.label
+   * @param  options (object, optional)
+   *         An object with the following optional properties:
+   *         - event (DOM event): The event that triggered the feedback.
+   *         - hideArrow (boolean): Optionally hide the arrow.
+   */
+  show(anchor, messageId, options = {}) {
+    this._message.textContent =
+      gBrowserBundle.GetStringFromName("confirmationHint." + messageId + ".label");
+
+    if (options.hideArrow) {
+      this._panel.setAttribute("hidearrow", "true");
+    }
+
+    this._panel.addEventListener("popupshown", () => {
+      this._animationBox.setAttribute("animate", "true");
+
+      // The timeout value used here allows the panel to stay open for
+      // X second after the text transition (duration=120ms) has finished.
+      const DURATION = 1500;
+      setTimeout(() => {
+        this._panel.hidePopup(true);
+      }, DURATION + 120);
+    }, {once: true});
+
+    this._panel.addEventListener("popuphidden", () => {
+      this._panel.removeAttribute("hidearrow");
+      this._animationBox.removeAttribute("animate");
+    }, {once: true});
+
+    this._panel.hidden = false;
+    this._panel.openPopup(anchor, {
+      position: "bottomcenter topright",
+      triggerEvent: options.event,
+    });
+  },
+
+  get _panel() {
+    delete this._panel;
+    return this._panel = document.getElementById("confirmation-hint");
+  },
+
+  get _animationBox() {
+    delete this._animationBox;
+    return this._animationBox = document.getElementById("confirmation-hint-checkmark-animation-container");
+  },
+
+  get _message() {
+    delete this._message;
+    return this._message = document.getElementById("confirmation-hint-message");
+  },
+};
+
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -459,31 +459,29 @@
                       viewCacheId="appMenu-viewCache">
         <panelview id="pageActionPanelMainView"
                    context="pageActionContextMenu"
                    class="PanelUI-subView">
           <vbox class="panel-subview-body"/>
         </panelview>
       </panelmultiview>
     </panel>
-    <panel id="pageActionFeedback"
+
+    <panel id="confirmation-hint"
            role="alert"
            type="arrow"
            hidden="true"
            flip="slide"
            position="bottomcenter topright"
            tabspecific="true"
-           noautofocus="true"
-           copyURLFeedback="&copyURLFeedback.label;"
-           sendToDeviceFeedback="&sendToDeviceFeedback.label;"
-           sendToDeviceOfflineFeedback="&sendToDeviceOfflineFeedback.label;">
-      <hbox id="pageActionFeedbackAnimatableBox">
-        <image id="pageActionFeedbackAnimatableImage"/>
+           noautofocus="true">
+      <hbox id="confirmation-hint-checkmark-animation-container">
+        <image id="confirmation-hint-checkmark-image"/>
       </hbox>
-      <label id="pageActionFeedbackMessage"/>
+      <label id="confirmation-hint-message"/>
     </panel>
 
     <menupopup id="pageActionContextMenu"
                onpopupshowing="BrowserPageActions.onContextMenuShowing(event, this);">
       <menuitem class="pageActionContextMenuItem builtInUnpinned"
                 label="&pageAction.addToUrlbar.label;"
                 oncommand="BrowserPageActions.togglePinningForContextAction();"/>
       <menuitem class="pageActionContextMenuItem builtInPinned"
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -132,21 +132,21 @@ add_task(async function copyURLFromPanel
     Assert.ok(true, "page action panel opened");
 
     let copyURLButton =
       document.getElementById("pageAction-panel-copyURL");
     let hiddenPromise = promisePageActionPanelHidden();
     EventUtils.synthesizeMouseAtCenter(copyURLButton, {});
     await hiddenPromise;
 
-    let feedbackPanel = document.getElementById("pageActionFeedback");
+    let feedbackPanel = document.getElementById("confirmation-hint");
     let feedbackShownPromise = BrowserTestUtils.waitForEvent(feedbackPanel, "popupshown");
     await feedbackShownPromise;
     Assert.equal(feedbackPanel.anchorNode.id, "pageActionButton", "Feedback menu should be anchored on the main Page Action button");
-    let feedbackHiddenPromise = promisePanelHidden("pageActionFeedback");
+    let feedbackHiddenPromise = promisePanelHidden("confirmation-hint");
     await feedbackHiddenPromise;
 
     action.pinnedToUrlbar = false;
   });
 });
 
 add_task(async function copyURLFromURLBar() {
   // Open an actionable page so that the main page action button appears.  (It
@@ -155,23 +155,23 @@ add_task(async function copyURLFromURLBa
   await BrowserTestUtils.withNewTab(url, async () => {
     // Add action to URL bar.
     let action = PageActions._builtInActions.find(a => a.id == "copyURL");
     action.pinnedToUrlbar = true;
     registerCleanupFunction(() => action.pinnedToUrlbar = false);
 
     let copyURLButton =
       document.getElementById("pageAction-urlbar-copyURL");
-    let feedbackShownPromise = promisePanelShown("pageActionFeedback");
+    let feedbackShownPromise = promisePanelShown("confirmation-hint");
     EventUtils.synthesizeMouseAtCenter(copyURLButton, {});
 
     await feedbackShownPromise;
-    let panel = document.getElementById("pageActionFeedback");
+    let panel = document.getElementById("confirmation-hint");
     Assert.equal(panel.anchorNode.id, "pageAction-urlbar-copyURL", "Feedback menu should be anchored on the main URL bar button");
-    let feedbackHiddenPromise = promisePanelHidden("pageActionFeedback");
+    let feedbackHiddenPromise = promisePanelHidden("confirmation-hint");
     await feedbackHiddenPromise;
 
     action.pinnedToUrlbar = false;
   });
 });
 
 add_task(async function sendToDevice_nonSendable() {
   // Open a tab that's not sendable but where the page action buttons still
@@ -612,23 +612,23 @@ add_task(async function sendToDevice_inU
     info("Waiting for Send to Device panel to close after clicking a device");
     await hiddenPromise;
     Assert.ok(!urlbarButton.hasAttribute("open"),
       "URL bar button no longer has open attribute");
 
     // And then the "Sent!" notification panel should open and close by itself
     // after a moment.
     info("Waiting for the Sent! notification panel to open");
-    await promisePanelShown(BrowserPageActionFeedback.panelNode.id);
+    await promisePanelShown(ConfirmationHint._panel.id);
     Assert.equal(
-      BrowserPageActionFeedback.panelNode.anchorNode.id,
+      ConfirmationHint._panel.anchorNode.id,
       urlbarButton.id
     );
     info("Waiting for the Sent! notification panel to close");
-    await promisePanelHidden(BrowserPageActionFeedback.panelNode.id);
+    await promisePanelHidden(ConfirmationHint._panel.id);
 
     // Remove Send to Device from the urlbar.
     action.pinnedToUrlbar = false;
 
     cleanUp();
   });
 });
 
--- a/browser/base/content/test/urlbar/browser_page_action_menu_add_search_engine.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu_add_search_engine.js
@@ -44,17 +44,17 @@ add_task(async function one() {
     let enginePromise =
       promiseEngine("engine-added", "page_action_menu_add_search_engine_0");
     let hiddenPromise = promisePageActionPanelHidden();
     let feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(button, {});
     await hiddenPromise;
     let engine = await enginePromise;
     let feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine");
+    Assert.equal(feedbackText, "Search engine added!");
 
     // Open the panel again.
     await promisePageActionPanelOpen();
     EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
     await promisePageActionPanelHidden();
 
     // The action should be gone.
     actions = PageActions.actionsInPanel(window);
@@ -133,17 +133,17 @@ add_task(async function many() {
     let hiddenPromise = promisePageActionPanelHidden();
     let feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
     await hiddenPromise;
     let engines = [];
     let engine = await enginePromise;
     engines.push(engine);
     let feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+    Assert.equal(feedbackText, "Search engine added!", "Feedback text");
 
     // Open the panel and show the subview again.  The installed engine should
     // be gone.
     await promisePageActionPanelOpen();
     viewPromise = promisePageActionViewShown();
     EventUtils.synthesizeMouseAtCenter(button, {});
     await viewPromise;
     Assert.deepEqual(
@@ -160,17 +160,17 @@ add_task(async function many() {
       promiseEngine("engine-added", "page_action_menu_add_search_engine_1");
     hiddenPromise = promisePageActionPanelHidden();
     feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
     await hiddenPromise;
     engine = await enginePromise;
     engines.push(engine);
     feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+    Assert.equal(feedbackText, "Search engine added!", "Feedback text");
 
     // Open the panel again.  This time the action button should show the one
     // remaining engine.
     await promisePageActionPanelOpen();
     actions = PageActions.actionsInPanel(window);
     action = actions.find(a => a.id == "addSearchEngine");
     Assert.ok(action, "Action should be present in panel");
     expectedTitle = "Add Search Engine";
@@ -186,17 +186,17 @@ add_task(async function many() {
       promiseEngine("engine-added", "page_action_menu_add_search_engine_2");
     hiddenPromise = promisePageActionPanelHidden();
     feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(button, {});
     await hiddenPromise;
     engine = await enginePromise;
     engines.push(engine);
     feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+    Assert.equal(feedbackText, "Search engine added!", "Feedback text");
 
     // All engines are installed at this point.  Open the panel and make sure
     // the action is gone.
     await promisePageActionPanelOpen();
     EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
     await promisePageActionPanelHidden();
     actions = PageActions.actionsInPanel(window);
     action = actions.find(a => a.id == "addSearchEngine");
@@ -305,17 +305,17 @@ add_task(async function urlbarOne() {
 
     // Click the action's button.
     let enginePromise =
       promiseEngine("engine-added", "page_action_menu_add_search_engine_0");
     let feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(button, {});
     let engine = await enginePromise;
     let feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine");
+    Assert.equal(feedbackText, "Search engine added!");
 
     // The action should be gone.
     actions = PageActions.actionsInUrlbar(window);
     action = actions.find(a => a.id == "addSearchEngine");
     Assert.ok(!action, "Action should not be present in urlbar");
     button = BrowserPageActions.urlbarButtonNodeForActionID("addSearchEngine");
     Assert.ok(!button, "Action button should not be in urlbar");
 
@@ -384,17 +384,17 @@ add_task(async function urlbarMany() {
       promisePanelHidden(BrowserPageActions.activatedActionPanelNode);
     let feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
     await hiddenPromise;
     let engines = [];
     let engine = await enginePromise;
     engines.push(engine);
     let feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+    Assert.equal(feedbackText, "Search engine added!", "Feedback text");
 
     // Open the panel again.  The installed engine should be gone.
     EventUtils.synthesizeMouseAtCenter(button, {});
     view = await waitForActivatedActionPanel();
     body = view.firstChild;
     Assert.deepEqual(
       Array.map(body.childNodes, n => n.label),
       [
@@ -410,28 +410,28 @@ add_task(async function urlbarMany() {
     hiddenPromise =
       promisePanelHidden(BrowserPageActions.activatedActionPanelNode);
     feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
     await hiddenPromise;
     engine = await enginePromise;
     engines.push(engine);
     feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+    Assert.equal(feedbackText, "Search engine added!", "Feedback text");
 
     // Now there's only one engine left, so clicking the button should simply
     // install it instead of opening the activated-action panel.
     enginePromise =
       promiseEngine("engine-added", "page_action_menu_add_search_engine_2");
     feedbackPromise = promiseFeedbackPanelShownAndHidden();
     EventUtils.synthesizeMouseAtCenter(button, {});
     engine = await enginePromise;
     engines.push(engine);
     feedbackText = await feedbackPromise;
-    Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+    Assert.equal(feedbackText, "Search engine added!", "Feedback text");
 
     // All engines are installed at this point.  The action should be gone.
     actions = PageActions.actionsInUrlbar(window);
     action = actions.find(a => a.id == "addSearchEngine");
     Assert.ok(!action, "Action should be gone");
     button = BrowserPageActions.urlbarButtonNodeForActionID("addSearchEngine");
     Assert.ok(!button, "Button should not be in urlbar");
 
@@ -516,20 +516,20 @@ function promiseEngine(expectedData, exp
     info(`Got engine ${engine.wrappedJSObject.name} ${data}`);
     return expectedData == data &&
            expectedEngineName == engine.wrappedJSObject.name;
   }).then(([engine, data]) => engine);
 }
 
 function promiseFeedbackPanelShownAndHidden() {
   info("Waiting for feedback panel popupshown");
-  return BrowserTestUtils.waitForEvent(BrowserPageActionFeedback.panelNode, "popupshown").then(() => {
+  return BrowserTestUtils.waitForEvent(ConfirmationHint._panel, "popupshown").then(() => {
     info("Got feedback panel popupshown. Now waiting for popuphidden");
-    return BrowserTestUtils.waitForEvent(BrowserPageActionFeedback.panelNode, "popuphidden")
-          .then(() => BrowserPageActionFeedback.feedbackLabel.textContent);
+    return BrowserTestUtils.waitForEvent(ConfirmationHint._panel, "popuphidden")
+          .then(() => ConfirmationHint._message.textContent);
   });
 }
 
 function promisePlacedInUrlbar() {
   let action = PageActions.actionForID("addSearchEngine");
   return new Promise(resolve => {
     let onPlaced = action._onPlacedInUrlbar;
     action._onPlacedInUrlbar = button => {
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 2.0.602
+Current extension version is: 2.0.625
 
-Taken from upstream commit: 3b07147d
+Taken from upstream commit: e8b50883
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.602';
-var pdfjsBuild = '3b07147d';
+var pdfjsVersion = '2.0.625';
+var pdfjsBuild = 'e8b50883';
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 var pdfjsDisplayAPI = __w_pdfjs_require__(6);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(18);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(19);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(7);
 var pdfjsDisplaySVG = __w_pdfjs_require__(20);
 let pdfjsDisplayWorkerOptions = __w_pdfjs_require__(12);
 let pdfjsDisplayAPICompatibility = __w_pdfjs_require__(9);
@@ -820,21 +820,16 @@ var Util = function UtilClosure() {
     romanBuf.push(ROMAN_NUMBER_MAP[pos]);
     pos = number / 10 | 0;
     number %= 10;
     romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]);
     romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);
     var romanStr = romanBuf.join('');
     return lowerCase ? romanStr.toLowerCase() : romanStr;
   };
-  Util.extendObj = function extendObj(obj1, obj2) {
-    for (var key in obj2) {
-      obj1[key] = obj2[key];
-    }
-  };
   Util.inherit = function Util_inherit(sub, base, prototype) {
     sub.prototype = Object.create(base.prototype);
     sub.prototype.constructor = sub;
     for (var prop in prototype) {
       sub.prototype[prop] = prototype[prop];
     }
   };
   return Util;
@@ -4150,20 +4145,20 @@ function getDocument(src) {
   }
   if (typeof params.isEvalSupported !== 'boolean') {
     params.isEvalSupported = true;
   }
   if (typeof params.disableFontFace !== 'boolean') {
     params.disableFontFace = _api_compatibility.apiCompatibilityParams.disableFontFace || false;
   }
   if (typeof params.disableRange !== 'boolean') {
-    params.disableRange = _api_compatibility.apiCompatibilityParams.disableRange || false;
+    params.disableRange = false;
   }
   if (typeof params.disableStream !== 'boolean') {
-    params.disableStream = _api_compatibility.apiCompatibilityParams.disableStream || false;
+    params.disableStream = false;
   }
   if (typeof params.disableAutoFetch !== 'boolean') {
     params.disableAutoFetch = false;
   }
   if (typeof params.disableCreateObjectURL !== 'boolean') {
     params.disableCreateObjectURL = _api_compatibility.apiCompatibilityParams.disableCreateObjectURL || false;
   }
   (0, _util.setVerbosityLevel)(params.verbosity);
@@ -4223,17 +4218,17 @@ function _fetchDocument(worker, source, 
     return Promise.reject(new Error('Worker was destroyed'));
   }
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.0.602',
+    apiVersion: '2.0.625',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -4560,17 +4555,17 @@ var PDFPageProxy = function PDFPageProxy
       let readableStream = this.streamTextContent(params);
       return new Promise(function (resolve, reject) {
         function pump() {
           reader.read().then(function ({ value, done }) {
             if (done) {
               resolve(textContent);
               return;
             }
-            _util.Util.extendObj(textContent.styles, value.styles);
+            Object.assign(textContent.styles, value.styles);
             textContent.items.push(...value.items);
             pump();
           }, reject);
         }
         let reader = readableStream.getReader();
         let textContent = {
           items: [],
           styles: Object.create(null)
@@ -5357,18 +5352,16 @@ var WorkerTransport = function WorkerTra
         }
         this.commonObjs.clear();
         this.fontLoader.clear();
       });
     },
     get loadingParams() {
       let params = this._params;
       return (0, _util.shadow)(this, 'loadingParams', {
-        disableRange: params.disableRange,
-        disableStream: params.disableStream,
         disableAutoFetch: params.disableAutoFetch,
         disableCreateObjectURL: params.disableCreateObjectURL,
         disableFontFace: params.disableFontFace,
         nativeImageDecoderSupport: params.nativeImageDecoderSupport
       });
     }
   };
   return WorkerTransport;
@@ -5564,18 +5557,18 @@ var InternalRenderTask = function Intern
         }
       });
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.0.602';
-  exports.build = build = '3b07147d';
+  exports.version = version = '2.0.625';
+  exports.build = build = 'e8b50883';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamFactory = setPDFNetworkStreamFactory;
@@ -10062,17 +10055,17 @@ var renderTextLayer = function renderTex
         capability.resolve();
       } else if (this._textContentStream) {
         let pump = () => {
           this._reader.read().then(({ value, done }) => {
             if (done) {
               capability.resolve();
               return;
             }
-            _util.Util.extendObj(styleCache, value.styles);
+            Object.assign(styleCache, value.styles);
             this._processItems(value.items, styleCache);
             pump();
           }, capability.reject);
         };
         this._reader = this._textContentStream.getReader();
         pump();
       } else {
         throw new Error('Neither "textContent" nor "textContentStream"' + ' parameters specified.');
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.602';
-var pdfjsBuild = '3b07147d';
+var pdfjsVersion = '2.0.625';
+var pdfjsBuild = 'e8b50883';
 var pdfjsCoreWorker = __w_pdfjs_require__(1);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -322,17 +322,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.0.602';
+    let workerVersion = '2.0.625';
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
     var handler = new _message_handler.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
@@ -1359,21 +1359,16 @@ var Util = function UtilClosure() {
     romanBuf.push(ROMAN_NUMBER_MAP[pos]);
     pos = number / 10 | 0;
     number %= 10;
     romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]);
     romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);
     var romanStr = romanBuf.join('');
     return lowerCase ? romanStr.toLowerCase() : romanStr;
   };
-  Util.extendObj = function extendObj(obj1, obj2) {
-    for (var key in obj2) {
-      obj1[key] = obj2[key];
-    }
-  };
   Util.inherit = function Util_inherit(sub, base, prototype) {
     sub.prototype = Object.create(base.prototype);
     sub.prototype.constructor = sub;
     for (var prop in prototype) {
       sub.prototype[prop] = prototype[prop];
     }
   };
   return Util;
@@ -6461,24 +6456,46 @@ var XRef = function XRefClosure() {
       if (!recoveryMode) {
         trailerDict = this.readXRef();
       } else {
         (0, _util.warn)('Indexing all PDF objects');
         trailerDict = this.indexObjects();
       }
       trailerDict.assignXref(this);
       this.trailer = trailerDict;
-      var encrypt = trailerDict.get('Encrypt');
+      let encrypt;
+      try {
+        encrypt = trailerDict.get('Encrypt');
+      } catch (ex) {
+        if (ex instanceof _util.MissingDataException) {
+          throw ex;
+        }
+        (0, _util.warn)(`XRef.parse - Invalid "Encrypt" reference: "${ex}".`);
+      }
       if ((0, _primitives.isDict)(encrypt)) {
         var ids = trailerDict.get('ID');
         var fileId = ids && ids.length ? ids[0] : '';
         encrypt.suppressEncryption = true;
         this.encrypt = new _crypto.CipherTransformFactory(encrypt, fileId, this.pdfManager.password);
       }
-      if (!(this.root = trailerDict.get('Root'))) {
+      let root;
+      try {
+        root = trailerDict.get('Root');
+      } catch (ex) {
+        if (ex instanceof _util.MissingDataException) {
+          throw ex;
+        }
+        (0, _util.warn)(`XRef.parse - Invalid "Root" reference: "${ex}".`);
+      }
+      if ((0, _primitives.isDict)(root) && root.has('Pages')) {
+        this.root = root;
+      } else {
+        if (!recoveryMode) {
+          throw new _util.XRefParseException();
+        }
         throw new _util.FormatError('Invalid root reference');
       }
     },
     processXRefTable: function XRef_processXRefTable(parser) {
       if (!('tableState' in this)) {
         this.tableState = {
           entryNum: 0,
           streamPos: parser.lexer.stream.pos,
@@ -6729,17 +6746,17 @@ var XRef = function XRefClosure() {
             } else {
               let objToken = nestedObjRegExp.exec(tokenStr);
               if (objToken && objToken[1]) {
                 (0, _util.warn)('indexObjects: Found new "obj" inside of another "obj", ' + 'caused by missing "endobj" -- trying to recover.');
                 contentLength -= objToken[1].length;
                 break;
               }
             }
-            startPos += contentLength;
+            startPos = endPos;
           }
           let content = buffer.subarray(position, position + contentLength);
           var xrefTagOffset = skipUntil(content, 0, xrefBytes);
           if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) {
             xrefStms.push(position - stream.start);
             this.xrefstms[position - stream.start] = 1;
           }
           position += contentLength;
@@ -6750,34 +6767,47 @@ var XRef = function XRefClosure() {
           position += token.length + 1;
         }
       }
       var i, ii;
       for (i = 0, ii = xrefStms.length; i < ii; ++i) {
         this.startXRefQueue.push(xrefStms[i]);
         this.readXRef(true);
       }
-      var dict;
+      let trailerDict;
       for (i = 0, ii = trailers.length; i < ii; ++i) {
         stream.pos = trailers[i];
         var parser = new _parser.Parser(new _parser.Lexer(stream), true, this, true);
         var obj = parser.getObj();
         if (!(0, _primitives.isCmd)(obj, 'trailer')) {
           continue;
         }
-        dict = parser.getObj();
+        let dict = parser.getObj();
         if (!(0, _primitives.isDict)(dict)) {
           continue;
         }
+        let rootDict;
+        try {
+          rootDict = dict.get('Root');
+        } catch (ex) {
+          if (ex instanceof _util.MissingDataException) {
+            throw ex;
+          }
+          continue;
+        }
+        if (!(0, _primitives.isDict)(rootDict) || !rootDict.has('Pages')) {
+          continue;
+        }
         if (dict.has('ID')) {
           return dict;
         }
-      }
-      if (dict) {
-        return dict;
+        trailerDict = dict;
+      }
+      if (trailerDict) {
+        return trailerDict;
       }
       throw new _util.InvalidPDFException('Invalid PDF structure');
     },
     readXRef: function XRef_readXRef(recoveryMode) {
       var stream = this.stream;
       let startXRefParsedCache = Object.create(null);
       try {
         while (this.startXRefQueue.length) {
@@ -8110,38 +8140,44 @@ var Lexer = function LexerClosure() {
     },
     peekChar: function Lexer_peekChar() {
       return this.stream.peekByte();
     },
     getNumber: function Lexer_getNumber() {
       var ch = this.currentChar;
       var eNotation = false;
       var divideBy = 0;
-      var sign = 1;
+      var sign = 0;
       if (ch === 0x2D) {
         sign = -1;
         ch = this.nextChar();
         if (ch === 0x2D) {
           ch = this.nextChar();
         }
       } else if (ch === 0x2B) {
-        ch = this.nextChar();
-      }
-      if (ch === 0x2E) {
-        divideBy = 10;
+        sign = 1;
         ch = this.nextChar();
       }
       if (ch === 0x0A || ch === 0x0D) {
         do {
           ch = this.nextChar();
         } while (ch === 0x0A || ch === 0x0D);
       }
+      if (ch === 0x2E) {
+        divideBy = 10;
+        ch = this.nextChar();
+      }
       if (ch < 0x30 || ch > 0x39) {
+        if (divideBy === 10 && sign === 0 && ((0, _util.isSpace)(ch) || ch === -1)) {
+          (0, _util.warn)('Lexer.getNumber - treating a single decimal point as zero.');
+          return 0;
+        }
         throw new _util.FormatError(`Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`);
       }
+      sign = sign || 1;
       var baseValue = ch - 0x30;
       var powerValue = 0;
       var powerValueSign = 1;
       while ((ch = this.nextChar()) >= 0) {
         if (0x30 <= ch && ch <= 0x39) {
           var currentDigit = ch - 0x30;
           if (eNotation) {
             powerValue = powerValue * 10 + currentDigit;
@@ -18797,17 +18833,17 @@ var OperatorList = function OperatorList
       this.addOp(_util.OPS.dependency, [dependency]);
     },
     addDependencies(dependencies) {
       for (var key in dependencies) {
         this.addDependency(key);
       }
     },
     addOpList(opList) {
-      _util.Util.extendObj(this.dependencies, opList.dependencies);
+      Object.assign(this.dependencies, opList.dependencies);
       for (var i = 0, ii = opList.length; i < ii; i++) {
         this.addOp(opList.fnArray[i], opList.argsArray[i]);
       }
     },
     getIR() {
       return {
         fnArray: this.fnArray,
         argsArray: this.argsArray,
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -3201,20 +3201,16 @@ const defaultOptions = {
   externalLinkTarget: {
     value: 0,
     kind: OptionKind.VIEWER
   },
   imageResourcesPath: {
     value: './images/',
     kind: OptionKind.VIEWER
   },
-  locale: {
-    value: typeof navigator !== 'undefined' ? navigator.language : 'en-US',
-    kind: OptionKind.VIEWER
-  },
   maxCanvasPixels: {
     value: _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels || 16777216,
     kind: OptionKind.VIEWER
   },
   pdfBugEnabled: {
     value: false,
     kind: OptionKind.VIEWER
   },
@@ -3258,21 +3254,21 @@ const defaultOptions = {
     value: _pdfjsLib.apiCompatibilityParams.disableCreateObjectURL || false,
     kind: OptionKind.API
   },
   disableFontFace: {
     value: false,
     kind: OptionKind.API
   },
   disableRange: {
-    value: _pdfjsLib.apiCompatibilityParams.disableRange || false,
+    value: false,
     kind: OptionKind.API
   },
   disableStream: {
-    value: _pdfjsLib.apiCompatibilityParams.disableStream || false,
+    value: false,
     kind: OptionKind.API
   },
   isEvalSupported: {
     value: true,
     kind: OptionKind.API
   },
   maxImageSize: {
     value: -1,
@@ -3294,16 +3290,17 @@ const defaultOptions = {
     value: null,
     kind: OptionKind.WORKER
   },
   workerSrc: {
     value: '../build/pdf.worker.js',
     kind: OptionKind.WORKER
   }
 };
+;
 const userOptions = Object.create(null);
 class AppOptions {
   constructor() {
     throw new Error('Cannot initialize AppOptions.');
   }
   static get(name) {
     let defaultOption = defaultOptions[name],
         userOption = userOptions[name];
@@ -6344,17 +6341,17 @@ var _ui_utils = __webpack_require__(2);
 
 var _pdfjsLib = __webpack_require__(3);
 
 class PDFViewer extends _base_viewer.BaseViewer {
   get _setDocumentViewerElement() {
     return (0, _pdfjsLib.shadow)(this, '_setDocumentViewerElement', this.viewer);
   }
   _scrollIntoView({ pageDiv, pageSpot = null }) {
-    if (!pageSpot) {
+    if (!pageSpot && !this.isInPresentationMode) {
       const left = pageDiv.offsetLeft + pageDiv.clientLeft;
       const right = left + pageDiv.clientWidth;
       const { scrollLeft, clientWidth } = this.container;
       if (this.scrollMode === _base_viewer.ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) {
         pageSpot = {
           left: 0,
           top: 0
         };
@@ -6405,37 +6402,79 @@ class PDFViewer extends _base_viewer.Bas
       this._setCurrentPageNumber(currentId);
     }
     this._updateLocation(visible.first);
     this.eventBus.dispatch('updateviewarea', {
       source: this,
       location: this._location
     });
   }
+  get _isScrollModeHorizontal() {
+    return this.isInPresentationMode ? false : this.scrollMode === _base_viewer.ScrollMode.HORIZONTAL;
+  }
+  setScrollMode(mode) {
+    if (mode === this.scrollMode) {
+      return;
+    }
+    super.setScrollMode(mode);
+    this.eventBus.dispatch('scrollmodechanged', { mode });
+    this._updateScrollModeClasses();
+    if (!this.pdfDocument) {
+      return;
+    }
+    const pageNumber = this._currentPageNumber;
+    if (isNaN(this._currentScaleValue)) {
+      this._setScale(this._currentScaleValue, true);
+    }
+    this.scrollPageIntoView({ pageNumber });
+    this.update();
+  }
+  _updateScrollModeClasses() {
+    const { scrollMode, viewer } = this;
+    if (scrollMode === _base_viewer.ScrollMode.HORIZONTAL) {
+      viewer.classList.add('scrollHorizontal');
+    } else {
+      viewer.classList.remove('scrollHorizontal');
+    }
+    if (scrollMode === _base_viewer.ScrollMode.WRAPPED) {
+      viewer.classList.add('scrollWrapped');
+    } else {
+      viewer.classList.remove('scrollWrapped');
+    }
+  }
+  setSpreadMode(mode) {
+    if (mode === this.spreadMode) {
+      return;
+    }
+    super.setSpreadMode(mode);
+    this.eventBus.dispatch('spreadmodechanged', { mode });
+    this._regroupSpreads();
+  }
   _regroupSpreads() {
-    const container = this._setDocumentViewerElement,
+    if (!this.pdfDocument) {
+      return;
+    }
+    const viewer = this.viewer,
           pages = this._pages;
-    while (container.firstChild) {
-      container.firstChild.remove();
-    }
+    viewer.textContent = '';
     if (this.spreadMode === _base_viewer.SpreadMode.NONE) {
       for (let i = 0, iMax = pages.length; i < iMax; ++i) {
-        container.appendChild(pages[i].div);
+        viewer.appendChild(pages[i].div);
       }
     } else {
       const parity = this.spreadMode - 1;
       let spread = null;
       for (let i = 0, iMax = pages.length; i < iMax; ++i) {
         if (spread === null) {
           spread = document.createElement('div');
           spread.className = 'spread';
-          container.appendChild(spread);
+          viewer.appendChild(spread);
         } else if (i % 2 === parity) {
           spread = spread.cloneNode(false);
-          container.appendChild(spread);
+          viewer.appendChild(spread);
         }
         spread.appendChild(pages[i].div);
       }
     }
     this.scrollPageIntoView({ pageNumber: this._currentPageNumber });
     this.update();
   }
 }
@@ -6549,17 +6588,19 @@ class BaseViewer {
       this.renderingQueue = options.renderingQueue;
     }
     this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdate.bind(this));
     this.presentationModeState = _ui_utils.PresentationModeState.UNKNOWN;
     this._resetView();
     if (this.removePageBorders) {
       this.viewer.classList.add('removePageBorders');
     }
-    this._updateScrollModeClasses();
+    if (this.scrollMode !== ScrollMode.VERTICAL) {
+      this._updateScrollModeClasses();
+    }
   }
   get pagesCount() {
     return this._pages.length;
   }
   getPageView(index) {
     return this._pages[index];
   }
   get pageViewsReady() {
@@ -6853,19 +6894,20 @@ class BaseViewer {
     let scale = parseFloat(value);
     if (scale > 0) {
       this._setScaleUpdatePages(scale, value, noScroll, false);
     } else {
       let currentPage = this._pages[this._currentPageNumber - 1];
       if (!currentPage) {
         return;
       }
-      let hPadding = this.isInPresentationMode || this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING;
-      let vPadding = this.isInPresentationMode || this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING;
-      if (this.scrollMode === ScrollMode.HORIZONTAL) {
+      const noPadding = this.isInPresentationMode || this.removePageBorders;
+      let hPadding = noPadding ? 0 : _ui_utils.SCROLLBAR_PADDING;
+      let vPadding = noPadding ? 0 : _ui_utils.VERTICAL_PADDING;
+      if (!noPadding && this._isScrollModeHorizontal) {
         const temp = hPadding;
         hPadding = vPadding;
         vPadding = temp;
       }
       let pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale;
       let pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale;
       switch (value) {
         case 'page-actual':
@@ -7025,16 +7067,19 @@ class BaseViewer {
     throw new Error('Not implemented: update');
   }
   containsElement(element) {
     return this.container.contains(element);
   }
   focus() {
     this.container.focus();
   }
+  get _isScrollModeHorizontal() {
+    throw new Error('Not implemented: _isScrollModeHorizontal');
+  }
   get isInPresentationMode() {
     return this.presentationModeState === _ui_utils.PresentationModeState.FULLSCREEN;
   }
   get isChangingPresentationMode() {
     return this.presentationModeState === _ui_utils.PresentationModeState.CHANGING;
   }
   get isHorizontalScrollbarEnabled() {
     return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth;
@@ -7077,17 +7122,17 @@ class BaseViewer {
       console.error('Unable to get page for page view', reason);
       this._pagesRequests[pageNumber] = null;
     });
     this._pagesRequests[pageNumber] = promise;
     return promise;
   }
   forceRendering(currentlyVisiblePages) {
     let visiblePages = currentlyVisiblePages || this._getVisiblePages();
-    let scrollAhead = this.scrollMode === ScrollMode.HORIZONTAL ? this.scroll.right : this.scroll.down;
+    let scrollAhead = this._isScrollModeHorizontal ? this.scroll.right : this.scroll.down;
     let pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead);
     if (pageView) {
       this._ensurePdfPageLoaded(pageView).then(() => {
         this.renderingQueue.renderView(pageView);
       });
       return true;
     }
     return false;
@@ -7151,40 +7196,27 @@ class BaseViewer {
       return {
         width: size.height,
         height: size.width,
         rotation: (size.rotation + 90) % 360
       };
     });
   }
   setScrollMode(mode) {
-    if (mode !== this.scrollMode) {
-      this.scrollMode = mode;
-      this._updateScrollModeClasses();
-      this.eventBus.dispatch('scrollmodechanged', { mode });
-      const pageNumber = this._currentPageNumber;
-      if (isNaN(this._currentScaleValue)) {
-        this._setScale(this._currentScaleValue, this.isInPresentationMode);
-      }
-      this.scrollPageIntoView({ pageNumber });
-      this.update();
-    }
-  }
-  _updateScrollModeClasses() {
-    const mode = this.scrollMode,
-          { classList } = this.viewer;
-    classList.toggle('scrollHorizontal', mode === ScrollMode.HORIZONTAL);
-    classList.toggle('scrollWrapped', mode === ScrollMode.WRAPPED);
-  }
+    if (!Number.isInteger(mode) || !Object.values(ScrollMode).includes(mode)) {
+      throw new Error(`Invalid scroll mode: ${mode}`);
+    }
+    this.scrollMode = mode;
+  }
+  _updateScrollModeClasses() {}
   setSpreadMode(mode) {
-    if (mode !== this.spreadMode) {
-      this.spreadMode = mode;
-      this.eventBus.dispatch('spreadmodechanged', { mode });
-      this._regroupSpreads();
-    }
+    if (!Number.isInteger(mode) || !Object.values(SpreadMode).includes(mode)) {
+      throw new Error(`Invalid spread mode: ${mode}`);
+    }
+    this.spreadMode = mode;
   }
   _regroupSpreads() {}
 }
 exports.BaseViewer = BaseViewer;
 exports.ScrollMode = ScrollMode;
 exports.SpreadMode = SpreadMode;
 
 /***/ }),
@@ -8171,26 +8203,48 @@ class SecondaryToolbar {
         case _pdf_cursor_tools.CursorTool.HAND:
           buttons.cursorHandToolButton.classList.add('toggled');
           break;
       }
     });
   }
   _bindScrollModeListener(buttons) {
     this.eventBus.on('scrollmodechanged', function (evt) {
-      buttons.scrollVerticalButton.classList.toggle('toggled', evt.mode === _base_viewer.ScrollMode.VERTICAL);
-      buttons.scrollHorizontalButton.classList.toggle('toggled', evt.mode === _base_viewer.ScrollMode.HORIZONTAL);
-      buttons.scrollWrappedButton.classList.toggle('toggled', evt.mode === _base_viewer.ScrollMode.WRAPPED);
+      buttons.scrollVerticalButton.classList.remove('toggled');
+      buttons.scrollHorizontalButton.classList.remove('toggled');
+      buttons.scrollWrappedButton.classList.remove('toggled');
+      switch (evt.mode) {
+        case _base_viewer.ScrollMode.VERTICAL:
+          buttons.scrollVerticalButton.classList.add('toggled');
+          break;
+        case _base_viewer.ScrollMode.HORIZONTAL:
+          buttons.scrollHorizontalButton.classList.add('toggled');
+          break;
+        case _base_viewer.ScrollMode.WRAPPED:
+          buttons.scrollWrappedButton.classList.add('toggled');
+          break;
+      }
     });
   }
   _bindSpreadModeListener(buttons) {
     this.eventBus.on('spreadmodechanged', function (evt) {
-      buttons.spreadNoneButton.classList.toggle('toggled', evt.mode === _base_viewer.SpreadMode.NONE);
-      buttons.spreadOddButton.classList.toggle('toggled', evt.mode === _base_viewer.SpreadMode.ODD);
-      buttons.spreadEvenButton.classList.toggle('toggled', evt.mode === _base_viewer.SpreadMode.EVEN);
+      buttons.spreadNoneButton.classList.remove('toggled');
+      buttons.spreadOddButton.classList.remove('toggled');
+      buttons.spreadEvenButton.classList.remove('toggled');
+      switch (evt.mode) {
+        case _base_viewer.SpreadMode.NONE:
+          buttons.spreadNoneButton.classList.add('toggled');
+          break;
+        case _base_viewer.SpreadMode.ODD:
+          buttons.spreadOddButton.classList.add('toggled');
+          break;
+        case _base_viewer.SpreadMode.EVEN:
+          buttons.spreadEvenButton.classList.add('toggled');
+          break;
+      }
     });
   }
   open() {
     if (this.opened) {
       return;
     }
     this.opened = true;
     this._setMaxHeight();
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -47,18 +47,16 @@ can reach it easily. -->
 <!ENTITY  unpinTab.label                     "Unpin Tab">
 <!ENTITY  unpinTab.accesskey                 "b">
 <!ENTITY  sendTabToDevice.label              "Send Tab to Device">
 <!ENTITY  sendTabToDevice.accesskey          "n">
 <!ENTITY  sendPageToDevice.label             "Send Page to Device">
 <!ENTITY  sendPageToDevice.accesskey         "n">
 <!ENTITY  sendLinkToDevice.label             "Send Link to Device">
 <!ENTITY  sendLinkToDevice.accesskey         "n">
-<!ENTITY  sendToDeviceFeedback.label         "Sent!">
-<!ENTITY  sendToDeviceOfflineFeedback.label  "Queued (offline)">
 <!ENTITY  moveToNewWindow.label              "Move to New Window">
 <!ENTITY  moveToNewWindow.accesskey          "W">
 <!ENTITY  reopenInContainer.label            "Reopen in Container">
 <!ENTITY  reopenInContainer.accesskey        "e">
 <!ENTITY  bookmarkAllTabs.label              "Bookmark All Tabs…">
 <!ENTITY  bookmarkAllTabs.accesskey          "T">
 <!ENTITY  undoCloseTab.label                 "Undo Close Tab">
 <!ENTITY  undoCloseTab.accesskey             "U">
@@ -402,42 +400,31 @@ These should match what Safari and other
 <!ENTITY appMenuRemoteTabs.managedevices.label "Manage Devices…">
 <!ENTITY appMenuRemoteTabs.sidebar.label "View Synced Tabs Sidebar">
 <!ENTITY appMenuRemoteTabs.connectdevice.label "Connect Another Device">
 
 <!ENTITY appMenuRecentHighlights.label "Recent Highlights">
 
 <!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar">
 <!ENTITY customizeMenu.addToToolbar.accesskey "A">
-<!ENTITY customizeMenu.addToPanel.label "Add to Menu">
-<!ENTITY customizeMenu.addToPanel.accesskey "M">
 <!-- LOCALIZATION NOTE (customizeMenu.addToOverflowMenu.label,
      customizeMenu.pinToOverflowMenu.label, customizeMenu.unpinFromOverflowMenu.label)
      The overflow menu is the menu that appears if you click the chevron (>> button)
-     in the location bar. These labels are only used in Photon, where you can put
-     items into this menu permanently (pinned). -->
+     in the location bar. -->
 <!ENTITY customizeMenu.addToOverflowMenu.label "Add to Overflow Menu">
 <!ENTITY customizeMenu.addToOverflowMenu.accesskey "M">
-<!ENTITY customizeMenu.moveToToolbar.label "Move to Toolbar">
-<!ENTITY customizeMenu.moveToToolbar.accesskey "o">
-<!-- LOCALIZATION NOTE (customizeMenu.moveToPanel.accesskey, customizeMenu.pinToOverflowMenu.accesskey)
+<!-- LOCALIZATION NOTE (customizeMenu.pinToOverflowMenu.accesskey)
      can appear on the same context menu as menubarCmd and personalbarCmd,
-     so they should have different access keys. customizeMenu.moveToToolbar and
-     customizeMenu.moveToPanel are mutually exclusive, so can share access
-     keys.  -->
-<!ENTITY customizeMenu.moveToPanel.label "Move to Menu">
-<!ENTITY customizeMenu.moveToPanel.accesskey "o">
+     so they should have different access keys.  -->
 <!ENTITY customizeMenu.pinToOverflowMenu.label "Pin to Overflow Menu">
 <!ENTITY customizeMenu.pinToOverflowMenu.accesskey "P">
 <!ENTITY customizeMenu.unpinFromOverflowMenu.label "Unpin from Overflow Menu">
 <!ENTITY customizeMenu.unpinFromOverflowMenu.accesskey "U">
 <!ENTITY customizeMenu.removeFromToolbar.label "Remove from Toolbar">
 <!ENTITY customizeMenu.removeFromToolbar.accesskey "R">
-<!ENTITY customizeMenu.removeFromMenu.label "Remove from Menu">
-<!ENTITY customizeMenu.removeFromMenu.accesskey "R">
 <!ENTITY customizeMenu.addMoreItems.label "Add More Items…">
 <!ENTITY customizeMenu.addMoreItems.accesskey "A">
 <!ENTITY customizeMenu.autoHideDownloadsButton.label "Auto-Hide in Toolbar">
 <!ENTITY customizeMenu.autoHideDownloadsButton.accesskey "A">
 <!ENTITY customizeMenu.manageExtension.label "Manage Extension">
 <!ENTITY customizeMenu.manageExtension.accesskey "E">
 
 <!-- LOCALIZATION NOTE (moreMenu.label) This label is used in the new Photon
@@ -575,17 +562,16 @@ These should match what Safari and other
 <!ENTITY setDesktopBackgroundCmd.accesskey  "S">
 <!ENTITY bookmarkPageCmd2.label       "Bookmark This Page">
 <!ENTITY bookmarkPageCmd2.accesskey   "m">
 <!ENTITY bookmarkThisLinkCmd.label      "Bookmark This Link">
 <!ENTITY bookmarkThisLinkCmd.accesskey  "L">
 <!ENTITY bookmarkThisFrameCmd.label      "Bookmark This Frame">
 <!ENTITY bookmarkThisFrameCmd.accesskey  "m">
 <!ENTITY pageAction.copyLink.label    "Copy Link">
-<!ENTITY copyURLFeedback.label        "Copied!">
 <!ENTITY emailPageCmd.label           "Email Link…">
 <!ENTITY emailPageCmd.accesskey       "E">
 <!ENTITY savePageCmd.label            "Save Page As…">
 <!ENTITY savePageCmd.accesskey        "A">
 <!-- alternate for content area context menu -->
 <!ENTITY savePageCmd.accesskey2       "P">
 <!ENTITY savePageCmd.commandkey       "s">
 <!ENTITY saveFrameCmd.label           "Save Frame As…">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -965,8 +965,14 @@ autoplay.DontAllow.accesskey = n
 autoplay.remember = Remember this decision
 # LOCALIZATION NOTE (autoplay.message): %S is the name of the site URL (https://...) trying to autoplay media
 autoplay.message = Will you allow %S to autoplay media with sound?
 autoplay.messageWithFile = Will you allow this file to autoplay media with sound?
 # LOCALIZATION NOTE (panel.back):
 # This is used by screen readers to label the "back" button in various browser
 # popup panels, including the sliding subviews of the main menu.
 panel.back = Back
+
+confirmationHint.sendToDevice.label = Sent!
+confirmationHint.sendToDeviceOffline.label = Queued (offline)
+confirmationHint.copyURL.label = Copied to clipboard!
+confirmationHint.pageBookmarked.label = Saved to Library!
+confirmationHint.addSearchEngine.label = Search engine added!
--- a/browser/locales/en-US/chrome/browser/search.properties
+++ b/browser/locales/en-US/chrome/browser/search.properties
@@ -29,17 +29,16 @@ cmd_showSuggestions_accesskey=S
 cmd_addFoundEngine=Add “%S”
 # LOCALIZATION NOTE (cmd_addFoundEngineMenu): When more than 5 engines
 # are offered by a web page, instead of listing all of them in the
 # search panel using the cmd_addFoundEngine string, they will be
 # grouped in a submenu using cmd_addFoundEngineMenu as a label.
 cmd_addFoundEngineMenu=Add search engine
 
 searchAddFoundEngine2=Add Search Engine
-searchAddedFoundEngine2=Added Search Engine
 
 # LOCALIZATION NOTE (searchForSomethingWith2):
 # This string is used to build the header above the list of one-click
 # search providers:  "Search for <user-typed string> with:"
 searchForSomethingWith2=Search for %S with:
 
 # LOCALIZATION NOTE (searchWithHeader):
 # The wording of this string should be as close as possible to
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -214,88 +214,90 @@ panel[photon] > .panel-arrowcontainer > 
 #wrapper-zoom-controls:-moz-any([place="palette"],[place="menu-panel"]) > #zoom-controls {
   margin-inline-start: 0;
 }
 
 #BMB_bookmarksPopup {
   max-width: @standaloneSubviewWidth@;
 }
 
-#pageActionFeedback > .panel-arrowcontainer > .panel-arrowbox {
+#confirmation-hint {
+  --arrowpanel-background: #058b00;
+  --arrowpanel-border-color: #046b00;
+  --arrowpanel-color: #fff;
+}
+
+#confirmation-hint[hidearrow] > .panel-arrowcontainer > .panel-arrowbox {
   /* Don't display the arrow but keep the popup at the same vertical
      offset as other arrow panels. */
   visibility: hidden;
 }
 
-#pageActionFeedback > .panel-arrowcontainer > .panel-arrowcontent {
-  background-color: #058b00;
-  background-image: none;
-  border-radius: 2px;
-  color: #fff;
+#confirmation-hint > .panel-arrowcontainer > .panel-arrowcontent {
   font-weight: 400;
   font-size: 1.1rem;
   -moz-box-align: center;
   padding: 6px 10px;
 }
 
-#pageActionFeedbackAnimatableBox {
+#confirmation-hint-checkmark-animation-container {
   position: relative;
   overflow: hidden;
   width: 14px;
   height: 14px;
 }
 
-#pageActionFeedbackAnimatableBox[animate] > #pageActionFeedbackAnimatableImage {
+#confirmation-hint-checkmark-animation-container[animate] > #confirmation-hint-checkmark-image {
   position: absolute;
   background-image: url(chrome://browser/skin/check-animation.svg);
   background-repeat: no-repeat;
   min-width: 266px;
   max-width: 266px;
   min-height: 14px;
   max-height: 14px;
-  animation-name: page-action-feedback-animation;
+  animation-name: confirmation-hint-checkmark-animation;
   animation-duration: 300ms;
   animation-delay: 60ms;
   animation-fill-mode: forwards;
   animation-timing-function: steps(18);
 }
 
-#pageActionFeedbackAnimatableBox[animate] > #pageActionFeedbackAnimatableImage:-moz-locale-dir(rtl) {
-  animation-name: page-action-feedback-animation-rtl;
+#confirmation-hint-checkmark-animation-container[animate] > #confirmation-hint-checkmark-image:-moz-locale-dir(rtl) {
+  animation-name: confirmation-hint-checkmark-animation-rtl;
   transform: translateX(252px);
 }
 
-@keyframes page-action-feedback-animation {
+@keyframes confirmation-hint-checkmark-animation {
   from {
     transform: translateX(0);
   }
   to {
     transform: translateX(-252px);
   }
 }
 
-@keyframes page-action-feedback-animation-rtl {
+@keyframes confirmation-hint-checkmark-animation-rtl {
   from {
     transform: translateX(252px);
   }
   to {
     transform: translateX(0);
   }
 }
 
-#pageActionFeedbackMessage {
+#confirmation-hint-message {
   margin-inline-start: 7px;
   margin-inline-end: 0;
   transform: scale(.8);
   opacity: 0;
   transition: transform 120ms cubic-bezier(.25,1.27,.35,1.18),
               opacity 60ms linear;
 }
 
-#pageActionFeedbackAnimatableBox[animate] + #pageActionFeedbackMessage {
+#confirmation-hint-checkmark-animation-container[animate] + #confirmation-hint-message {
   transform: scale(1);
   opacity: 1;
 }
 
 .cui-widget-panel[viewId^=PanelUI-webext-] > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
--- a/browser/themes/windows/syncedtabs/sidebar.css
+++ b/browser/themes/windows/syncedtabs/sidebar.css
@@ -81,38 +81,30 @@
   background-repeat: no-repeat;
   background-position: center;
   min-width: 9px; /* The image's width is 9 pixels */
   height: 9px;
   margin: auto;
 }
 
 .item.client .item-twisty-container {
-  background-image: url("chrome://global/skin/tree/twisty.svg#open");
+  background-image: url("chrome://global/skin/tree/twisty-expanded.svg");
+  -moz-context-properties: fill, fill-opacity;
+  fill: #636363;
+  fill-opacity: 1;
 }
 
 .item.client.closed .item-twisty-container {
-  background-image: url("chrome://global/skin/tree/twisty.svg#clsd");
+  background-image: url("chrome://global/skin/tree/twisty-collapsed.svg");
+  fill: #b6b6b6;
+}
+
+.item.client.closed .item-twisty-container:dir(rtl) {
+  background-image: url("chrome://global/skin/tree/twisty-collapsed-rtl.svg");
 }
 
 .item.client .item-twisty-container:hover {
-  background-image: url("chrome://global/skin/tree/twisty.svg#open-hover");
-}
-
-.item.client.closed .item-twisty-container:hover {
-  background-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover");
-}
-
-.item.client .item-twisty-container:dir(rtl) {
-  background-image: url("chrome://global/skin/tree/twisty.svg#open-rtl");
+  fill: #4ed0f9;
 }
 
-.item.client.closed .item-twisty-container:dir(rtl) {
-  background-image: url("chrome://global/skin/tree/twisty.svg#clsd-rtl");
+.item.client.selected .item-twisty-container:not(:hover) {
+  fill: currentColor;
 }
-
-.item.client .item-twisty-container:hover:dir(rtl) {
-  background-image: url("chrome://global/skin/tree/twisty.svg#open-hover-rtl");
-}
-
-.item.client.closed .item-twisty-container:hover:dir(rtl) {
-  background-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover-rtl");
-}
--- a/devtools/client/inspector/fonts/components/FontEditor.js
+++ b/devtools/client/inspector/fonts/components/FontEditor.js
@@ -9,17 +9,17 @@ const dom = require("devtools/client/sha
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const FontMeta = createFactory(require("./FontMeta"));
 const FontPropertyValue = createFactory(require("./FontPropertyValue"));
 const FontSize = createFactory(require("./FontSize"));
 const FontStyle = createFactory(require("./FontStyle"));
 const FontWeight = createFactory(require("./FontWeight"));
 
-const { getStr, getFormatStr } = require("../utils/l10n");
+const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
 class FontEditor extends PureComponent {
   static get propTypes() {
     return {
       fontEditor: PropTypes.shape(Types.fontEditor).isRequired,
       onInstanceChange: PropTypes.func.isRequired,
       onPropertyChange: PropTypes.func.isRequired,
@@ -74,55 +74,26 @@ class FontEditor extends PureComponent {
         step: this.getAxisStep(axis.minValue, axis.maxValue),
         label: axis.name,
         name: axis.tag,
         onChange: this.props.onPropertyChange,
         unit: null
       });
     });
   }
-
-  renderFamilesNotUsed(familiesNotUsed = []) {
-    if (!familiesNotUsed.length) {
-      return null;
-    }
-
-    const familiesList = familiesNotUsed.map(family => {
-      return dom.div(
-        {
-          className: "font-family-unused",
-        },
-        family
-      );
-    });
-
-    return dom.details(
-      {},
-      dom.summary(
-        {
-          className: "font-family-unused-header",
-        },
-        getFormatStr("fontinspector.familiesNotUsedLabel", familiesNotUsed.length)
-      ),
-      familiesList
-    );
-  }
-
   /**
    * Render font family, font name, and metadata for all fonts used on selected node.
    *
    * @param {Array} fonts
    *        Fonts used on selected node.
-   * @param {Array} families
-   *        Font familes declared on selected node.
    * @param {Function} onToggleFontHighlight
    *        Callback to trigger in-context highlighting of text that uses a font.
    * @return {DOMNode}
    */
-  renderFontFamily(fonts, families, onToggleFontHighlight) {
+  renderFontFamily(fonts, onToggleFontHighlight) {
     if (!fonts.length) {
       return null;
     }
 
     const fontList = dom.ul(
       {
         className: "fonts-list"
       },
@@ -143,18 +114,17 @@ class FontEditor extends PureComponent {
           className: "font-control-label",
         },
         getStr("fontinspector.fontFamilyLabel")
       ),
       dom.div(
         {
           className: "font-control-box",
         },
-        fontList,
-        this.renderFamilesNotUsed(families.notUsed)
+        fontList
       )
     );
   }
 
   renderFontSize(value) {
     return value && FontSize({
       onChange: this.props.onPropertyChange,
       value,
@@ -240,17 +210,17 @@ class FontEditor extends PureComponent {
         className: "devtools-sidepanel-no-result"
       },
       getStr("fontinspector.noFontsOnSelectedElement")
     );
   }
 
   render() {
     const { fontEditor, onToggleFontHighlight } = this.props;
-    const { fonts, families, axes, instance, properties } = fontEditor;
+    const { fonts, axes, instance, properties } = fontEditor;
     // Pick the first font to show editor controls regardless of how many fonts are used.
     const font = fonts[0];
     const hasFontAxes = font && font.variationAxes;
     const hasFontInstances = font && font.variationInstances
       && font.variationInstances.length > 0;
     const hasSlantOrItalicAxis = hasFontAxes && font.variationAxes.find(axis => {
       return axis.tag === "slnt" || axis.tag === "ital";
     });
@@ -262,17 +232,17 @@ class FontEditor extends PureComponent {
 
     return dom.div(
       {
         id: "font-editor"
       },
       // Render empty state message for nodes that don't have font properties.
       !hasWeight && this.renderWarning(),
       // Always render UI for font family, format and font file URL.
-      this.renderFontFamily(fonts, families, onToggleFontHighlight),
+      this.renderFontFamily(fonts, onToggleFontHighlight),
       // Render UI for font variation instances if they are defined.
       hasFontInstances && this.renderInstances(font.variationInstances, instance),
       // Always render UI for font size.
       this.renderFontSize(properties["font-size"]),
       // Render UI for font weight if no "wght" registered axis is defined.
       !hasWeightAxis && this.renderFontWeight(properties["font-weight"]),
       // Render UI for font style if no "slnt" or "ital" registered axis is defined.
       !hasSlantOrItalicAxis && this.renderFontStyle(properties["font-style"]),
--- a/devtools/client/inspector/fonts/fonts.js
+++ b/devtools/client/inspector/fonts/fonts.js
@@ -406,17 +406,18 @@ class FontInspector {
     const families = {};
     // Font family names declared and used.
     families.used = fontsUsed.map(font =>
       font.CSSGeneric ? font.CSSGeneric : font.CSSFamilyName
     );
     const familiesUsedLowercase = families.used.map(family => family.toLowerCase());
     // Font family names declared but not used.
     families.notUsed = fontFamilies
-      .filter(family => !familiesUsedLowercase.includes(family.toLowerCase()));
+      .map(family => family.toLowerCase())
+      .filter(family => !familiesUsedLowercase.includes(family));
 
     return families;
   }
 
   /**
    * Check if the font inspector panel is visible.
    *
    * @return {Boolean}
--- a/devtools/client/inspector/fonts/test/browser.ini
+++ b/devtools/client/inspector/fonts/test/browser.ini
@@ -16,12 +16,11 @@ support-files =
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_fontinspector.js]
 [browser_fontinspector_copy-URL.js]
 skip-if = !e10s # too slow on !e10s, logging fully serialized actors (Bug 1446595)
 subsuite = clipboard
 [browser_fontinspector_edit-previews.js]
 [browser_fontinspector_expand-css-code.js]
-[browser_fontinspector_family-unused.js]
 [browser_fontinspector_other-fonts.js]
 [browser_fontinspector_reveal-in-page.js]
 [browser_fontinspector_theme-change.js]
--- a/devtools/client/inspector/fonts/test/browser_fontinspector.html
+++ b/devtools/client/inspector/fonts/test/browser_fontinspector.html
@@ -22,17 +22,17 @@
   }
   body{
     /* Arial doesn't exist on Linux. Liberation Sans is the default sans-serif there. */
     font-family:Arial, "Liberation Sans";
     font-size: 36px;
   }
   div {
     font-family:Arial;
-    font-family:bar, "Missing Family", sans-serif;
+    font-family:bar;
   }
   .normal-text {
     font-family: barnormal;
     font-weight: normal;
   }
   .bold-text {
     font-family: bar;
     font-weight: bold;
deleted file mode 100644
--- a/devtools/client/inspector/fonts/test/browser_fontinspector_family-unused.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-const TEST_URI = URL_ROOT + "browser_fontinspector.html";
-
-// Test that unused font families show up in the font editor.
-add_task(async function() {
-  await pushPref("devtools.inspector.fonteditor.enabled", true);
-  const { inspector, view } = await openFontInspectorForURL(TEST_URI);
-  const viewDoc = view.document;
-
-  await testFamiliesUnused(inspector, viewDoc);
-  await testZeroFamiliesUnused(inspector, viewDoc);
-});
-
-function getUnusedFontFamilies(viewDoc) {
-  return [...viewDoc.querySelectorAll("#font-editor .font-family-unused")]
-    .map(el => el.textContent);
-}
-
-async function testFamiliesUnused(inspector, viewDoc) {
-  await selectNode("div", inspector);
-
-  const unused = getUnusedFontFamilies(viewDoc);
-  is(unused.length, 2, "Two font families were not used");
-  is(unused[0], "Missing Family", "First unused family is correct");
-  is(unused[1], "sans-serif", "Second unused family is correct");
-}
-
-async function testZeroFamiliesUnused(inspector, viewDoc) {
-  await selectNode(".normal-text", inspector);
-
-  const unused = getUnusedFontFamilies(viewDoc);
-  const header = viewDoc.querySelector("#font-editor .font-family-unused-header");
-  is(unused.length, 0, "All font families were used");
-  is(header, null, "Container for unused font families was not rendered");
-}
--- a/devtools/client/inspector/fonts/utils/l10n.js
+++ b/devtools/client/inspector/fonts/utils/l10n.js
@@ -3,11 +3,10 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/font-inspector.properties");
 
 module.exports = {
-  getFormatStr: (...args) => L10N.getFormatStr(...args),
   getStr: (...args) => L10N.getStr(...args),
 };
--- a/devtools/client/locales/en-US/font-inspector.properties
+++ b/devtools/client/locales/en-US/font-inspector.properties
@@ -50,13 +50,8 @@ fontinspector.fontSizeLabel=Size
 
 # LOCALIZATION NOTE (fontinspector.fontWeightLabel): This label is shown next to the UI
 # in the font editor which allows the user to change the font weight.
 fontinspector.fontWeightLabel=Weight
 
 # LOCALIZATION NOTE (fontinspector.fontItalicLabel): This label is shown next to the UI
 # in the font editor which allows the user to change the style of the font to italic.
 fontinspector.fontItalicLabel=Italic
-
-# LOCALIZATION NOTE (fontinspector.familiesNotUsedLabel): This label is shown at the top
-# of the list of unused font families. %S is the number of unused font families. It is
-# always a positive integer larger than zero.
-fontinspector.familiesNotUsedLabel=%S not used
--- a/devtools/client/themes/fonts.css
+++ b/devtools/client/themes/fonts.css
@@ -151,27 +151,16 @@
   display: inline-block;
   flex: 1;
   font-size: 12px;
   min-width: 80px;
   margin-right: 10px;
   -moz-user-select: none;
 }
 
-.font-family-unused-header {
-  -moz-user-select: none;
-  margin-bottom: .7em;
-  cursor: pointer;
-}
-
-.font-family-unused {
-  margin-bottom: .3em;
-  color: var(--grey-50);
-}
-
 .font-instance-select:active{
   outline: none;
 }
 
 .font-value-input {
   margin-left: 10px;
   width: 60px;
 }
--- a/devtools/server/actors/targets/browsing-context.js
+++ b/devtools/server/actors/targets/browsing-context.js
@@ -30,16 +30,20 @@ var { DebuggerServer } = require("devtoo
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var { assert } = DevToolsUtils;
 var { TabSources } = require("devtools/server/actors/utils/TabSources");
 var makeDebugger = require("devtools/server/actors/utils/make-debugger");
 const InspectorUtils = require("InspectorUtils");
 
 const EXTENSION_CONTENT_JSM = "resource://gre/modules/ExtensionContent.jsm";
 
+const { LocalizationHelper } = require("devtools/shared/l10n");
+const STRINGS_URI = "devtools/shared/locales/browsing-context.properties";
+const L10N = new LocalizationHelper(STRINGS_URI);
+
 const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
 const { browsingContextTargetSpec } = require("devtools/shared/specs/targets/browsing-context");
 
 loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/thread", true);
 loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
 loader.lazyRequireGetter(this, "WorkerTargetActorList", "devtools/server/actors/worker/worker-list", true);
 loader.lazyImporter(this, "ExtensionContent", EXTENSION_CONTENT_JSM);
 
@@ -1050,21 +1054,34 @@ const browsingContextTargetPrototype = {
         docShell.cssErrorReportingEnabled = true;
       } catch (e) {
         continue;
       }
       // We don't really want to reparse UA sheets and such, but want to do
       // Shadow DOM / XBL.
       const sheets =
         InspectorUtils.getAllStyleSheets(docShell.document, /* documentOnly = */ true);
+      const promises = [];
       for (const sheet of sheets) {
-        getSheetText(sheet, this._consoleActor).then(text => {
+        if (InspectorUtils.hasRulesModifiedByCSSOM(sheet)) {
+          continue;
+        }
+        // Reparse the sheet so that we see the existing errors.
+        promises.push(getSheetText(sheet, this._consoleActor).then(text => {
           InspectorUtils.parseStyleSheet(sheet, text, /* aUpdate = */ false);
+        }));
+      }
+
+      Promise.all(promises).then(() => {
+        this.logInPage({
+          text: L10N.getStr("cssSheetsReparsedWarning"),
+          category: "CSS Parser",
+          flags: Ci.nsIScriptError.warningFlag,
         });
-      }
+      });
     }
 
     return {};
   },
 
   /**
    * Handle logic to enable/disable JS/cache/Service Worker testing.
    */
new file mode 100644
--- /dev/null
+++ b/devtools/shared/locales/en-US/browsing-context.properties
@@ -0,0 +1,7 @@
+# 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/.
+
+# LOCALIZATION NOTE (cssSheetsReparsedWarning): The warning
+# to show after the CSS message filter has been toggled on.
+cssSheetsReparsedWarning=Stylesheets without CSSOM changes reparsed to check for errors. Refresh the page to also see errors from stylesheets changed from CSSOM and from style attributes.
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5092,16 +5092,22 @@ nsIDocument::DispatchContentLoadedEvents
   // event.
   Element* root = GetRootElement();
   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
     nsContentUtils::DispatchChromeEvent(this, this,
                                         NS_LITERAL_STRING("MozApplicationManifest"),
                                         true, true);
   }
 
+  nsPIDOMWindowInner* inner = GetInnerWindow();
+  if (inner) {
+    inner->NoteDOMContentLoaded();
+  }
+
+  // TODO
   if (mMaybeServiceWorkerControlled) {
     using mozilla::dom::ServiceWorkerManager;
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     if (swm) {
       Maybe<ClientInfo> clientInfo = GetClientInfo();
       if (clientInfo.isSome()) {
         swm->MaybeCheckNavigationUpdate(clientInfo.ref());
       }
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2350,16 +2350,22 @@ nsPIDOMWindowInner::GetOrCreateServiceWo
 }
 
 void
 nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope)
 {
   nsGlobalWindowInner::Cast(this)->NoteCalledRegisterForServiceWorkerScope(aScope);
 }
 
+void
+nsPIDOMWindowInner::NoteDOMContentLoaded()
+{
+  nsGlobalWindowInner::Cast(this)->NoteDOMContentLoaded();
+}
+
 bool
 nsGlobalWindowInner::ShouldReportForServiceWorkerScope(const nsAString& aScope)
 {
   bool result = false;
 
   nsPIDOMWindowOuter* topOuter = GetScriptableTop();
   NS_ENSURE_TRUE(topOuter, false);
 
@@ -2467,16 +2473,26 @@ nsGlobalWindowInner::NoteCalledRegisterF
   if (!mClientSource) {
     return;
   }
 
   mClientSource->NoteCalledRegisterForServiceWorkerScope(aScope);
 }
 
 void
+nsGlobalWindowInner::NoteDOMContentLoaded()
+{
+  if (!mClientSource) {
+    return;
+  }
+
+  mClientSource->NoteDOMContentLoaded();
+}
+
+void
 nsGlobalWindowInner::MigrateStateForDocumentOpen(nsGlobalWindowInner* aOldInner)
 {
   MOZ_DIAGNOSTIC_ASSERT(aOldInner);
   MOZ_DIAGNOSTIC_ASSERT(aOldInner != this);
   MOZ_DIAGNOSTIC_ASSERT(mDoc);
 
   // Rebind DETH objects to the new global created by document.open().
   // XXX: Is this correct?  We should consider if the spec and our
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -360,16 +360,18 @@ public:
   virtual RefPtr<mozilla::dom::ServiceWorker>
   GetOrCreateServiceWorker(const mozilla::dom::ServiceWorkerDescriptor& aDescriptor) override;
 
   RefPtr<mozilla::dom::ServiceWorkerRegistration>
   GetOrCreateServiceWorkerRegistration(const mozilla::dom::ServiceWorkerRegistrationDescriptor& aDescriptor) override;
 
   void NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope);
 
+  void NoteDOMContentLoaded();
+
   virtual nsresult FireDelayedDOMEvents() override;
 
   virtual nsresult SetNewDocument(nsIDocument *aDocument,
                                   nsISupports *aState,
                                   bool aForceReuseInnerWindow) override;
 
   virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
                                bool aOriginalOpener) override;
--- a/dom/base/nsIGlobalObject.cpp
+++ b/dom/base/nsIGlobalObject.cpp
@@ -145,17 +145,17 @@ nsIGlobalObject::RemoveEventTargetObject
 }
 
 void
 nsIGlobalObject::ForEachEventTargetObject(const std::function<void(DOMEventTargetHelper*, bool* aDoneOut)>& aFunc) const
 {
   // Protect against the function call triggering a mutation of the list
   // while we are iterating by copying the DETH references to a temporary
   // list.
-  AutoTArray<DOMEventTargetHelper*, 64> targetList;
+  AutoTArray<RefPtr<DOMEventTargetHelper>, 64> targetList;
   for (const DOMEventTargetHelper* deth = mEventTargetObjects.getFirst();
        deth; deth = deth->getNext()) {
     targetList.AppendElement(const_cast<DOMEventTargetHelper*>(deth));
   }
 
   // Iterate the target list and call the function on each one.
   bool done = false;
   for (auto target : targetList) {
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -327,16 +327,18 @@ public:
   mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
   mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
 
   RefPtr<mozilla::dom::ServiceWorker>
   GetOrCreateServiceWorker(const mozilla::dom::ServiceWorkerDescriptor& aDescriptor);
 
   void NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope);
 
+  void NoteDOMContentLoaded();
+
   mozilla::dom::TabGroup* TabGroup();
 
   virtual nsPIDOMWindowOuter* GetPrivateRoot() = 0;
 
   virtual mozilla::dom::CustomElementRegistry* CustomElements() = 0;
 
   // XXX: This is called on inner windows
   virtual nsPIDOMWindowOuter* GetScriptableTop() = 0;
--- a/dom/clients/manager/ClientSource.cpp
+++ b/dom/clients/manager/ClientSource.cpp
@@ -472,16 +472,32 @@ ClientSource::InheritController(const Se
 }
 
 const Maybe<ServiceWorkerDescriptor>&
 ClientSource::GetController() const
 {
   return mController;
 }
 
+void
+ClientSource::NoteDOMContentLoaded()
+{
+  if (mController.isSome() && !ServiceWorkerParentInterceptEnabled()) {
+    AssertIsOnMainThread();
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (swm) {
+      swm->MaybeCheckNavigationUpdate(mClientInfo);
+    }
+  }
+
+  MaybeExecute([] (PClientSourceChild* aActor) {
+    aActor->SendNoteDOMContentLoaded();
+  });
+}
+
 RefPtr<ClientOpPromise>
 ClientSource::Focus(const ClientFocusArgs& aArgs)
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
 
   RefPtr<ClientOpPromise> ref;
 
   if (mClientInfo.Type() != ClientType::Window) {
@@ -606,31 +622,39 @@ ClientSource::PostMessage(const ClientPo
   }
 
   nsAutoCString origin;
   rv = principal->GetOriginNoSuffix(origin);
   if (NS_SUCCEEDED(rv)) {
     CopyUTF8toUTF16(origin, init.mOrigin);
   }
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  if (!swm) {
-    // Shutting down. Just don't deliver this message.
-    ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
-    return ref.forget();
+  RefPtr<ServiceWorker> instance;
+
+  if (ServiceWorkerParentInterceptEnabled()) {
+    instance = globalObject->GetOrCreateServiceWorker(source);
+  } else {
+    // If we are in legacy child-side intercept mode then we need to verify
+    // this registration exists in the current process.
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      // Shutting down. Just don't deliver this message.
+      ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+      return ref.forget();
+    }
+
+    RefPtr<ServiceWorkerRegistrationInfo> reg =
+      swm->GetRegistration(principal, source.Scope());
+    if (reg) {
+      instance = globalObject->GetOrCreateServiceWorker(source);
+    }
   }
 
-  RefPtr<ServiceWorkerRegistrationInfo> reg =
-    swm->GetRegistration(principal, source.Scope());
-  if (reg) {
-    RefPtr<ServiceWorker> instance =
-      globalObject->GetOrCreateServiceWorker(source);
-    if (instance) {
-      init.mSource.SetValue().SetAsServiceWorker() = instance;
-    }
+  if (instance) {
+    init.mSource.SetValue().SetAsServiceWorker() = instance;
   }
 
   RefPtr<MessageEvent> event =
     MessageEvent::Constructor(target, NS_LITERAL_STRING("message"), init);
   event->SetTrusted(true);
 
   target->DispatchEvent(*event, result);
   if (result.Failed()) {
--- a/dom/clients/manager/ClientSource.h
+++ b/dom/clients/manager/ClientSource.h
@@ -145,16 +145,21 @@ public:
   void
   InheritController(const ServiceWorkerDescriptor& aServiceWorker);
 
   // Get the ClientSource's current controlling service worker, if one has
   // been set.
   const Maybe<ServiceWorkerDescriptor>&
   GetController() const;
 
+  // Note that the client has reached DOMContentLoaded.  Only applies to window
+  // clients.
+  void
+  NoteDOMContentLoaded();
+
   RefPtr<ClientOpPromise>
   Focus(const ClientFocusArgs& aArgs);
 
   RefPtr<ClientOpPromise>
   PostMessage(const ClientPostMessageArgs& aArgs);
 
   RefPtr<ClientOpPromise>
   Claim(const ClientClaimArgs& aArgs);
--- a/dom/clients/manager/ClientSourceParent.cpp
+++ b/dom/clients/manager/ClientSourceParent.cpp
@@ -165,16 +165,34 @@ ClientSourceParent::RecvInheritControlle
       });
 
     MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
   }
 
   return IPC_OK();
 }
 
+IPCResult
+ClientSourceParent::RecvNoteDOMContentLoaded()
+{
+  if (mController.isSome() && ServiceWorkerParentInterceptEnabled()) {
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+      "ClientSourceParent::RecvNoteDOMContentLoaded",
+      [clientInfo = mClientInfo] () {
+        RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+        NS_ENSURE_TRUE_VOID(swm);
+
+        swm->MaybeCheckNavigationUpdate(clientInfo);
+      });
+
+    MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
+  }
+  return IPC_OK();
+}
+
 void
 ClientSourceParent::ActorDestroy(ActorDestroyReason aReason)
 {
   DebugOnly<bool> removed = mService->RemoveSource(this);
   MOZ_ASSERT(removed);
 
   nsTArray<ClientHandleParent*> handleList(mHandleList);
   for (ClientHandleParent* handle : handleList) {
--- a/dom/clients/manager/ClientSourceParent.h
+++ b/dom/clients/manager/ClientSourceParent.h
@@ -43,16 +43,19 @@ class ClientSourceParent final : public 
   RecvFreeze() override;
 
   mozilla::ipc::IPCResult
   RecvThaw() override;
 
   mozilla::ipc::IPCResult
   RecvInheritController(const ClientControlledArgs& aArgs) override;
 
+  mozilla::ipc::IPCResult
+  RecvNoteDOMContentLoaded() override;
+
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   PClientSourceOpParent*
   AllocPClientSourceOpParent(const ClientOpConstructorArgs& aArgs) override;
 
   bool
   DeallocPClientSourceOpParent(PClientSourceOpParent* aActor) override;
--- a/dom/clients/manager/PClientSource.ipdl
+++ b/dom/clients/manager/PClientSource.ipdl
@@ -21,16 +21,17 @@ sync protocol PClientSource
 
 parent:
   sync WorkerSyncPing();
   async Teardown();
   async ExecutionReady(ClientSourceExecutionReadyArgs aArgs);
   async Freeze();
   async Thaw();
   async InheritController(ClientControlledArgs aArgs);
+  async NoteDOMContentLoaded();
 
 child:
   async PClientSourceOp(ClientOpConstructorArgs aArgs);
 
   async __delete__();
 };
 
 } // namespace dom
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -50,18 +50,22 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(PaymentRequest, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(PaymentRequest, DOMEventTargetHelper)
 
 bool
 PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
 {
+#ifdef NIGHTLY_BUILD
   return XRE_IsContentProcess() &&
          Preferences::GetBool("dom.payments.request.enabled");
+#else
+  return false;
+#endif
 }
 
 nsresult
 PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier,
                                        nsAString& aErrorMsg)
 {
   /*
    *   The syntax of a standardized payment method identifier is given by the
--- a/dom/payments/ipc/PaymentRequestParent.cpp
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -151,17 +151,17 @@ PaymentRequestParent::RecvRequestPayment
       return IPC_FAIL(this, "Unexpected request type");
     }
   }
   nsCOMPtr<nsIPaymentRequestService> service =
     do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
   MOZ_ASSERT(service);
   rv = service->RequestPayment(action);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return IPC_FAIL_NO_REASON(this);
+    return IPC_FAIL(this, "nsIPaymentRequestService::RequestPayment failed");
   }
   return IPC_OK();
 }
 
 NS_IMETHODIMP
 PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse)
 {
   if (!NS_IsMainThread()) {
--- a/dom/payments/test/browser.ini
+++ b/dom/payments/test/browser.ini
@@ -1,8 +1,8 @@
 [DEFAULT]
 # skip-if !e10s will be removed once non-e10s is supported
-skip-if = !e10s
+skip-if = !e10s || !nightly_build
 support-files =
   head.js
   simple_payment_request.html
 
 [browser_payment_in_different_tabs.js]
--- a/dom/payments/test/mochitest.ini
+++ b/dom/payments/test/mochitest.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 # skip-if !e10s will be removed once non-e10s is supported
-skip-if = !e10s
+skip-if = !e10s || !nightly_build
 scheme = https
 support-files =
   simple_payment_request.html
   echo_payment_request.html
   BasiccardChromeScript.js
   ConstructorChromeScript.js
   CurrencyAmountValidationChromeScript.js
   DefaultData.js
--- a/dom/push/PushNotifier.cpp
+++ b/dom/push/PushNotifier.cpp
@@ -98,17 +98,17 @@ nsresult
 PushNotifier::Dispatch(PushDispatcher& aDispatcher)
 {
   if (XRE_IsParentProcess()) {
     // Always notify XPCOM observers in the parent process.
     Unused << NS_WARN_IF(NS_FAILED(aDispatcher.NotifyObservers()));
 
     nsTArray<ContentParent*> contentActors;
     ContentParent::GetAll(contentActors);
-    if (!contentActors.IsEmpty()) {
+    if (!contentActors.IsEmpty() && !ServiceWorkerParentInterceptEnabled()) {
       // At least one content process is active, so e10s must be enabled.
       // Broadcast a message to notify observers and service workers.
       for (uint32_t i = 0; i < contentActors.Length(); ++i) {
         // We need to filter based on process type, only "web" AKA the default
         // remote type is acceptable.
         if (!contentActors[i]->GetRemoteType().EqualsLiteral(
                DEFAULT_REMOTE_TYPE)) {
           continue;
@@ -123,17 +123,17 @@ PushNotifier::Dispatch(PushDispatcher& a
           // Only send the push message to the first content process to avoid
           // multiple SWs showing the same notification. See bug 1300112.
           break;
         }
       }
       return NS_OK;
     }
 
-    if (BrowserTabsRemoteAutostart()) {
+    if (BrowserTabsRemoteAutostart() && !ServiceWorkerParentInterceptEnabled()) {
       // e10s is enabled, but no content processes are active.
       return aDispatcher.HandleNoChildProcesses();
     }
 
     // e10s is disabled; notify workers in the parent.
     return aDispatcher.NotifyWorkers();
   }
 
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1279,20 +1279,28 @@ nsEventStatus AsyncPanZoomController::On
     case NOTHING:
     case ANIMATING_ZOOM:
       // May happen if the user double-taps and drags without lifting after the
       // second tap. Ignore the move if this happens.
       return nsEventStatus_eIgnore;
 
     case TOUCHING: {
       ScreenCoord panThreshold = GetTouchStartTolerance();
-      UpdateWithTouchAtDevicePoint(aEvent);
-
-      if (PanDistance() < panThreshold) {
-        return nsEventStatus_eIgnore;
+
+      // We intentionally skip the UpdateWithTouchAtDevicePoint call when the
+      // panThreshold is zero. This ensures more deterministic behaviour during
+      // testing. If we call that, Axis::mPos gets updated to the point of this
+      // touchmove event, but we "consume" the move to overcome the
+      // panThreshold, so it's hard to pan a specific amount reliably from a
+      // mochitest.
+      if (panThreshold > 0.0f) {
+        UpdateWithTouchAtDevicePoint(aEvent);
+        if (PanDistance() < panThreshold) {
+          return nsEventStatus_eIgnore;
+        }
       }
 
       ParentLayerPoint touchPoint = GetFirstTouchPoint(aEvent);
 
       MOZ_ASSERT(GetCurrentTouchBlock());
       if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
         // User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
         // + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -206,16 +206,24 @@ public:
   RefPtr<InputQueue> GetInputQueue() const {
     return mInputQueue;
   }
 
   void ClearContentController() {
     mcc = nullptr;
   }
 
+  /**
+   * This function is not currently implemented.
+   * See bug 1468804 for more information.
+   **/
+  void CancelAnimation() {
+    EXPECT_TRUE(false);
+  }
+
 protected:
   AsyncPanZoomController* NewAPZCInstance(LayersId aLayersId,
                                           GeckoContentController* aController) override;
 
   TimeStamp GetFrameTime() override {
     return mcc->Time();
   }
 
@@ -350,17 +358,18 @@ public:
     None = 0,
     KeepFingerDown = 0x1,
     /*
      * Do not adjust the touch-start coordinates to overcome the touch-start
      * tolerance threshold. If this option is passed, it's up to the caller
      * to pass in coordinates that are sufficient to overcome the touch-start
      * tolerance *and* cause the desired amount of scrolling.
      */
-    ExactCoordinates = 0x2
+    ExactCoordinates = 0x2,
+    NoFling = 0x4
   };
 
   enum class PinchOptions {
     None = 0,
     LiftFinger1 = 0x1,
     LiftFinger2 = 0x2,
     /*
      * The bitwise OR result of (LiftFinger1 | LiftFinger2).
@@ -408,21 +417,16 @@ public:
   */
   template<class InputReceiver>
   void PanAndCheckStatus(const RefPtr<InputReceiver>& aTarget, int aTouchStartY,
                          int aTouchEndY,
                          bool aExpectConsumed,
                          nsTArray<uint32_t>* aAllowedTouchBehaviors,
                          uint64_t* aOutInputBlockId = nullptr);
 
-  void ApzcPanNoFling(const RefPtr<TestAsyncPanZoomController>& aApzc,
-                      int aTouchStartY,
-                      int aTouchEndY,
-                      uint64_t* aOutInputBlockId = nullptr);
-
   template<class InputReceiver>
   void DoubleTap(const RefPtr<InputReceiver>& aTarget,
                  const ScreenIntPoint& aPoint,
                  nsEventStatus (*aOutEventStatuses)[4] = nullptr,
                  uint64_t (*aOutInputBlockIds)[2] = nullptr);
 
   template<class InputReceiver>
   void DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
@@ -584,16 +588,20 @@ APZCTesterBase::Pan(const RefPtr<InputRe
     status = TouchUp(aTarget, aTouchEnd, mcc->Time());
   } else {
     status = nsEventStatus_eIgnore;
   }
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[3] = status;
   }
 
+  if ((aOptions & PanOptions::NoFling)) {
+    aTarget->CancelAnimation();
+  }
+
   // Don't increment the time here. Animations started on touch-up, such as
   // flings, are affected by elapsed time, and we want to be able to sample
   // them immediately after they start, without time having elapsed.
 }
 
 template<class InputReceiver>
 void
 APZCTesterBase::Pan(const RefPtr<InputReceiver>& aTarget,
@@ -625,25 +633,16 @@ APZCTesterBase::PanAndCheckStatus(const 
     touchMoveStatus = nsEventStatus_eConsumeDoDefault;
   } else {
     touchMoveStatus = nsEventStatus_eIgnore;
   }
   EXPECT_EQ(touchMoveStatus, statuses[1]);
   EXPECT_EQ(touchMoveStatus, statuses[2]);
 }
 
-void
-APZCTesterBase::ApzcPanNoFling(const RefPtr<TestAsyncPanZoomController>& aApzc,
-                               int aTouchStartY, int aTouchEndY,
-                               uint64_t* aOutInputBlockId)
-{
-  Pan(aApzc, aTouchStartY, aTouchEndY, PanOptions::None, nullptr, nullptr, aOutInputBlockId);
-  aApzc->CancelAnimation();
-}
-
 template<class InputReceiver>
 void
 APZCTesterBase::DoubleTap(const RefPtr<InputReceiver>& aTarget,
                           const ScreenIntPoint& aPoint,
                           nsEventStatus (*aOutEventStatuses)[4],
                           uint64_t (*aOutInputBlockIds)[2])
 {
   uint64_t blockId;
--- a/gfx/layers/apz/test/gtest/TestBasic.cpp
+++ b/gfx/layers/apz/test/gtest/TestBasic.cpp
@@ -164,17 +164,17 @@ TEST_F(APZCBasicTester, Fling) {
 }
 
 TEST_F(APZCBasicTester, FlingIntoOverscroll) {
   // Enable overscrolling.
   SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
   SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
 
   // Scroll down by 25 px. Don't fling for simplicity.
-  ApzcPanNoFling(apzc, 50, 25);
+  Pan(apzc, 50, 25, PanOptions::NoFling);
 
   // Now scroll back up by 20px, this time flinging after.
   // The fling should cover the remaining 5 px of room to scroll, then
   // go into overscroll, and finally snap-back to recover from overscroll.
   Pan(apzc, 25, 45);
   const TimeDuration increment = TimeDuration::FromMilliseconds(1);
   bool reachedOverscroll = false;
   bool recoveredFromOverscroll = false;
@@ -217,17 +217,17 @@ TEST_F(APZCBasicTester, PanningTransform
     EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eTransformBegin,_)).Times(1);
     EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eStartPanning,_)).Times(1);
     EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eEndTouch,_)).Times(1);
     EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eTransformEnd,_)).Times(1);
     EXPECT_CALL(check, Call("Done"));
   }
 
   check.Call("Simple pan");
-  ApzcPanNoFling(apzc, 50, 25);
+  Pan(apzc, 50, 25, PanOptions::NoFling);
   check.Call("Complex pan");
   Pan(apzc, 25, 45);
   apzc->AdvanceAnimationsUntilEnd();
   check.Call("Done");
 }
 
 void APZCBasicTester::PanIntoOverscroll()
 {
--- a/gfx/layers/apz/test/gtest/TestEventRegions.cpp
+++ b/gfx/layers/apz/test/gtest/TestEventRegions.cpp
@@ -230,20 +230,20 @@ TEST_F(APZEventRegionsTester, HitRegionA
 TEST_F(APZEventRegionsTester, Obscuration) {
   SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateObscuringLayerTree();
   ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
 
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
 
-  TestAsyncPanZoomController* parent = ApzcOf(layers[1]);
+  RefPtr<TestAsyncPanZoomController> parent = ApzcOf(layers[1]);
   TestAsyncPanZoomController* child = ApzcOf(layers[2]);
 
-  ApzcPanNoFling(parent, 75, 25);
+  Pan(parent, 75, 25, PanOptions::NoFling);
 
   gfx::CompositorHitTestInfo result;
   RefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(50, 75), &result);
   EXPECT_EQ(child, hit.get());
   EXPECT_EQ(CompositorHitTestInfo::eVisibleToHitTest, result);
 }
 
 TEST_F(APZEventRegionsTester, Bug1119497) {
--- a/gfx/layers/apz/test/gtest/TestHitTesting.cpp
+++ b/gfx/layers/apz/test/gtest/TestHitTesting.cpp
@@ -180,17 +180,17 @@ TEST_F(APZHitTestingTester, HitTesting2)
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
 
   // At this point, the following holds (all coordinates in screen pixels):
   // layers[0] has content from (0,0)-(200,200), clipped by composition bounds (0,0)-(100,100)
   // layers[1] has content from (10,10)-(90,90), clipped by composition bounds (10,10)-(50,50)
   // layers[2] has content from (20,60)-(100,100). no clipping as it's not a scrollable layer
   // layers[3] has content from (20,60)-(180,140), clipped by composition bounds (20,60)-(100,100)
 
-  TestAsyncPanZoomController* apzcroot = ApzcOf(root);
+  RefPtr<TestAsyncPanZoomController> apzcroot = ApzcOf(root);
   TestAsyncPanZoomController* apzc1 = ApzcOf(layers[1]);
   TestAsyncPanZoomController* apzc3 = ApzcOf(layers[3]);
 
   // Hit an area that's clearly on the root layer but not any of the child layers.
   RefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(75, 25));
   EXPECT_EQ(apzcroot, hit.get());
   EXPECT_EQ(ParentLayerPoint(75, 25), transformToApzc.TransformPoint(ScreenPoint(75, 25)));
   EXPECT_EQ(ScreenPoint(75, 25), transformToGecko.TransformPoint(ParentLayerPoint(75, 25)));
@@ -233,17 +233,17 @@ TEST_F(APZHitTestingTester, HitTesting2)
   // Pan the root layer upward by 50 pixels.
   // This causes layers[1] to scroll out of view, and an async transform
   // of -50 to be set on the root layer.
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   // This first pan will move the APZC by 50 pixels, and dispatch a paint request.
   // Since this paint request is in the queue to Gecko, transformToGecko will
   // take it into account.
-  ApzcPanNoFling(apzcroot, 100, 50);
+  Pan(apzcroot, 100, 50, PanOptions::NoFling);
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
   EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc.TransformPoint(ScreenPoint(75, 75)));
   // and transformToGecko unapplies it and then reapplies it, because by the
   // time the event being transformed reaches Gecko the new paint request will
@@ -257,17 +257,17 @@ TEST_F(APZHitTestingTester, HitTesting2)
   // async transform
   EXPECT_EQ(ParentLayerPoint(12.5, 75), transformToApzc.TransformPoint(ScreenPoint(25, 25)));
   // transformToGecko reapplies both the css transform and the async transform
   // because we have already issued a paint request with it.
   EXPECT_EQ(ScreenPoint(25, 25), transformToGecko.TransformPoint(ParentLayerPoint(12.5, 75)));
 
   // This second pan will move the APZC by another 50 pixels.
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
-  ApzcPanNoFling(apzcroot, 100, 50);
+  Pan(apzcroot, 100, 50, PanOptions::NoFling);
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
   EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc.TransformPoint(ScreenPoint(75, 75)));
   // transformToGecko unapplies the full async transform of -100 pixels
   EXPECT_EQ(ScreenPoint(75, 75), transformToGecko.TransformPoint(ParentLayerPoint(75, 75)));
@@ -398,17 +398,17 @@ TEST_F(APZHitTestingTester, TestRepaintF
   // The main purpose of this test is to verify that touch-start events (or anything
   // that starts a new input block) don't ever get untransformed. This should always
   // hold because the APZ code should flush repaints when we start a new input block
   // and the transform to gecko space should be empty.
 
   CreateSimpleScrollingLayer();
   ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
-  TestAsyncPanZoomController* apzcroot = ApzcOf(root);
+  RefPtr<TestAsyncPanZoomController> apzcroot = ApzcOf(root);
 
   // At this point, the following holds (all coordinates in screen pixels):
   // layers[0] has content from (0,0)-(500,500), clipped by composition bounds (0,0)-(200,200)
 
   MockFunction<void(std::string checkPointName)> check;
 
   {
     InSequence s;
@@ -417,17 +417,17 @@ TEST_F(APZHitTestingTester, TestRepaintF
     EXPECT_CALL(check, Call("post-first-touch-start"));
     EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
     EXPECT_CALL(check, Call("post-second-fling"));
     EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
     EXPECT_CALL(check, Call("post-second-touch-start"));
   }
 
   // This first pan will move the APZC by 50 pixels, and dispatch a paint request.
-  ApzcPanNoFling(apzcroot, 100, 50);
+  Pan(apzcroot, 100, 50, PanOptions::NoFling);
 
   // Verify that a touch start doesn't get untransformed
   ScreenIntPoint touchPoint(50, 50);
   MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
   mti.mTouches.AppendElement(SingleTouchData(0, touchPoint, ScreenSize(0, 0), 0, 0));
 
   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr, nullptr));
   EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
@@ -440,20 +440,20 @@ TEST_F(APZHitTestingTester, TestRepaintF
   mcc->AdvanceByMillis(1000);
 
   // Now do two pans. The first of these will dispatch a repaint request, as above.
   // The second will get stuck in the paint throttler because the first one doesn't
   // get marked as "completed", so this will result in a non-empty LD transform.
   // (Note that any outstanding repaint requests from the first half of this test
   // don't impact this half because we advance the time by 1 second, which will trigger
   // the max-wait-exceeded codepath in the paint throttler).
-  ApzcPanNoFling(apzcroot, 100, 50);
+  Pan(apzcroot, 100, 50, PanOptions::NoFling);
   check.Call("post-second-fling");
-  ApzcPanNoFling(apzcroot, 100, 50);
-  
+  Pan(apzcroot, 100, 50, PanOptions::NoFling);
+
   // Ensure that a touch start again doesn't get untransformed by flushing
   // a repaint
   mti.mType = MultiTouchInput::MULTITOUCH_START;
   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr, nullptr));
   EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
   check.Call("post-second-touch-start");
 
   mti.mType = MultiTouchInput::MULTITOUCH_END;
--- a/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
+++ b/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
@@ -159,25 +159,25 @@ protected:
 
 // Here we test that if the processing of a touch block is deferred while we
 // wait for content to send a prevent-default message, overscroll is still
 // handed off correctly when the block is processed.
 TEST_F(APZScrollHandoffTester, DeferredInputEventProcessing) {
   // Set up the APZC tree.
   CreateScrollHandoffLayerTree1();
 
-  TestAsyncPanZoomController* childApzc = ApzcOf(layers[1]);
+  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
 
   // Enable touch-listeners so that we can separate the queueing of input
   // events from them being processed.
   childApzc->SetWaitForMainThread();
 
   // Queue input events for a pan.
   uint64_t blockId = 0;
-  ApzcPanNoFling(childApzc, 90, 30, &blockId);
+  Pan(childApzc, 90, 30, PanOptions::NoFling, nullptr, nullptr, &blockId);
 
   // Allow the pan to be processed.
   childApzc->ContentReceivedInputBlock(blockId, false);
   childApzc->ConfirmTarget(blockId);
 
   // Make sure overscroll was handed off correctly.
   EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
   EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
@@ -187,36 +187,36 @@ TEST_F(APZScrollHandoffTester, DeferredI
 // blocks being queued, and the first block is only processed after the second
 // one has been queued, overscroll handoff for the first block follows
 // the original layer structure while overscroll handoff for the second block
 // follows the new layer structure.
 TEST_F(APZScrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
   // Set up an initial APZC tree.
   CreateScrollHandoffLayerTree1();
 
-  TestAsyncPanZoomController* childApzc = ApzcOf(layers[1]);
+  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
 
   // Enable touch-listeners so that we can separate the queueing of input
   // events from them being processed.
   childApzc->SetWaitForMainThread();
 
   // Queue input events for a pan.
   uint64_t blockId = 0;
-  ApzcPanNoFling(childApzc, 90, 30, &blockId);
+  Pan(childApzc, 90, 30, PanOptions::NoFling, nullptr, nullptr, &blockId);
 
   // Modify the APZC tree to insert a new APZC 'middle' into the handoff chain
   // between the child and the root.
   CreateScrollHandoffLayerTree2();
   RefPtr<Layer> middle = layers[1];
   childApzc->SetWaitForMainThread();
   TestAsyncPanZoomController* middleApzc = ApzcOf(middle);
 
   // Queue input events for another pan.
   uint64_t secondBlockId = 0;
-  ApzcPanNoFling(childApzc, 30, 90, &secondBlockId);
+  Pan(childApzc, 30, 90, PanOptions::NoFling, nullptr, nullptr, &secondBlockId);
 
   // Allow the first pan to be processed.
   childApzc->ContentReceivedInputBlock(blockId, false);
   childApzc->ConfirmTarget(blockId);
 
   // Make sure things have scrolled according to the handoff chain in
   // place at the time the touch-start of the first pan was queued.
   EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
--- a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
@@ -275,25 +275,19 @@ function* synthesizeNativeTouchSequences
         synthesizeNativeTouch(aElement, aPositions[i][j].x, aPositions[i][j].y, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, aTouchIds[j]);
         currentPositions[j] = aPositions[i][j];
       }
     }
   }
   return true;
 }
 
-// A handy constant when synthesizing native touch drag events with the pref
-// "apz.touch_start_tolerance" set to 0. In this case, the first touchmove with
-// a nonzero pixel movement is consumed by the APZ to transition from the
-// "touching" state to the "panning" state, so calls to synthesizeNativeTouchDrag
-// should add an extra pixel pixel for this purpose. The TOUCH_SLOP provides
-// a constant that can be used for this purpose. Note that if the touch start
-// tolerance is set to something higher, the touch slop amount used must be
-// correspondingly increased so as to be higher than the tolerance.
-const TOUCH_SLOP = 1;
+// Note that when calling this function you'll want to make sure that the pref
+// "apz.touch_start_tolerance" is set to 0, or some of the touchmove will get
+// consumed to overcome the panning threshold.
 function synthesizeNativeTouchDrag(aElement, aX, aY, aDeltaX, aDeltaY, aObserver = null, aTouchId = 0) {
   var steps = Math.max(Math.abs(aDeltaX), Math.abs(aDeltaY));
   var positions = new Array();
   positions.push([{ x: aX, y: aY }]);
   for (var i = 1; i < steps; i++) {
     var dx = i * (aDeltaX / steps);
     var dy = i * (aDeltaY / steps);
     var pos = { x: aX + dx, y: aY + dy };
--- a/gfx/layers/apz/test/mochitest/helper_basic_pan.html
+++ b/gfx/layers/apz/test/mochitest/helper_basic_pan.html
@@ -12,17 +12,17 @@
 function scrollPage() {
   var transformEnd = function() {
     SpecialPowers.Services.obs.removeObserver(transformEnd, "APZ:TransformEnd", false);
     dump("Transform complete; flushing repaints...\n");
     flushApzRepaints(checkScroll);
   };
   SpecialPowers.Services.obs.addObserver(transformEnd, "APZ:TransformEnd");
 
-  synthesizeNativeTouchDrag(document.body, 10, 100, 0, -(50 + TOUCH_SLOP));
+  synthesizeNativeTouchDrag(document.body, 10, 100, 0, -50);
   dump("Finished native drag, waiting for transform-end observer...\n");
 }
 
 function checkScroll() {
   is(window.scrollY, 50, "check that the window scrolled");
   subtestDone();
 }
 
--- a/gfx/layers/apz/test/mochitest/helper_bug1280013.html
+++ b/gfx/layers/apz/test/mochitest/helper_bug1280013.html
@@ -14,34 +14,34 @@ function* test(testDriver) {
   ok(screen.height > 500, "Screen height must be at least 500 pixels for this test to work");
 
   // This listener will trigger the test to continue once APZ is done with
   // processing the scroll.
   SpecialPowers.Services.obs.addObserver(testDriver, "APZ:TransformEnd");
 
   // Scroll down to the iframe. Do it in two drags instead of one in case the
   // device screen is short
-  yield synthesizeNativeTouchDrag(document.body, 10, 400, 0, -(350 + TOUCH_SLOP));
-  yield synthesizeNativeTouchDrag(document.body, 10, 400, 0, -(350 + TOUCH_SLOP));
+  yield synthesizeNativeTouchDrag(document.body, 10, 400, 0, -350);
+  yield synthesizeNativeTouchDrag(document.body, 10, 400, 0, -350);
   // Now the top of the visible area should be at y=700 of the top-level page,
   // so if the screen is >= 500px tall, the entire iframe should be visible, at
   // least vertically.
 
   // However, because of the overflow:hidden on the root elements, all this
   // scrolling is happening in APZ and is not reflected in the main-thread
   // scroll position (it is stored in the callback transform instead). We check
   // this by checking the scroll offset.
   yield flushApzRepaints(testDriver);
   is(window.scrollY, 0, "Main-thread scroll position is still at 0");
 
   // Scroll the iframe by 300px. Note that since the main-thread scroll position
   // is still 0, the subframe's getBoundingClientRect is going to be off by
   // 700 pixels, so we compensate for that here.
   var subframe = document.getElementById('subframe');
-  yield synthesizeNativeTouchDrag(subframe, 10, 200 - 700, 0, -(300 + TOUCH_SLOP));
+  yield synthesizeNativeTouchDrag(subframe, 10, 200 - 700, 0, -300);
 
   // Remove the observer, we don't need it any more.
   SpecialPowers.Services.obs.removeObserver(testDriver, "APZ:TransformEnd", false);
 
   // Flush any pending paints
   yield flushApzRepaints(testDriver);
 
   // get the displayport for the subframe
--- a/gfx/layers/apz/test/mochitest/helper_div_pan.html
+++ b/gfx/layers/apz/test/mochitest/helper_div_pan.html
@@ -12,17 +12,17 @@
 function scrollOuter() {
   var transformEnd = function() {
     SpecialPowers.Services.obs.removeObserver(transformEnd, "APZ:TransformEnd", false);
     dump("Transform complete; flushing repaints...\n");
     flushApzRepaints(checkScroll);
   };
   SpecialPowers.Services.obs.addObserver(transformEnd, "APZ:TransformEnd");
 
-  synthesizeNativeTouchDrag(document.getElementById('outer'), 10, 100, 0, -(50 + TOUCH_SLOP));
+  synthesizeNativeTouchDrag(document.getElementById('outer'), 10, 100, 0, -50);
   dump("Finished native drag, waiting for transform-end observer...\n");
 }
 
 function checkScroll() {
   var outerScroll = document.getElementById('outer').scrollTop;
   is(outerScroll, 50, "check that the div scrolled");
   subtestDone();
 }
--- a/gfx/layers/apz/test/mochitest/helper_iframe_pan.html
+++ b/gfx/layers/apz/test/mochitest/helper_iframe_pan.html
@@ -13,17 +13,17 @@ function scrollOuter() {
   var outer = document.getElementById('outer');
   var transformEnd = function() {
     SpecialPowers.Services.obs.removeObserver(transformEnd, "APZ:TransformEnd", false);
     dump("Transform complete; flushing repaints...\n");
     flushApzRepaints(checkScroll, outer.contentWindow);
   };
   SpecialPowers.Services.obs.addObserver(transformEnd, "APZ:TransformEnd");
 
-  synthesizeNativeTouchDrag(outer.contentDocument.body, 10, 100, 0, -(50 + TOUCH_SLOP));
+  synthesizeNativeTouchDrag(outer.contentDocument.body, 10, 100, 0, -50);
   dump("Finished native drag, waiting for transform-end observer...\n");
 }
 
 function checkScroll() {
   var outerScroll = document.getElementById('outer').contentWindow.scrollY;
   if (getPlatform() == "windows") {
     // On windows, because we run this test with native event synthesization,
     // Windows can end up eating the first touchmove which can result in the
--- a/gfx/layers/apz/test/mochitest/helper_touch_action.html
+++ b/gfx/layers/apz/test/mochitest/helper_touch_action.html
@@ -15,84 +15,84 @@ function checkScroll(x, y, desc) {
 }
 
 function* test(testDriver) {
   var target = document.getElementById('target');
 
   document.body.addEventListener('touchend', testDriver, { passive: true });
 
   // drag the page up to scroll down by 50px
-  yield ok(synthesizeNativeTouchDrag(target, 10, 100, 0, -(50 + TOUCH_SLOP)),
+  yield ok(synthesizeNativeTouchDrag(target, 10, 100, 0, -50),
       "Synthesized native vertical drag (1), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(0, 50, "After first vertical drag, with pan-y" );
 
   // switch style to pan-x
   document.body.style.touchAction = 'pan-x';
   ok(true, "Waiting for pan-x to propagate...");
   yield waitForAllPaintsFlushed(function() {
     flushApzRepaints(testDriver);
   });
 
   // drag the page up to scroll down by 50px, but it won't happen because pan-x
-  yield ok(synthesizeNativeTouchDrag(target, 10, 100, 0, -(50 + TOUCH_SLOP)),
+  yield ok(synthesizeNativeTouchDrag(target, 10, 100, 0, -50),
      "Synthesized native vertical drag (2), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(0, 50, "After second vertical drag, with pan-x");
 
   // drag the page left to scroll right by 50px
-  yield ok(synthesizeNativeTouchDrag(target, 100, 10, -(50 + TOUCH_SLOP), 0),
+  yield ok(synthesizeNativeTouchDrag(target, 100, 10, -50, 0),
      "Synthesized horizontal drag (1), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(50, 50, "After first horizontal drag, with pan-x");
 
   // drag the page diagonally right/down to scroll up/left by 40px each axis;
   // only the x-axis will actually scroll because pan-x
-  yield ok(synthesizeNativeTouchDrag(target, 10, 10, (40 + TOUCH_SLOP), (40 + TOUCH_SLOP)),
+  yield ok(synthesizeNativeTouchDrag(target, 10, 10, 40, 40),
      "Synthesized diagonal drag (1), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(10, 50, "After first diagonal drag, with pan-x");
 
   // switch style back to pan-y
   document.body.style.touchAction = 'pan-y';
   ok(true, "Waiting for pan-y to propagate...");
   yield waitForAllPaintsFlushed(function() {
     flushApzRepaints(testDriver);
   });
 
   // drag the page diagonally right/down to scroll up/left by 40px each axis;
   // only the y-axis will actually scroll because pan-y
-  yield ok(synthesizeNativeTouchDrag(target, 10, 10, (40 + TOUCH_SLOP), (40 + TOUCH_SLOP)),
+  yield ok(synthesizeNativeTouchDrag(target, 10, 10, 40, 40),
      "Synthesized diagonal drag (2), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(10, 10, "After second diagonal drag, with pan-y");
 
   // switch style to none
   document.body.style.touchAction = 'none';
   ok(true, "Waiting for none to propagate...");
   yield waitForAllPaintsFlushed(function() {
     flushApzRepaints(testDriver);
   });
 
   // drag the page diagonally up/left to scroll down/right by 40px each axis;
   // neither will scroll because of touch-action
-  yield ok(synthesizeNativeTouchDrag(target, 100, 100, -(40 + TOUCH_SLOP), -(40 + TOUCH_SLOP)),
+  yield ok(synthesizeNativeTouchDrag(target, 100, 100, -40, -40),
       "Synthesized diagonal drag (3), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(10, 10, "After third diagonal drag, with none");
 
   document.body.style.touchAction = 'manipulation';
   ok(true, "Waiting for manipulation to propagate...");
   yield waitForAllPaintsFlushed(function() {
     flushApzRepaints(testDriver);
   });
 
   // drag the page diagonally up/left to scroll down/right by 40px each axis;
   // both will scroll because of touch-action
-  yield ok(synthesizeNativeTouchDrag(target, 100, 100, -(40 + TOUCH_SLOP), -(40 + TOUCH_SLOP)),
+  yield ok(synthesizeNativeTouchDrag(target, 100, 100, -40, -40),
       "Synthesized diagonal drag (4), waiting for touch-end event...");
   yield flushApzRepaints(testDriver);
   checkScroll(50, 50, "After fourth diagonal drag, with manipulation");
 }
 
 waitUntilApzStable()
 .then(runContinuation(test))
 .then(subtestDone);
--- a/gfx/layers/apz/test/mochitest/helper_touch_action_complex.html
+++ b/gfx/layers/apz/test/mochitest/helper_touch_action_complex.html
@@ -52,23 +52,19 @@ function* test(testDriver) {
 
   // Helper function for the tests below.
   // Touch-pan configuration |configuration| towards scroll offset (dx, dy) with
   // the pan touching down at (x, y). Check that the final scroll offset is
   // (ex, ey). |desc| is some description string.
   function* scrollAndCheck(configuration, x, y, dx, dy, ex, ey, desc) {
     // Start with a clean slate
     yield resetConfiguration(configuration, testDriver);
-    // Figure out the panning deltas
-    if (dx != 0) {
-      dx = -(dx + TOUCH_SLOP);
-    }
-    if (dy != 0) {
-      dy = -(dy + TOUCH_SLOP);
-    }
+    // Reverse the touch delta in order to scroll in the desired direction
+    dx = -dx;
+    dy = -dy;
     // Do the pan
     yield ok(synthesizeNativeTouchDrag(scrollframe, x, y, dx, dy),
         "Synthesized drag of (" + dx + ", " + dy + ") on configuration " + configuration);
     yield waitForAllPaints(function() {
       flushApzRepaints(testDriver);
     });
     // Check for expected scroll position
     checkScroll(scrollframe, ex, ey, 'configuration ' + configuration + ' ' + desc);
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -24,16 +24,17 @@
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/NotNull.h"
+#include "mozilla/Scoped.h"
 #include "mozilla/UniquePtr.h"
 #include "MainThreadUtils.h"
 #include "nsILabelableRunnable.h"
 
 #if defined(ANDROID) && defined(DEBUG)
 #include <android/log.h>
 #endif
 
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -7,17 +7,16 @@
 #ifndef js_Utility_h
 #define js_Utility_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/Move.h"
-#include "mozilla/Scoped.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WrappingOperations.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #ifdef JS_OOM_DO_BACKTRACES
@@ -601,43 +600,16 @@ js_pod_realloc(T* prior, size_t oldSize,
 {
     MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
     size_t bytes;
     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
         return nullptr;
     return static_cast<T*>(js_realloc(prior, bytes));
 }
 
-namespace js {
-
-template<typename T>
-struct ScopedFreePtrTraits
-{
-    typedef T* type;
-    static T* empty() { return nullptr; }
-    static void release(T* ptr) { js_free(ptr); }
-};
-SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
-
-template <typename T>
-struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
-{
-    static void release(T* ptr) { js_delete(ptr); }
-};
-SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
-
-template <typename T>
-struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
-{
-    static void release(T* ptr) { if (ptr) ptr->release(); }
-};
-SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
-
-} /* namespace js */
-
 namespace JS {
 
 template<typename T>
 struct DeletePolicy
 {
     constexpr DeletePolicy() {}
 
     template<typename U>
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -3346,17 +3346,17 @@ reflect_parse(JSContext* cx, uint32_t ar
                                   "Reflect.parse", "0", "s");
         return false;
     }
 
     RootedString src(cx, ToString<CanGC>(cx, args[0]));
     if (!src)
         return false;
 
-    ScopedJSFreePtr<char> filename;
+    UniqueChars filename;
     uint32_t lineno = 1;
     bool loc = true;
     RootedObject builder(cx);
     ParseGoal target = ParseGoal::Script;
 
     RootedValue arg(cx, args.get(1));
 
     if (!arg.isNullOrUndefined()) {
@@ -3385,17 +3385,17 @@ reflect_parse(JSContext* cx, uint32_t ar
             if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
                 return false;
 
             if (!prop.isNullOrUndefined()) {
                 RootedString str(cx, ToString<CanGC>(cx, prop));
                 if (!str)
                     return false;
 
-                filename = JS_EncodeString(cx, str);
+                filename.reset(JS_EncodeString(cx, str));
                 if (!filename)
                     return false;
             }
 
             /* config.line */
             RootedId lineId(cx, NameToId(cx->names().line));
             RootedValue oneValue(cx, Int32Value(1));
             if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
@@ -3446,30 +3446,30 @@ reflect_parse(JSContext* cx, uint32_t ar
             target = ParseGoal::Module;
         } else {
             JS_ReportErrorASCII(cx, "Bad target value, expected 'script' or 'module'");
             return false;
         }
     }
 
     /* Extract the builder methods first to report errors before parsing. */
-    ASTSerializer serialize(cx, loc, filename, lineno);
+    ASTSerializer serialize(cx, loc, filename.get(), lineno);
     if (!serialize.init(builder))
         return false;
 
     JSLinearString* linear = src->ensureLinear(cx);
     if (!linear)
         return false;
 
     AutoStableStringChars linearChars(cx);
     if (!linearChars.initTwoByte(cx, linear))
         return false;
 
     CompileOptions options(cx);
-    options.setFileAndLine(filename, lineno);
+    options.setFileAndLine(filename.get(), lineno);
     options.setCanLazilyParse(false);
     options.allowHTMLComments = target == ParseGoal::Script;
     mozilla::Range<const char16_t> chars = linearChars.twoByteRange();
     UsedNameTracker usedNames(cx);
     if (!usedNames.init())
         return false;
 
     RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -34,16 +34,17 @@
 #include "jsnum.h"
 
 #include "builtin/TypedObject.h"
 #include "ctypes/Library.h"
 #include "gc/FreeOp.h"
 #include "gc/Policy.h"
 #include "gc/Zone.h"
 #include "jit/AtomicOperations.h"
+#include "js/UniquePtr.h"
 #include "js/Vector.h"
 #include "util/Windows.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 
 #include "vm/JSObject-inl.h"
 
 using namespace std;
@@ -8388,35 +8389,34 @@ CDataFinalizer::Construct(JSContext* cx,
   size_t sizeArg;
   RootedValue valData(cx, args[0]);
   if (!CType::GetSafeSize(objArgType, &sizeArg)) {
     RootedValue valCodeType(cx, ObjectValue(*objCodeType));
     return TypeError(cx, "a function with one known size argument",
                      valCodeType);
   }
 
-  ScopedJSFreePtr<void> cargs(malloc(sizeArg));
+  UniquePtr<void, JS::FreePolicy> cargs(malloc(sizeArg));
 
   if (!ImplicitConvert(cx, valData, objArgType, cargs.get(),
                        ConversionType::Finalizer, &freePointer,
                        objCodePtrType, 0)) {
     return false;
   }
   if (freePointer) {
     // Note: We could handle that case, if necessary.
     JS_ReportErrorASCII(cx, "Internal Error during CDataFinalizer. Object cannot be represented");
     return false;
   }
 
   // 4. Prepare buffer for holding return value
 
-  ScopedJSFreePtr<void> rvalue;
+  UniquePtr<void, JS::FreePolicy> rvalue;
   if (CType::GetTypeCode(returnType) != TYPE_void_t) {
-    rvalue = malloc(Align(CType::GetSize(returnType),
-                          sizeof(ffi_arg)));
+    rvalue.reset(malloc(Align(CType::GetSize(returnType), sizeof(ffi_arg))));
   } //Otherwise, simply do not allocate
 
   // 5. Create |objResult|
 
   JSObject* objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto);
   if (!objResult) {
     return false;
   }
@@ -8460,28 +8460,28 @@ CDataFinalizer::Construct(JSContext* cx,
   ffi_type* rtype = CType::GetFFIType(cx, funInfoFinalizer->mReturnType);
   if (!rtype) {
     JS_ReportErrorASCII(cx, "Internal Error: "
                         "Could not access ffi type of CDataFinalizer");
     return false;
   }
 
   // 7. Store C information as private
-  ScopedJSFreePtr<CDataFinalizer::Private>
+  UniquePtr<CDataFinalizer::Private, JS::FreePolicy>
     p((CDataFinalizer::Private*)malloc(sizeof(CDataFinalizer::Private)));
 
   memmove(&p->CIF, &funInfoFinalizer->mCIF, sizeof(ffi_cif));
 
-  p->cargs = cargs.forget();
-  p->rvalue = rvalue.forget();
+  p->cargs = cargs.release();
+  p->rvalue = rvalue.release();
   p->cargs_size = sizeArg;
   p->code = code;
 
 
-  JS_SetPrivate(objResult, p.forget());
+  JS_SetPrivate(objResult, p.release());
   args.rval().setObject(*objResult);
   return true;
 }
 
 
 /*
  * Actually call the finalizer. Does not perform any cleanup on the object.
  *
--- a/js/src/ds/OrderedHashTable.h
+++ b/js/src/ds/OrderedHashTable.h
@@ -97,16 +97,19 @@ class OrderedHashTable
         }
     }
 
   public:
     OrderedHashTable(AllocPolicy& ap, mozilla::HashCodeScrambler hcs)
       : hashTable(nullptr),
         data(nullptr),
         dataLength(0),
+        dataCapacity(0),
+        liveCount(0),
+        hashShift(0),
         ranges(nullptr),
         nurseryRanges(nullptr),
         alloc(ap),
         hcs(hcs)
     {}
 
     MOZ_MUST_USE bool init() {
         MOZ_ASSERT(!hashTable, "init must be called at most once");
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -103,16 +103,17 @@ class BinASTParser : public BinASTParser
     using AutoTuple = typename Tokenizer::AutoTuple;
     using BinFields = typename Tokenizer::BinFields;
     using Chars = typename Tokenizer::Chars;
 
   public:
     BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options)
         : BinASTParserBase(cx, alloc, usedNames)
         , options_(options)
+        , variableDeclarationKind_(VariableDeclarationKind::Var)
     {
     }
     ~BinASTParser()
     {
     }
 
     /**
      * Parse a buffer, returning a node (which may be nullptr) in case of success
--- a/js/src/frontend/BinTokenReaderBase.h
+++ b/js/src/frontend/BinTokenReaderBase.h
@@ -70,16 +70,17 @@ class MOZ_STACK_CLASS BinTokenReaderBase
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidNumberOfFields(
         const BinKind kind, const uint32_t expected, const uint32_t got);
     MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidField(const char* kind,
         const BinField field);
 
   protected:
     BinTokenReaderBase(JSContext* cx, const uint8_t* start, const size_t length)
         : cx_(cx)
+        , poisoned_(false)
         , start_(start)
         , current_(start)
         , stop_(start + length)
         , latestKnownGoodPos_(0)
     { }
 
     /**
      * Read a single byte.
--- a/js/src/frontend/BinTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinTokenReaderMultipart.cpp
@@ -339,17 +339,18 @@ BinTokenReaderMultipart::enterList(uint3
 
 void
 BinTokenReaderMultipart::AutoBase::init()
 {
     initialized_ = true;
 }
 
 BinTokenReaderMultipart::AutoBase::AutoBase(BinTokenReaderMultipart& reader)
-    : reader_(reader)
+    : initialized_(false)
+    , reader_(reader)
 { }
 
 BinTokenReaderMultipart::AutoBase::~AutoBase()
 {
     // By now, the `AutoBase` must have been deinitialized by calling `done()`.
     // The only case in which we can accept not calling `done()` is if we have
     // bailed out because of an error.
     MOZ_ASSERT_IF(initialized_, reader_.cx_->isExceptionPending());
--- a/js/src/frontend/BinTokenReaderTester.cpp
+++ b/js/src/frontend/BinTokenReaderTester.cpp
@@ -350,17 +350,18 @@ BinTokenReaderTester::enterList(uint32_t
 
 void
 BinTokenReaderTester::AutoBase::init()
 {
     initialized_ = true;
 }
 
 BinTokenReaderTester::AutoBase::AutoBase(BinTokenReaderTester& reader)
-    : reader_(reader)
+    : initialized_(false)
+    , reader_(reader)
 { }
 
 BinTokenReaderTester::AutoBase::~AutoBase()
 {
     // By now, the `AutoBase` must have been deinitialized by calling `done()`.
     // The only case in which we can accept not calling `done()` is if we have
     // bailed out because of an error.
     MOZ_ASSERT_IF(initialized_, reader_.cx_->isExceptionPending());
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1691,17 +1691,18 @@ class MOZ_STACK_CLASS TryEmitter
 
   public:
     TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
       : bce_(bce),
         kind_(kind),
         controlKind_(controlKind),
         depth_(0),
         noteIndex_(0),
-        tryStart_(0)
+        tryStart_(0),
+        tryEnd_{}
 #ifdef DEBUG
       , state_(State::Start)
 #endif
     {
         if (controlKind_ == ControlKind::Syntactic)
             controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
         finallyStart_.offset = 0;
     }
@@ -2506,16 +2507,17 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
   : sc(sc),
     cx(sc->context),
     parent(parent),
     script(cx, script),
     lazyScript(cx, lazyScript),
     prologue(cx, lineNum),
     main(cx, lineNum),
     current(&main),
+    parser(nullptr),
     atomIndices(cx->frontendCollectionPool()),
     firstLine(lineNum),
     maxFixedSlots(0),
     maxStackDepth(0),
     stackDepth(0),
     emitLevel(0),
     bodyScopeIndex(UINT32_MAX),
     varEmitterScope(nullptr),
--- a/js/src/frontend/NameCollections.h
+++ b/js/src/frontend/NameCollections.h
@@ -108,17 +108,19 @@ struct RecyclableAtomMapValueWrapper
         uint64_t dummy;
     };
 
     static void assertInvariant() {
         static_assert(sizeof(Wrapped) <= sizeof(uint64_t),
                       "Can only recycle atom maps with values smaller than uint64");
     }
 
-    RecyclableAtomMapValueWrapper() {
+    RecyclableAtomMapValueWrapper()
+      : dummy(0)
+    {
         assertInvariant();
     }
 
     MOZ_IMPLICIT RecyclableAtomMapValueWrapper(Wrapped w)
       : wrapped(w)
     {
         assertInvariant();
     }
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -191,17 +191,20 @@ struct KeywordInfo;
 
 namespace js {
 namespace frontend {
 
 struct TokenPos {
     uint32_t    begin;  // Offset of the token's first char.
     uint32_t    end;    // Offset of 1 past the token's last char.
 
-    TokenPos() {}
+    TokenPos()
+      : begin(0),
+        end(0)
+    {}
     TokenPos(uint32_t begin, uint32_t end) : begin(begin), end(end) {}
 
     // Return a TokenPos that covers left, right, and anything in between.
     static TokenPos box(const TokenPos& left, const TokenPos& right) {
         MOZ_ASSERT(left.begin <= left.end);
         MOZ_ASSERT(left.end <= right.begin);
         MOZ_ASSERT(right.begin <= right.end);
         return TokenPos(left.begin, right.end);
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -428,26 +428,22 @@ class Nursery
         mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount, mozilla::TimeStamp>;
     using ProfileDurations =
         mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount, mozilla::TimeDuration>;
 
     ProfileTimes startTimes_;
     ProfileDurations profileDurations_;
     ProfileDurations totalDurations_;
 
-    /*
-     * This data is initialised only if the nursery is enabled and after at
-     * least one call to Nursery::collect()
-     */
     struct {
-        JS::gcreason::Reason reason;
-        size_t nurseryCapacity;
-        size_t nurseryLazyCapacity;
-        size_t nurseryUsedBytes;
-        size_t tenuredBytes;
+        JS::gcreason::Reason reason = JS::gcreason::NO_REASON;
+        size_t nurseryCapacity = 0;
+        size_t nurseryLazyCapacity = 0;
+        size_t nurseryUsedBytes = 0;
+        size_t tenuredBytes = 0;
     } previousGC;
 
     /*
      * Calculate the promotion rate of the most recent minor GC.
      * The valid_for_tenuring parameter is used to return whether this
      * promotion rate is accurate enough (the nursery was full enough) to be
      * used for tenuring and other decisions.
      *
--- a/js/src/gc/Rooting.h
+++ b/js/src/gc/Rooting.h
@@ -129,17 +129,19 @@ class FakeMutableHandle : public js::Mut
         *ptr = v;
     }
 
     DECLARE_POINTER_CONSTREF_OPS(T);
     DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
     DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
 
   private:
-    FakeMutableHandle() {}
+    FakeMutableHandle()
+      : ptr(nullptr)
+    {}
     DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T);
 
     T* ptr;
 };
 
 template <typename T> class MaybeRooted<T, NoGC>
 {
   public:
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -739,16 +739,19 @@ Statistics::Statistics(JSRuntime* rt)
   : runtime(rt),
     gcTimerFile(nullptr),
     gcDebugFile(nullptr),
     nonincrementalReason_(gc::AbortReason::None),
     preBytes(0),
     thresholdTriggered(false),
     triggerAmount(0.0),
     triggerThreshold(0.0),
+    startingMinorGCNumber(0),
+    startingMajorGCNumber(0),
+    startingSliceNumber(0),
     maxPauseInInterval(0),
     sliceCallback(nullptr),
     nurseryCollectionCallback(nullptr),
     aborted(false),
     enableProfiling_(false),
     sliceCount_(0)
 {
     for (auto& count : counts)
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -216,17 +216,18 @@ struct Statistics
     struct SliceData {
         SliceData(SliceBudget budget, JS::gcreason::Reason reason,
                   TimeStamp start, size_t startFaults, gc::State initialState)
           : budget(budget), reason(reason),
             initialState(initialState),
             finalState(gc::State::NotActive),
             resetReason(gc::AbortReason::None),
             start(start),
-            startFaults(startFaults)
+            startFaults(startFaults),
+            endFaults(0)
         {}
 
         SliceBudget budget;
         JS::gcreason::Reason reason;
         gc::State initialState, finalState;
         gc::AbortReason resetReason;
         TimeStamp start, end;
         size_t startFaults, endFaults;
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1647,16 +1647,17 @@ IsLatin1Equivalent(char16_t c, RegExpCom
 }
 
 // Attempts to compile the regexp using an Irregexp code generator.  Returns
 // a fixed array or a null handle depending on whether it succeeded.
 RegExpCompiler::RegExpCompiler(JSContext* cx, LifoAlloc* alloc, int capture_count,
                                bool ignore_case, bool latin1, bool match_only, bool unicode)
   : next_register_(2 * (capture_count + 1)),
     recursion_depth_(0),
+    macro_assembler_(nullptr),
     ignore_case_(ignore_case),
     latin1_(latin1),
     match_only_(match_only),
     unicode_(unicode),
     reg_exp_too_big_(false),
     current_expansion_factor_(1),
     frequency_collator_(),
     cx_(cx),
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -681,16 +681,17 @@ class ActionNode : public SeqRegExpNode
         BEGIN_SUBMATCH,
         POSITIVE_SUBMATCH_SUCCESS,
         EMPTY_MATCH_CHECK,
         CLEAR_CAPTURES
     };
 
     ActionNode(ActionType action_type, RegExpNode* on_success)
       : SeqRegExpNode(on_success),
+        data_{},
         action_type_(action_type)
     {}
 
     static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
     static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
     static ActionNode* StorePosition(int reg,
                                      bool is_capture,
                                      RegExpNode* on_success);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/Ion.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ThreadLocal.h"
+#include "mozilla/Unused.h"
 
 #include "gc/FreeOp.h"
 #include "gc/Marking.h"
 #include "jit/AliasAnalysis.h"
 #include "jit/AlignmentMaskAnalysis.h"
 #include "jit/BacktrackingAllocator.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineInspector.h"
@@ -41,16 +42,17 @@
 #include "jit/PerfSpewer.h"
 #include "jit/RangeAnalysis.h"
 #include "jit/ScalarReplacement.h"
 #include "jit/Sink.h"
 #include "jit/StupidAllocator.h"
 #include "jit/ValueNumbering.h"
 #include "jit/WasmBCE.h"
 #include "js/Printf.h"
+#include "js/UniquePtr.h"
 #include "util/Windows.h"
 #include "vm/Debugger.h"
 #include "vm/HelperThreads.h"
 #include "vm/Realm.h"
 #include "vm/TraceLogging.h"
 #include "vtune/VTuneWrapper.h"
 
 #include "gc/PrivateIterators-inl.h"
@@ -2040,23 +2042,21 @@ IonCompile(JSContext* cx, JSScript* scri
     AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
 
     // Make sure the script's canonical function isn't lazy. We can't de-lazify
     // it in a helper thread.
     script->ensureNonLazyCanonicalFunction();
 
     TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
 
-    LifoAlloc* alloc = cx->new_<LifoAlloc>(TempAllocator::PreferredLifoChunkSize);
+    auto alloc = cx->make_unique<LifoAlloc>(TempAllocator::PreferredLifoChunkSize);
     if (!alloc)
         return AbortReason::Alloc;
 
-    ScopedJSDeletePtr<LifoAlloc> autoDelete(alloc);
-
-    TempAllocator* temp = alloc->new_<TempAllocator>(alloc);
+    TempAllocator* temp = alloc->new_<TempAllocator>(alloc.get());
     if (!temp)
         return AbortReason::Alloc;
 
     JitContext jctx(cx, temp);
 
     if (!cx->realm()->ensureJitRealmExists(cx))
         return AbortReason::Alloc;
 
@@ -2179,34 +2179,33 @@ IonCompile(JSContext* cx, JSScript* scri
             return AbortReason::Alloc;
         }
 
         if (!recompile)
             builderScript->setIonScript(cx->runtime(), ION_COMPILING_SCRIPT);
 
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
-        autoDelete.forget();
+        mozilla::Unused << alloc.release();
 
         return AbortReason::NoAbort;
     }
 
     bool succeeded = false;
     {
-        ScopedJSDeletePtr<CodeGenerator> codegen;
         AutoEnterAnalysis enter(cx);
-        codegen = CompileBackEnd(builder);
+        UniquePtr<CodeGenerator> codegen(CompileBackEnd(builder));
         if (!codegen) {
             JitSpew(JitSpew_IonAbort, "Failed during back-end compilation.");
             if (cx->isExceptionPending())
                 return AbortReason::Error;
             return AbortReason::Disable;
         }
 
-        succeeded = LinkCodeGen(cx, builder, codegen);
+        succeeded = LinkCodeGen(cx, builder, codegen.get());
     }
 
     if (succeeded)
         return AbortReason::NoAbort;
     if (cx->isExceptionPending())
         return AbortReason::Error;
     return AbortReason::Disable;
 }
--- a/js/src/jsapi-tests/testPrivateGCThingValue.cpp
+++ b/js/src/jsapi-tests/testPrivateGCThingValue.cpp
@@ -19,16 +19,18 @@ class TestTracer : public JS::CallbackTr
 
   public:
     js::gc::Cell* expectedCell;
     JS::TraceKind expectedKind;
     bool found;
 
     explicit TestTracer(JSContext* cx)
       : JS::CallbackTracer(cx),
+        expectedCell(nullptr),
+        expectedKind(static_cast<JS::TraceKind>(0)),
         found(false)
     { }
 };
 
 static const JSClass TestClass = {
     "TestClass",
     JSCLASS_HAS_RESERVED_SLOTS(1)
 };
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -474,17 +474,21 @@ class ExternalData {
  */
 class AutoLeaveZeal
 {
     JSContext* cx_;
     uint32_t zealBits_;
     uint32_t frequency_;
 
   public:
-    explicit AutoLeaveZeal(JSContext* cx) : cx_(cx) {
+    explicit AutoLeaveZeal(JSContext* cx)
+      : cx_(cx),
+        zealBits_(0),
+        frequency_(0)
+    {
         uint32_t dummy;
         JS_GetGCZealBits(cx_, &zealBits_, &frequency_, &dummy);
         JS_SetGCZeal(cx_, 0, 0);
         JS::PrepareForFullGC(cx_);
         JS::NonIncrementalGC(cx_, GC_SHRINK, JS::gcreason::DEBUG_GC);
     }
     ~AutoLeaveZeal() {
         JS_SetGCZeal(cx_, 0, 0);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6625,17 +6625,17 @@ JS_ObjectIsDate(JSContext* cx, HandleObj
  * Regular Expressions.
  */
 JS_PUBLIC_API(JSObject*)
 JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    ScopedJSFreePtr<char16_t> chars(InflateString(cx, bytes, length));
+    UniqueTwoByteChars chars(InflateString(cx, bytes, length));
     if (!chars)
         return nullptr;
 
     return RegExpObject::create(cx, chars.get(), length, RegExpFlag(flags), cx->tempLifoAlloc(),
                                 GenericObject);
 }
 
 JS_PUBLIC_API(JSObject*)
@@ -6864,17 +6864,20 @@ JS::AutoSaveExceptionState::~AutoSaveExc
             context->overRecursed_ = wasOverRecursed;
             context->throwing = true;
             context->unwrappedException() = exceptionValue;
         }
     }
 }
 
 struct JSExceptionState {
-    explicit JSExceptionState(JSContext* cx) : exception(cx) {}
+    explicit JSExceptionState(JSContext* cx)
+      : throwing(false),
+        exception(cx)
+    {}
     bool throwing;
     PersistentRootedValue exception;
 };
 
 JS_PUBLIC_API(JSExceptionState*)
 JS_SaveExceptionState(JSContext* cx)
 {
     JSExceptionState* state;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1419,17 +1419,17 @@ class MOZ_STACK_CLASS JS_FRIEND_API(Auto
      * When copying string char, use this many bytes of inline storage.  This is
      * chosen to allow the inline string types to be copied without allocating.
      * This is asserted in AutoStableStringChars::allocOwnChars.
      */
     static const size_t InlineCapacity = 24;
 
     /* Ensure the string is kept alive while we're using its chars. */
     JS::RootedString s_;
-    union {
+    MOZ_INIT_OUTSIDE_CTOR union {
         const char16_t* twoByteChars_;
         const JS::Latin1Char* latin1Chars_;
     };
     mozilla::Maybe<Vector<uint8_t, InlineCapacity>> ownChars_;
     enum State { Uninitialized, Latin1, TwoByte };
     State state_;
 
   public:
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -81,32 +81,32 @@ EnsureDtoaState(JSContext* cx)
  * Call js_strtod_harder to get the correct answer.
  */
 template <typename CharT>
 static bool
 ComputeAccurateDecimalInteger(JSContext* cx, const CharT* start, const CharT* end,
                               double* dp)
 {
     size_t length = end - start;
-    ScopedJSFreePtr<char> cstr(cx->pod_malloc<char>(length + 1));
+    UniqueChars cstr(cx->pod_malloc<char>(length + 1));
     if (!cstr)
         return false;
 
     for (size_t i = 0; i < length; i++) {
         char c = char(start[i]);
         MOZ_ASSERT(IsAsciiAlphanumeric(c));
         cstr[i] = c;
     }
     cstr[length] = 0;
 
     if (!EnsureDtoaState(cx))
         return false;
 
     char* estr;
-    *dp = js_strtod_harder(cx->dtoaState, cstr, &estr);
+    *dp = js_strtod_harder(cx->dtoaState, cstr.get(), &estr);
 
     return true;
 }
 
 namespace {
 
 template <typename CharT>
 class BinaryDigitReader
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -879,33 +879,33 @@ RunBinAST(JSContext* cx, const char* fil
 static bool
 InitModuleLoader(JSContext* cx)
 {
 
     // Decompress and evaluate the embedded module loader source to initialize
     // the module loader for the current compartment.
 
     uint32_t srcLen = moduleloader::GetRawScriptsSize();
-    ScopedJSFreePtr<char> src(cx->pod_malloc<char>(srcLen));
+    UniqueChars src(cx->pod_malloc<char>(srcLen));
     if (!src || !DecompressString(moduleloader::compressedSources, moduleloader::GetCompressedSize(),
                                   reinterpret_cast<unsigned char*>(src.get()), srcLen))
     {
         return false;
     }
 
     CompileOptions options(cx);
     options.setIntroductionType("shell module loader");
     options.setFileAndLine("shell/ModuleLoader.js", 1);
     options.setSelfHostingMode(false);
     options.setCanLazilyParse(false);
     options.werrorOption = true;
     options.strictOption = true;
 
     RootedValue rv(cx);
-    return Evaluate(cx, options, src, srcLen, &rv);
+    return Evaluate(cx, options, src.get(), srcLen, &rv);
 }
 
 static bool
 GetLoaderObject(JSContext* cx, MutableHandleObject resultOut)
 {
     // Look up the |Reflect.Loader| object that has been defined by the module
     // loader.
 
--- a/js/src/util/StringBuffer.cpp
+++ b/js/src/util/StringBuffer.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "util/StringBuffer.h"
 
 #include "mozilla/Range.h"
+#include "mozilla/Unused.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/StringType-inl.h"
 
 using namespace js;
 
 template <typename CharT, class Buffer>
 static CharT*
@@ -74,31 +75,31 @@ StringBuffer::inflateChars()
 template <typename CharT, class Buffer>
 static JSFlatString*
 FinishStringFlat(JSContext* cx, StringBuffer& sb, Buffer& cb)
 {
     size_t len = sb.length();
     if (!sb.append('\0'))
         return nullptr;
 
-    ScopedJSFreePtr<CharT> buf(ExtractWellSized<CharT>(cx, cb));
+    UniquePtr<CharT[], JS::FreePolicy> buf(ExtractWellSized<CharT>(cx, cb));
     if (!buf)
         return nullptr;
 
     JSFlatString* str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
     if (!str)
         return nullptr;
 
     /*
      * The allocation was made on a TempAllocPolicy, so account for the string
      * data on the string's zone.
      */
     cx->updateMallocCounter(sizeof(CharT) * len);
 
-    buf.forget();
+    mozilla::Unused << buf.release();
     return str;
 }
 
 JSFlatString*
 StringBuffer::finishString()
 {
     size_t len = length();
     if (len == 0)
--- a/js/src/vm/BytecodeUtil.h
+++ b/js/src/vm/BytecodeUtil.h
@@ -468,17 +468,17 @@ class SrcNoteLineScanner
      * Is the current op the first one after a line change directive? Note that
      * multiple ops may be "first" if a line directive is used to return to a
      * previous line (eg, with a for loop increment expression.)
      */
     bool lineHeader;
 
   public:
     SrcNoteLineScanner(jssrcnote* sn, uint32_t lineno)
-        : offset(0), sn(sn), lineno(lineno)
+        : offset(0), sn(sn), lineno(lineno), lineHeader(false)
     {
     }
 
     /*
      * This is called repeatedly with always-advancing relpc values. The src
      * notes are tuples of <PC offset from prev src note, type, args>. Scan
      * through, updating the lineno, until the next src note is for a later
      * bytecode.
--- a/js/src/vm/Caches.h
+++ b/js/src/vm/Caches.h
@@ -78,17 +78,17 @@ struct EvalCacheEntry
     }
 };
 
 struct EvalCacheLookup
 {
     explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
     RootedLinearString str;
     RootedScript callerScript;
-    jsbytecode* pc;
+    MOZ_INIT_OUTSIDE_CTOR jsbytecode* pc;
 };
 
 struct EvalCacheHashPolicy
 {
     typedef EvalCacheLookup Lookup;
 
     static HashNumber hash(const Lookup& l);
     static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
--- a/js/src/vm/Compartment.cpp
+++ b/js/src/vm/Compartment.cpp
@@ -122,32 +122,32 @@ CopyStringPure(JSContext* cx, JSString* 
             return nullptr;
 
         return chars.isLatin1()
                ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len)
                : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
     }
 
     if (str->hasLatin1Chars()) {
-        ScopedJSFreePtr<Latin1Char> copiedChars;
-        if (!str->asRope().copyLatin1CharsZ(cx, copiedChars))
+        UniquePtr<Latin1Char[], JS::FreePolicy> copiedChars = str->asRope().copyLatin1CharsZ(cx);
+        if (!copiedChars)
             return nullptr;
 
-        auto* rawCopiedChars = copiedChars.forget();
+        auto* rawCopiedChars = copiedChars.release();
         auto* result = NewString<CanGC>(cx, rawCopiedChars, len);
         if (!result)
             js_free(rawCopiedChars);
         return result;
     }
 
-    ScopedJSFreePtr<char16_t> copiedChars;
-    if (!str->asRope().copyTwoByteCharsZ(cx, copiedChars))
+    UniqueTwoByteChars copiedChars = str->asRope().copyTwoByteCharsZ(cx);
+    if (!copiedChars)
         return nullptr;
 
-    auto* rawCopiedChars = copiedChars.forget();
+    auto* rawCopiedChars = copiedChars.release();
     auto* result = NewStringDontDeflate<CanGC>(cx, rawCopiedChars, len);
     if (!result)
         js_free(rawCopiedChars);
     return result;
 }
 
 bool
 Compartment::wrap(JSContext* cx, MutableHandleString strp)
--- a/js/src/vm/Compression.cpp
+++ b/js/src/vm/Compression.cpp
@@ -40,16 +40,23 @@ Compressor::Compressor(const unsigned ch
     MOZ_ASSERT(inplen > 0);
     zs.opaque = nullptr;
     zs.next_in = (Bytef*)inp;
     zs.avail_in = 0;
     zs.next_out = nullptr;
     zs.avail_out = 0;
     zs.zalloc = zlib_alloc;
     zs.zfree = zlib_free;
+    zs.total_in = 0;
+    zs.total_out = 0;
+    zs.msg = nullptr;
+    zs.state = nullptr;
+    zs.data_type = 0;
+    zs.adler = 0;
+    zs.reserved = 0;
 
     // Reserve space for the CompressedDataHeader.
     outbytes = sizeof(CompressedDataHeader);
 }
 
 Compressor::~Compressor()
 {
     if (initialized) {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4225,19 +4225,23 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
         cx(cx),
         debugger(dbg),
         iterMarker(&cx->runtime()->gc),
         realms(cx->zone()),
         url(cx),
         displayURLString(cx),
         hasSource(false),
         source(cx, AsVariant(static_cast<ScriptSourceObject*>(nullptr))),
+        hasLine(false),
+        line(0),
+        innermost(false),
         innermostForRealm(cx->zone()),
         vector(cx, ScriptVector(cx)),
-        wasmInstanceVector(cx, WasmInstanceObjectVector(cx))
+        wasmInstanceVector(cx, WasmInstanceObjectVector(cx)),
+        oom(false)
     {}
 
     /*
      * Initialize this ScriptQuery. Raise an error and return false if we
      * haven't enough memory.
      */
     bool init() {
         if (!realms.init() ||
@@ -5458,17 +5462,20 @@ DebuggerScript_getStartLine(JSContext* c
     return true;
 }
 
 struct DebuggerScriptGetLineCountMatcher
 {
     JSContext* cx_;
     double totalLines;
 
-    explicit DebuggerScriptGetLineCountMatcher(JSContext* cx) : cx_(cx) {}
+    explicit DebuggerScriptGetLineCountMatcher(JSContext* cx)
+      : cx_(cx),
+        totalLines(0.0)
+    {}
     using ReturnType = bool;
 
     ReturnType match(HandleScript script) {
         totalLines = double(GetScriptLineExtent(script));
         return true;
     }
     ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
         uint32_t result;
@@ -6682,17 +6689,21 @@ DebuggerScript_clearAllBreakpoints(JSCon
 
 class DebuggerScriptIsInCatchScopeMatcher
 {
     JSContext* cx_;
     size_t offset_;
     bool isInCatch_;
 
   public:
-    explicit DebuggerScriptIsInCatchScopeMatcher(JSContext* cx, size_t offset) : cx_(cx), offset_(offset) { }
+    explicit DebuggerScriptIsInCatchScopeMatcher(JSContext* cx, size_t offset)
+      : cx_(cx),
+        offset_(offset),
+        isInCatch_(false)
+    { }
     using ReturnType = bool;
 
     inline bool isInCatch() const { return isInCatch_; }
 
     ReturnType match(HandleScript script) {
         if (!EnsureScriptOffsetIsValid(cx_, script, offset_))
             return false;
 
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Maybe.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Unused.h"
 
 #include "builtin/Promise.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/GCInternals.h"
 #include "jit/IonBuilder.h"
+#include "js/UniquePtr.h"
 #include "js/Utility.h"
 #include "threading/CpuCount.h"
 #include "util/NativeStack.h"
 #include "vm/Debugger.h"
 #include "vm/ErrorReporting.h"
 #include "vm/SharedImmutableStringsCache.h"
 #include "vm/Time.h"
 #include "vm/TraceLogging.h"
@@ -821,80 +822,75 @@ StartOffThreadParseTask(JSContext* cx, P
     return true;
 }
 
 bool
 js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                               const char16_t* chars, size_t length,
                               JS::OffThreadCompileCallback callback, void* callbackData)
 {
-    ScopedJSDeletePtr<ParseTask> task;
-    task = cx->new_<ScriptParseTask>(cx, chars, length, callback, callbackData);
-    if (!task || !StartOffThreadParseTask(cx, task, options))
+    auto task = cx->make_unique<ScriptParseTask>(cx, chars, length, callback, callbackData);
+    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
         return false;
 
-    task.forget();
+    Unused << task.release();
     return true;
 }
 
 bool
 js::StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                               const char16_t* chars, size_t length,
                               JS::OffThreadCompileCallback callback, void* callbackData)
 {
-    ScopedJSDeletePtr<ParseTask> task;
-    task = cx->new_<ModuleParseTask>(cx, chars, length, callback, callbackData);
-    if (!task || !StartOffThreadParseTask(cx, task, options))
+    auto task = cx->make_unique<ModuleParseTask>(cx, chars, length, callback, callbackData);
+    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
         return false;
 
-    task.forget();
+    Unused << task.release();
     return true;
 }
 
 bool
 js::StartOffThreadDecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                                const JS::TranscodeRange& range,
                                JS::OffThreadCompileCallback callback, void* callbackData)
 {
-    ScopedJSDeletePtr<ParseTask> task;
-    task = cx->new_<ScriptDecodeTask>(cx, range, callback, callbackData);
-    if (!task || !StartOffThreadParseTask(cx, task, options))
+    auto task = cx->make_unique<ScriptDecodeTask>(cx, range, callback, callbackData);
+    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
         return false;
 
-    task.forget();
+    Unused << task.release();
     return true;
 }
 
 bool
 js::StartOffThreadDecodeMultiScripts(JSContext* cx, const ReadOnlyCompileOptions& options,
                                      JS::TranscodeSources& sources,
                                      JS::OffThreadCompileCallback callback, void* callbackData)
 {
-    ScopedJSDeletePtr<ParseTask> task;
-    task = cx->new_<MultiScriptsDecodeTask>(cx, sources, callback, callbackData);
-    if (!task || !StartOffThreadParseTask(cx, task, options))
+    auto task = cx->make_unique<MultiScriptsDecodeTask>(cx, sources, callback, callbackData);
+    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
         return false;
 
-    task.forget();
+    Unused << task.release();
     return true;
 }
 
 #if defined(JS_BUILD_BINAST)
 
 bool
 js::StartOffThreadDecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
                                const uint8_t* buf, size_t length,
                                JS::OffThreadCompileCallback callback, void *callbackData)
 {
-    ScopedJSDeletePtr<ParseTask> task;
-    task = cx->new_<BinASTDecodeTask>(cx, buf, length, callback, callbackData);
-    if (!task || !StartOffThreadParseTask(cx, task, options))
+    auto task = cx->make_unique<BinASTDecodeTask>(cx, buf, length, callback, callbackData);
+    if (!task || !StartOffThreadParseTask(cx, task.get(), options))
         return false;
 
-    task.forget();
+    Unused << task.release();
     return true;
 }
 
 #endif /* JS_BUILD_BINAST */
 
 void
 js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
 {
@@ -1660,43 +1656,42 @@ GlobalHelperThreadState::removeFinishedP
 
 template <typename F, typename>
 bool
 GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
                                          JS::OffThreadToken* token, F&& finishCallback)
 {
     MOZ_ASSERT(cx->realm());
 
-    ScopedJSDeletePtr<ParseTask> parseTask(removeFinishedParseTask(kind, token));
+    Rooted<UniquePtr<ParseTask>> parseTask(cx, removeFinishedParseTask(kind, token));
 
     // Make sure we have all the constructors we need for the prototype
     // remapping below, since we can't GC while that's happening.
     if (!EnsureParserCreatedClasses(cx, kind)) {
-        LeaveParseTaskZone(cx->runtime(), parseTask);
+        LeaveParseTaskZone(cx->runtime(), parseTask.get().get());
         return false;
     }
 
-    mergeParseTaskRealm(cx, parseTask, cx->realm());
-
-    bool ok = finishCallback(parseTask);
+    mergeParseTaskRealm(cx, parseTask.get().get(), cx->realm());
+
+    bool ok = finishCallback(parseTask.get().get());
 
     for (auto& script : parseTask->scripts)
         releaseAssertSameCompartment(cx, script);
 
     if (!parseTask->finish(cx) || !ok)
         return false;
 
     // Report out of memory errors eagerly, or errors could be malformed.
     if (parseTask->outOfMemory) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    // Report any error or warnings generated during the parse, and inform the
-    // debugger about the compiled scripts.
+    // Report any error or warnings generated during the parse.
     for (size_t i = 0; i < parseTask->errors.length(); i++)
         parseTask->errors[i]->throwError(cx);
     if (parseTask->overRecursed)
         ReportOverRecursed(cx);
     if (cx->isExceptionPending())
         return false;
 
     return true;
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -32,16 +32,17 @@
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/SharedContext.h"
 #include "gc/FreeOp.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonCode.h"
 #include "js/MemoryMetrics.h"
 #include "js/Printf.h"
+#include "js/UniquePtr.h"
 #include "js/Utility.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Compression.h"
 #include "vm/Debugger.h"
@@ -1612,17 +1613,19 @@ ScriptSource::chunkChars(JSContext* cx, 
         return nullptr;
     }
     return ret;
 }
 
 ScriptSource::PinnedChars::PinnedChars(JSContext* cx, ScriptSource* source,
                                        UncompressedSourceCache::AutoHoldEntry& holder,
                                        size_t begin, size_t len)
-  : source_(source)
+  : stack_(nullptr),
+    prev_(nullptr),
+    source_(source)
 {
     chars_ = source->chars(cx, holder, begin, len);
     if (chars_) {
         stack_ = &source->pinnedCharsStack_;
         prev_ = *stack_;
         *stack_ = this;
     }
 }
@@ -3446,17 +3449,17 @@ js::detail::CopyScript(JSContext* cx, Ha
     uint32_t nscopes   = src->scopes()->length;
     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
     uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
     uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
 
     /* Script data */
 
     size_t size = src->dataSize();
-    ScopedJSFreePtr<uint8_t> data(AllocScriptData(cx->zone(), size));
+    UniquePtr<uint8_t, JS::FreePolicy> data(AllocScriptData(cx->zone(), size));
     if (size && !data) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     /* Scopes */
 
     // The passed in scopes vector contains body scopes that needed to be
@@ -3514,17 +3517,17 @@ js::detail::CopyScript(JSContext* cx, Ha
             }
 
             if (!clone || !objects.append(clone))
                 return false;
         }
     }
 
     /* This assignment must occur before all the Rebase calls. */
-    dst->data = data.forget();
+    dst->data = data.release();
     dst->dataSize_ = size;
     MOZ_ASSERT(bool(dst->data) == bool(src->data));
     if (dst->data)
         memcpy(dst->data, src->data, size);
 
     if (cx->zone() != src->zoneFromAnyThread()) {
         for (size_t i = 0; i < src->scriptData()->natoms(); i++)
             cx->markAtom(src->scriptData()->atoms()[i]);
@@ -4250,30 +4253,33 @@ LazyScript::CreateRaw(JSContext* cx, Han
 
     // Reset runtime flags to obtain a fresh LazyScript.
     p.hasBeenCloned = false;
     p.treatAsRunOnce = false;
 
     size_t bytes = (p.numClosedOverBindings * sizeof(JSAtom*))
                  + (p.numInnerFunctions * sizeof(GCPtrFunction));
 
-    ScopedJSFreePtr<uint8_t> table(bytes ? fun->zone()->pod_malloc<uint8_t>(bytes) : nullptr);
-    if (bytes && !table) {
-        ReportOutOfMemory(cx);
-        return nullptr;
+    UniquePtr<uint8_t, JS::FreePolicy> table;
+    if (bytes) {
+        table.reset(fun->zone()->pod_malloc<uint8_t>(bytes));
+        if (!table) {
+            ReportOutOfMemory(cx);
+            return nullptr;
+        }
     }
 
     LazyScript* res = Allocate<LazyScript>(cx);
     if (!res)
         return nullptr;
 
     cx->realm()->scheduleDelazificationForDebugger();
 
-    return new (res) LazyScript(fun, *sourceObject, table.forget(), packed, sourceStart, sourceEnd,
-                                toStringStart, lineno, column);
+    return new (res) LazyScript(fun, *sourceObject, table.release(), packed, sourceStart,
+                                sourceEnd, toStringStart, lineno, column);
 }
 
 /* static */ LazyScript*
 LazyScript::Create(JSContext* cx, HandleFunction fun,
                    HandleScriptSourceObject sourceObject,
                    const frontend::AtomVector& closedOverBindings,
                    Handle<GCVector<JSFunction*, 8>> innerFunctions,
                    uint32_t sourceStart, uint32_t sourceEnd,
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -2094,16 +2094,17 @@ class JSScript : public js::gc::TenuredC
     {
         JS::RootedScript script_;
         JSContext* cx_;
         bool oldDoNotRelazify_;
       public:
         explicit AutoDelazify(JSContext* cx, JS::HandleFunction fun = nullptr)
             : script_(cx)
             , cx_(cx)
+            , oldDoNotRelazify_(false)
         {
             holdScript(fun);
         }
 
         ~AutoDelazify()
         {
             dropScript();
         }
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -76,34 +76,36 @@ InefficientNonFlatteningStringHashPolicy
 template <typename Char1, typename Char2>
 static bool
 EqualStringsPure(JSString* s1, JSString* s2)
 {
     if (s1->length() != s2->length())
         return false;
 
     const Char1* c1;
-    ScopedJSFreePtr<Char1> ownedChars1;
+    UniquePtr<Char1[], JS::FreePolicy> ownedChars1;
     JS::AutoCheckCannotGC nogc;
     if (s1->isLinear()) {
         c1 = s1->asLinear().chars<Char1>(nogc);
     } else {
-        if (!s1->asRope().copyChars<Char1>(/* tcx */ nullptr, ownedChars1))
+        ownedChars1 = s1->asRope().copyChars<Char1>(/* tcx */ nullptr);
+        if (!ownedChars1)
             MOZ_CRASH("oom");
-        c1 = ownedChars1;
+        c1 = ownedChars1.get();
     }
 
     const Char2* c2;
-    ScopedJSFreePtr<Char2> ownedChars2;
+    UniquePtr<Char2[], JS::FreePolicy> ownedChars2;
     if (s2->isLinear()) {
         c2 = s2->asLinear().chars<Char2>(nogc);
     } else {
-        if (!s2->asRope().copyChars<Char2>(/* tcx */ nullptr, ownedChars2))
+        ownedChars2 = s2->asRope().copyChars<Char2>(/* tcx */ nullptr);
+        if (!ownedChars2)
             MOZ_CRASH("oom");
-        c2 = ownedChars2;
+        c2 = ownedChars2.get();
     }
 
     return EqualChars(c1, c2, s1->length());
 }
 
 /* static */ bool
 InefficientNonFlatteningStringHashPolicy::match(const JSString* const& k, const Lookup& l)
 {
@@ -143,24 +145,25 @@ NotableStringInfo::NotableStringInfo()
 {
 }
 
 template <typename CharT>
 static void
 StoreStringChars(char* buffer, size_t bufferSize, JSString* str)
 {
     const CharT* chars;
-    ScopedJSFreePtr<CharT> ownedChars;
+    UniquePtr<CharT[], JS::FreePolicy> ownedChars;
     JS::AutoCheckCannotGC nogc;
     if (str->isLinear()) {
         chars = str->asLinear().chars<CharT>(nogc);
     } else {
-        if (!str->asRope().copyChars<CharT>(/* tcx */ nullptr, ownedChars))
+        ownedChars = str->asRope().copyChars<CharT>(/* tcx */ nullptr);
+        if (!ownedChars)
             MOZ_CRASH("oom");
-        chars = ownedChars;
+        chars = ownedChars.get();
     }
 
     // We might truncate |str| even if it's much shorter than 1024 chars, if
     // |str| contains unicode chars.  Since this is just for a memory reporter,
     // we don't care.
     PutEscapedString(buffer, bufferSize, chars, str->length(), /* quote */ 0);
 }
 
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -2,26 +2,28 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/ObjectGroup.h"
 
 #include "mozilla/Maybe.h"
+#include "mozilla/Unused.h"
 
 #include "jsexn.h"
 
 #include "builtin/DataViewObject.h"
 #include "gc/FreeOp.h"
 #include "gc/HashUtil.h"
 #include "gc/Policy.h"
 #include "gc/StoreBuffer.h"
 #include "gc/Zone.h"
 #include "js/CharacterEncoding.h"
+#include "js/UniquePtr.h"
 #include "vm/ArrayObject.h"
 #include "vm/JSObject.h"
 #include "vm/RegExpObject.h"
 #include "vm/Shape.h"
 #include "vm/TaggedProto.h"
 
 #include "gc/Marking-inl.h"
 #include "vm/UnboxedObject-inl.h"
@@ -1225,53 +1227,53 @@ ObjectGroup::newPlainObject(JSContext* c
         // will try to use an unboxed layout for the group.
         PreliminaryObjectArrayWithTemplate* preliminaryObjects =
             cx->new_<PreliminaryObjectArrayWithTemplate>(obj->lastProperty());
         if (!preliminaryObjects)
             return nullptr;
         group->setPreliminaryObjects(preliminaryObjects);
         preliminaryObjects->registerNewObject(obj);
 
-        ScopedJSFreePtr<jsid> ids(group->zone()->pod_calloc<jsid>(nproperties));
+        UniquePtr<jsid[], JS::FreePolicy> ids(group->zone()->pod_calloc<jsid>(nproperties));
         if (!ids) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
 
-        ScopedJSFreePtr<TypeSet::Type> types(
+        UniquePtr<TypeSet::Type[], JS::FreePolicy> types(
             group->zone()->pod_calloc<TypeSet::Type>(nproperties));
         if (!types) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
 
         for (size_t i = 0; i < nproperties; i++) {
             ids[i] = properties[i].id;
             types[i] = GetValueTypeForTable(obj->getSlot(i));
             AddTypePropertyId(cx, group, nullptr, IdToTypeId(ids[i]), types[i]);
         }
 
         ObjectGroupRealm::PlainObjectKey key;
-        key.properties = ids;
+        key.properties = ids.get();
         key.nproperties = nproperties;
         MOZ_ASSERT(ObjectGroupRealm::PlainObjectKey::match(key, lookup));
 
         ObjectGroupRealm::PlainObjectEntry entry;
         entry.group.set(group);
         entry.shape.set(obj->lastProperty());
-        entry.types = types;
+        entry.types = types.get();
 
         ObjectGroupRealm::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup);
         if (!table->add(np, key, entry)) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
 
-        ids.forget();
-        types.forget();
+        mozilla::Unused << ids.release();
+        mozilla::Unused << types.release();
 
         return obj;
     }
 
     RootedObjectGroup group(cx, p->value().group);
 
     // AutoSweepObjectGroup checks no GC happens in its scope, so we use Maybe
     // and reset() it before GC calls.
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -623,17 +623,21 @@ class ObjectGroupRealm
 
     // This cache is purged on GC.
     class DefaultNewGroupCache
     {
         ObjectGroup* group_;
         JSObject* associated_;
 
       public:
-        DefaultNewGroupCache() { purge(); }
+        DefaultNewGroupCache()
+          : associated_(nullptr)
+        {
+            purge();
+        }
 
         void purge() {
             group_ = nullptr;
         }
         void put(ObjectGroup* group, JSObject* associated) {
             group_ = group;
             associated_ = associated;
         }
--- a/js/src/vm/RegExpShared.h
+++ b/js/src/vm/RegExpShared.h
@@ -229,17 +229,19 @@ class RegExpShared : public gc::TenuredC
 };
 
 class RegExpZone
 {
     struct Key {
         JSAtom* atom;
         uint16_t flag;
 
-        Key() {}
+        Key()
+          : atom(nullptr), flag(0)
+        { }
         Key(JSAtom* atom, RegExpFlag flag)
           : atom(atom), flag(flag)
         { }
         MOZ_IMPLICIT Key(const ReadBarriered<RegExpShared*>& shared)
           : atom(shared.unbarrieredGet()->getSource()),
             flag(shared.unbarrieredGet()->getFlags())
         { }
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2950,24 +2950,24 @@ JSRuntime::initSelfHosting(JSContext* cx
     FillSelfHostingCompileOptions(options);
 
     RootedValue rv(cx);
 
     uint32_t srcLen = GetRawScriptsSize();
 
     const unsigned char* compressed = compressedSources;
     uint32_t compressedLen = GetCompressedSize();
-    ScopedJSFreePtr<char> src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
+    UniqueChars src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
     if (!src || !DecompressString(compressed, compressedLen,
                                   reinterpret_cast<unsigned char*>(src.get()), srcLen))
     {
         return false;
     }
 
-    if (!Evaluate(cx, options, src, srcLen, &rv))
+    if (!Evaluate(cx, options, src.get(), srcLen, &rv))
         return false;
 
     if (!VerifyGlobalNames(cx, shg))
         return false;
 
     return true;
 }
 
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1519,17 +1519,18 @@ class MutableWrappedPtrOperations<StackS
 
 inline
 Shape::Shape(const StackShape& other, uint32_t nfixed)
   : base_(other.base),
     propid_(other.propid),
     immutableFlags(other.immutableFlags),
     attrs(other.attrs),
     mutableFlags(other.mutableFlags),
-    parent(nullptr)
+    parent(nullptr),
+    listp(nullptr)
 {
     setNumFixedSlots(nfixed);
 
 #ifdef DEBUG
     gc::AllocKind allocKind = getAllocKind();
     MOZ_ASSERT_IF(other.isAccessorShape(), allocKind == gc::AllocKind::ACCESSOR_SHAPE);
     MOZ_ASSERT_IF(allocKind == gc::AllocKind::SHAPE, !other.isAccessorShape());
 #endif
@@ -1553,17 +1554,18 @@ class NurseryShapesRef : public gc::Buff
 
 inline
 Shape::Shape(UnownedBaseShape* base, uint32_t nfixed)
   : base_(base),
     propid_(JSID_EMPTY),
     immutableFlags(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
     attrs(0),
     mutableFlags(0),
-    parent(nullptr)
+    parent(nullptr),
+    listp(nullptr)
 {
     MOZ_ASSERT(base);
     kids.setNull();
 }
 
 inline GetterOp
 Shape::getter() const
 {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1666,17 +1666,17 @@ class JitActivation : public Activation
     mozilla::Maybe<wasm::TrapData> wasmTrapData_;
 
     void clearRematerializedFrames();
 
 #ifdef CHECK_OSIPOINT_REGISTERS
   protected:
     // Used to verify that live registers don't change between a VM call and
     // the OsiPoint that follows it. Protected to silence Clang warning.
-    uint32_t checkRegs_;
+    uint32_t checkRegs_ = 0;
     RegisterDump regs_;
 #endif
 
   public:
     explicit JitActivation(JSContext* cx);
     ~JitActivation();
 
     bool isProfiling() const {
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -274,81 +274,82 @@ AllocChars(JSString* str, size_t length,
     /* Like length, capacity does not include the null char, so take it out. */
     *capacity = numChars - 1;
 
     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
     *chars = str->zone()->pod_malloc<CharT>(numChars);
     return *chars != nullptr;
 }
 
-bool
-JSRope::copyLatin1CharsZ(JSContext* cx, ScopedJSFreePtr<Latin1Char>& out) const
+UniquePtr<Latin1Char[], JS::FreePolicy>
+JSRope::copyLatin1CharsZ(JSContext* cx) const
 {
-    return copyCharsInternal<Latin1Char>(cx, out, true);
+    return copyCharsInternal<Latin1Char>(cx, true);
 }
 
-bool
-JSRope::copyTwoByteCharsZ(JSContext* cx, ScopedJSFreePtr<char16_t>& out) const
+UniqueTwoByteChars
+JSRope::copyTwoByteCharsZ(JSContext* cx) const
 {
-    return copyCharsInternal<char16_t>(cx, out, true);
+    return copyCharsInternal<char16_t>(cx, true);
 }
 
-bool
-JSRope::copyLatin1Chars(JSContext* cx, ScopedJSFreePtr<Latin1Char>& out) const
+UniquePtr<Latin1Char[], JS::FreePolicy>
+JSRope::copyLatin1Chars(JSContext* cx) const
 {
-    return copyCharsInternal<Latin1Char>(cx, out, false);
+    return copyCharsInternal<Latin1Char>(cx, false);
 }
 
-bool
-JSRope::copyTwoByteChars(JSContext* cx, ScopedJSFreePtr<char16_t>& out) const
+UniqueTwoByteChars
+JSRope::copyTwoByteChars(JSContext* cx) const
 {
-    return copyCharsInternal<char16_t>(cx, out, false);
+    return copyCharsInternal<char16_t>(cx, false);
 }
 
 template <typename CharT>
-bool
-JSRope::copyCharsInternal(JSContext* cx, ScopedJSFreePtr<CharT>& out,
-                          bool nullTerminate) const
+UniquePtr<CharT[], JS::FreePolicy>
+JSRope::copyCharsInternal(JSContext* cx, bool nullTerminate) const
 {
     // Left-leaning ropes are far more common than right-leaning ropes, so
     // perform a non-destructive traversal of the rope, right node first,
     // splatting each node's characters into a contiguous buffer.
 
     size_t n = length();
+
+    UniquePtr<CharT[], JS::FreePolicy> out;
     if (cx)
         out.reset(cx->pod_malloc<CharT>(n + 1));
     else
         out.reset(js_pod_malloc<CharT>(n + 1));
 
     if (!out)
-        return false;
+        return nullptr;
 
     Vector<const JSString*, 8, SystemAllocPolicy> nodeStack;
     const JSString* str = this;
-    CharT* end = out + str->length();
+    CharT* end = out.get() + str->length();
     while (true) {
         if (str->isRope()) {
             if (!nodeStack.append(str->asRope().leftChild()))
-                return false;
+                return nullptr;
             str = str->asRope().rightChild();
         } else {
             end -= str->length();
             CopyChars(end, str->asLinear());
             if (nodeStack.empty())
                 break;
             str = nodeStack.popCopy();
         }
     }
 
-    MOZ_ASSERT(end == out);
+    MOZ_ASSERT(end == out.get());
 
     if (nullTerminate)
         out[n] = 0;
 
-    return true;
+    return out;
 }
 
 template <typename CharT>
 void AddStringToHash(uint32_t* hash, const CharT* chars, size_t len)
 {
     // It's tempting to use |HashString| instead of this loop, but that's
     // slightly different than our existing implementation for non-ropes. We
     // want to pretend we have a contiguous set of chars so we need to
@@ -1497,31 +1498,31 @@ static JSFlatString*
 NewStringDeflated(JSContext* cx, const char16_t* s, size_t n)
 {
     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
         return str;
 
     if (JSInlineString::lengthFits<Latin1Char>(n))
         return NewInlineStringDeflated<allowGC>(cx, mozilla::Range<const char16_t>(s, n));
 
-    ScopedJSFreePtr<Latin1Char> news(cx->pod_malloc<Latin1Char>(n + 1));
+    UniquePtr<Latin1Char[], JS::FreePolicy> news(cx->pod_malloc<Latin1Char>(n + 1));
     if (!news)
         return nullptr;
 
     for (size_t i = 0; i < n; i++) {
         MOZ_ASSERT(s[i] <= JSString::MAX_LATIN1_CHAR);
-        news.get()[i] = Latin1Char(s[i]);
+        news[i] = Latin1Char(s[i]);
     }
     news[n] = '\0';
 
     JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
     if (!str)
         return nullptr;
 
-    news.forget();
+    mozilla::Unused << news.release();
     return str;
 }
 
 template <AllowGC allowGC>
 static JSFlatString*
 NewStringDeflated(JSContext* cx, const Latin1Char* s, size_t n)
 {
     MOZ_CRASH("Shouldn't be called for Latin1 chars");
@@ -1599,31 +1600,31 @@ JSFlatString*
 NewStringCopyNDontDeflate(JSContext* cx, const CharT* s, size_t n)
 {
     if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
         return str;
 
     if (JSInlineString::lengthFits<CharT>(n))
         return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
 
-    ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
+    UniquePtr<CharT[], JS::FreePolicy> news(cx->pod_malloc<CharT>(n + 1));
     if (!news) {
         if (!allowGC)
             cx->recoverFromOutOfMemory();
         return nullptr;
     }
 
     PodCopy(news.get(), s, n);
     news[n] = 0;
 
     JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
     if (!str)
         return nullptr;
 
-    news.forget();
+    mozilla::Unused << news.release();
     return str;
 }
 
 template JSFlatString*
 NewStringCopyNDontDeflate<CanGC>(JSContext* cx, const char16_t* s, size_t n);
 
 template JSFlatString*
 NewStringCopyNDontDeflate<NoGC>(JSContext* cx, const char16_t* s, size_t n);
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -17,16 +17,17 @@
 #include "builtin/String.h"
 #include "gc/Barrier.h"
 #include "gc/Cell.h"
 #include "gc/Heap.h"
 #include "gc/Nursery.h"
 #include "gc/Rooting.h"
 #include "js/CharacterEncoding.h"
 #include "js/RootingAPI.h"
+#include "js/UniquePtr.h"
 #include "util/Text.h"
 #include "vm/Printer.h"
 
 class JSDependentString;
 class JSExtensibleString;
 class JSExternalString;
 class JSInlineString;
 class JSRope;
@@ -661,18 +662,18 @@ class JSString : public js::gc::Cell
     JSString() = delete;
     JSString(const JSString& other) = delete;
     void operator=(const JSString& other) = delete;
 };
 
 class JSRope : public JSString
 {
     template <typename CharT>
-    bool copyCharsInternal(JSContext* cx, js::ScopedJSFreePtr<CharT>& out,
-                           bool nullTerminate) const;
+    js::UniquePtr<CharT[], JS::FreePolicy> copyCharsInternal(JSContext* cx,
+                                                             bool nullTerminate) const;
 
     enum UsingBarrier { WithIncrementalBarrier, NoBarrier };
 
     template<UsingBarrier b, typename CharT>
     JSFlatString* flattenInternal(JSContext* cx);
 
     template<UsingBarrier b>
     JSFlatString* flattenInternal(JSContext* cx);
@@ -684,26 +685,24 @@ class JSRope : public JSString
 
   public:
     template <js::AllowGC allowGC>
     static inline JSRope* new_(JSContext* cx,
                                typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
                                typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
                                size_t length, js::gc::InitialHeap = js::gc::DefaultHeap);
 
-    bool copyLatin1Chars(JSContext* cx,
-                         js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
-    bool copyTwoByteChars(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
+    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1Chars(JSContext* cx) const;
+    JS::UniqueTwoByteChars copyTwoByteChars(JSContext* cx) const;
 
-    bool copyLatin1CharsZ(JSContext* cx,
-                          js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
-    bool copyTwoByteCharsZ(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
+    js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> copyLatin1CharsZ(JSContext* cx) const;
+    JS::UniqueTwoByteChars copyTwoByteCharsZ(JSContext* cx) const;
 
     template <typename CharT>
-    bool copyChars(JSContext* cx, js::ScopedJSFreePtr<CharT>& out) const;
+    js::UniquePtr<CharT[], JS::FreePolicy> copyChars(JSContext* cx) const;
 
     // Hash function specific for ropes that avoids allocating a temporary
     // string. There are still allocations internally so it's technically
     // fallible.
     //
     // Returns the same value as if this were a linear string being hashed.
     MOZ_MUST_USE bool hash(uint32_t* outhHash) const;
 
@@ -1729,28 +1728,27 @@ JSLinearString::chars(const JS::AutoRequ
 template<>
 MOZ_ALWAYS_INLINE const JS::Latin1Char*
 JSLinearString::chars(const JS::AutoRequireNoGC& nogc) const
 {
     return rawLatin1Chars();
 }
 
 template <>
-MOZ_ALWAYS_INLINE bool
-JSRope::copyChars<JS::Latin1Char>(JSContext* cx,
-                                  js::ScopedJSFreePtr<JS::Latin1Char>& out) const
+MOZ_ALWAYS_INLINE js::UniquePtr<JS::Latin1Char[], JS::FreePolicy>
+JSRope::copyChars<JS::Latin1Char>(JSContext* cx) const
 {
-    return copyLatin1Chars(cx, out);
+    return copyLatin1Chars(cx);
 }
 
 template <>
-MOZ_ALWAYS_INLINE bool
-JSRope::copyChars<char16_t>(JSContext* cx, js::ScopedJSFreePtr<char16_t>& out) const
+MOZ_ALWAYS_INLINE JS::UniqueTwoByteChars
+JSRope::copyChars<char16_t>(JSContext* cx) const
 {
-    return copyTwoByteChars(cx, out);
+    return copyTwoByteChars(cx);
 }
 
 template<>
 MOZ_ALWAYS_INLINE bool
 JSThinInlineString::lengthFits<JS::Latin1Char>(size_t length)
 {
     return length <= MAX_LENGTH_LATIN1;
 }
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -570,32 +570,34 @@ class MOZ_RAII AutoTraceLog
     bool executed;
     AutoTraceLog* prev;
 
   public:
     AutoTraceLog(TraceLoggerThread* logger,
                  const TraceLoggerEvent& event MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : logger(logger),
         isEvent(true),
-        executed(false)
+        executed(false),
+        prev(nullptr)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         payload.event = &event;
         if (logger) {
             logger->startEvent(event);
 
             prev = logger->top;
             logger->top = this;
         }
     }
 
     AutoTraceLog(TraceLoggerThread* logger, TraceLoggerTextId id MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : logger(logger),
         isEvent(false),
-        executed(false)
+        executed(false),
+        prev(nullptr)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         payload.id = id;
         if (logger) {
             logger->startEvent(id);
 
             prev = logger->top;
             logger->top = this;
--- a/js/src/vm/TraceLoggingGraph.h
+++ b/js/src/vm/TraceLoggingGraph.h
@@ -125,16 +125,20 @@ class TraceLoggerGraph
         {
             start_ = start;
             stop_ = stop;
             u.s.textId_ = textId;
             u.s.hasChildren_ = hasChildren;
             nextId_ = nextId;
         }
         TreeEntry()
+          : start_(0),
+            stop_(0),
+            u{},
+            nextId_(0)
         { }
         uint64_t start() {
             return start_;
         }
         uint64_t stop() {
             return stop_;
         }
         uint32_t textId() {
--- a/js/src/vm/TraceLoggingTypes.h
+++ b/js/src/vm/TraceLoggingTypes.h
@@ -157,17 +157,19 @@ class ContinuousSpace {
     uint32_t size_;
     uint32_t capacity_;
 
     // The maximum number of bytes of RAM a continuous space structure can take.
     static const uint32_t LIMIT = 200 * 1024 * 1024;
 
   public:
     ContinuousSpace ()
-     : data_(nullptr)
+     : data_(nullptr),
+       size_(0),
+       capacity_(0)
     { }
 
     bool init() {
         capacity_ = 64;
         size_ = 0;
         data_ = (T*) js_malloc(capacity_ * sizeof(T));
         if (!data_)
             return false;
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -21,16 +21,17 @@
 #include "gc/HashUtil.h"
 #include "jit/BaselineJIT.h"
 #include "jit/CompileInfo.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/JitRealm.h"
 #include "jit/OptimizationTracking.h"
 #include "js/MemoryMetrics.h"
+#include "js/UniquePtr.h"
 #include "vm/HelperThreads.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Opcodes.h"
 #include "vm/Printer.h"
 #include "vm/Shape.h"
 #include "vm/Time.h"
@@ -3636,17 +3637,17 @@ PreliminaryObjectArrayWithTemplate::mayb
 {
     // Don't perform the analyses until sufficient preliminary objects have
     // been allocated.
     if (!force && !full())
         return;
 
     AutoEnterAnalysis enter(cx);
 
-    ScopedJSDeletePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
+    UniquePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
     group->detachPreliminaryObjects();
 
     MOZ_ASSERT(shape());
     MOZ_ASSERT(shape()->slotSpan() != 0);
     MOZ_ASSERT(OnlyHasDataProperties(shape()));
 
     // Make sure all the preliminary objects reflect the properties originally
     // in the template object.
@@ -3658,17 +3659,17 @@ PreliminaryObjectArrayWithTemplate::mayb
 
         if (obj->inDictionaryMode() || !OnlyHasDataProperties(obj->lastProperty()))
             return;
 
         if (CommonPrefix(obj->lastProperty(), shape()) != shape())
             return;
     }
 
-    TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects);
+    TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects.get());
     AutoSweepObjectGroup sweep(group);
     if (group->maybeUnboxedLayout(sweep))
         return;
 
     // We weren't able to use an unboxed layout, but since the preliminary
     // objects still reflect the template object's properties, and all
     // objects in the future will be created with those properties, the
     // properties can be marked as definite for objects in the group.
@@ -3687,41 +3688,41 @@ TypeNewScript::make(JSContext* cx, Objec
     AutoSweepObjectGroup sweep(group);
     MOZ_ASSERT(cx->zone()->types.activeAnalysis);
     MOZ_ASSERT(!group->newScript(sweep));
     MOZ_ASSERT(!group->maybeUnboxedLayout(sweep));
 
     if (group->unknownProperties(sweep))
         return true;
 
-    ScopedJSDeletePtr<TypeNewScript> newScript(cx->new_<TypeNewScript>());
+    auto newScript = cx->make_unique<TypeNewScript>();
     if (!newScript)
         return false;
 
     newScript->function_ = fun;
 
     newScript->preliminaryObjects = group->zone()->new_<PreliminaryObjectArray>();
     if (!newScript->preliminaryObjects)
         return true;
 
-    group->setNewScript(newScript.forget());
+    group->setNewScript(newScript.release());
 
     gc::gcTracer.traceTypeNewScript(group);
     return true;
 }
 
 // Make a TypeNewScript with the same initializer list as |newScript| but with
 // a new template object.
 /* static */ TypeNewScript*
 TypeNewScript::makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
                                  PlainObject* templateObject)
 {
     MOZ_RELEASE_ASSERT(cx->zone()->types.activeAnalysis);
 
-    ScopedJSDeletePtr<TypeNewScript> nativeNewScript(cx->new_<TypeNewScript>());
+    auto nativeNewScript = cx->make_unique<TypeNewScript>();
     if (!nativeNewScript)
         return nullptr;
 
     nativeNewScript->function_ = newScript->function();
     nativeNewScript->templateObject_ = templateObject;
 
     Initializer* cursor = newScript->initializerList;
     while (cursor->kind != Initializer::DONE) { cursor++; }
@@ -3729,17 +3730,17 @@ TypeNewScript::makeNativeVersion(JSConte
 
     nativeNewScript->initializerList = cx->zone()->pod_calloc<Initializer>(initializerLength);
     if (!nativeNewScript->initializerList) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
     PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
 
-    return nativeNewScript.forget();
+    return nativeNewScript.release();
 }
 
 size_t
 TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
     size_t n = mallocSizeOf(this);
     n += mallocSizeOf(preliminaryObjects);
     n += mallocSizeOf(initializerList);
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -25,16 +25,17 @@
 
 #include "builtin/Array.h"
 #include "builtin/DataViewObject.h"
 #include "builtin/TypedObjectConstants.h"
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
 #include "jit/InlinableNatives.h"
 #include "js/Conversions.h"
+#include "js/UniquePtr.h"
 #include "js/Wrapper.h"
 #include "util/Windows.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/PIC.h"
@@ -647,33 +648,31 @@ class TypedArrayObjectTemplate : public 
                                   ? GetGCObjectKind(clasp)
                                   : AllocKindForLazyBuffer(nbytes);
         MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
         allocKind = GetBackgroundAllocKind(allocKind);
         RootedObjectGroup group(cx, templateObj->group());
 
         NewObjectKind newKind = TenuredObject;
 
-        ScopedJSFreePtr<void> buf;
+        UniquePtr<void, JS::FreePolicy> buf;
         if (!fitsInline && len > 0) {
-            buf = cx->zone()->pod_malloc<uint8_t>(nbytes);
+            buf.reset(cx->zone()->pod_calloc<uint8_t>(nbytes));
             if (!buf) {
                 ReportOutOfMemory(cx);
                 return nullptr;
             }
-
-            memset(buf, 0, nbytes);
         }
 
         TypedArrayObject* obj = NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind);
         if (!obj)
             return nullptr;
 
         initTypedArraySlots(obj, len);
-        initTypedArrayData(cx, obj, len, buf.forget(), allocKind);
+        initTypedArrayData(cx, obj, len, buf.release(), allocKind);
 
         return obj;
     }
 
     // ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
     // 22.2.4.1 TypedArray ( )
     // 22.2.4.2 TypedArray ( length )
     // 22.2.4.3 TypedArray ( typedArray )
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -333,16 +333,17 @@ struct js::AsmJSMetadata : Metadata, Asm
     }
     uint32_t srcEndAfterCurly() const {
         return srcStart + srcLengthWithRightBrace;
     }
 
     AsmJSMetadata()
       : Metadata(ModuleKind::AsmJS),
         cacheResult(CacheResult::Miss),
+        toStringStart(0),
         srcStart(0),
         strict(false)
     {}
     ~AsmJSMetadata() override {}
 
     const AsmJSExport& lookupAsmJSExport(uint32_t funcIndex) const {
         // The AsmJSExportVector isn't stored in sorted order so do a linear
         // search. This is for the super-cold and already-expensive toString()
@@ -1519,17 +1520,17 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED Modu
                 SimdType type_;
                 SimdOperation which_;
             } simdOp;
 
             // |varOrConst|, through |varOrConst.literalValue_|, has a
             // non-trivial constructor and therefore MUST be placement-new'd
             // into existence.
             MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
-            U() {}
+            U() : funcDefIndex_(0) {}
             MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
         } u;
 
         friend class ModuleValidator;
         friend class js::LifoAlloc;
 
         explicit Global(Which which) : which_(which) {}
 
@@ -1610,17 +1611,17 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED Modu
         enum Kind { Function, Constant };
         Kind kind;
 
         union {
             double cst;
             AsmJSMathBuiltinFunction func;
         } u;
 
-        MathBuiltin() : kind(Kind(-1)) {}
+        MathBuiltin() : kind(Kind(-1)), u{} {}
         explicit MathBuiltin(double cst) : kind(Constant) {
             u.cst = cst;
         }
         explicit MathBuiltin(AsmJSMathBuiltinFunction func) : kind(Function) {
             u.func = func;
         }
     };
 
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -1005,16 +1005,18 @@ using ScratchI8 = ScratchI32;
 BaseLocalIter::BaseLocalIter(const ValTypeVector& locals, size_t argsLength, bool debugEnabled)
   : locals_(locals),
     argsLength_(argsLength),
     argsRange_(locals.begin(), argsLength),
     argsIter_(argsRange_),
     index_(0),
     localSize_(debugEnabled ? DebugFrame::offsetOfFrame() : 0),
     reservedSize_(localSize_),
+    frameOffset_(0),
+    mirType_(MIRType::Undefined),
     done_(false)
 {
     MOZ_ASSERT(argsLength <= locals.length());
     settle();
 }
 
 int32_t
 BaseLocalIter::pushLocal(size_t nbytes)
--- a/js/src/wasm/WasmFrameIter.cpp
+++ b/js/src/wasm/WasmFrameIter.cpp
@@ -35,17 +35,18 @@ using mozilla::Maybe;
 
 WasmFrameIter::WasmFrameIter(JitActivation* activation, wasm::Frame* fp)
   : activation_(activation),
     code_(nullptr),
     codeRange_(nullptr),
     lineOrBytecode_(0),
     fp_(fp ? fp : activation->wasmExitFP()),
     unwoundIonCallerFP_(nullptr),
-    unwind_(Unwind::False)
+    unwind_(Unwind::False),
+    unwoundAddressOfReturnAddress_(nullptr)
 {
     MOZ_ASSERT(fp_);
 
     // When the stack is captured during a trap (viz., to create the .stack
     // for an Error object), use the pc/bytecode information captured by the
     // signal handler in the runtime.
 
     if (activation->isWasmTrapping()) {
--- a/js/src/wasm/WasmFrameIter.h
+++ b/js/src/wasm/WasmFrameIter.h
@@ -94,32 +94,35 @@ class WasmFrameIter
 enum class SymbolicAddress;
 
 // An ExitReason describes the possible reasons for leaving compiled wasm
 // code or the state of not having left compiled wasm code
 // (ExitReason::None). It is either a known reason, or a enumeration to a native
 // function that is used for better display in the profiler.
 class ExitReason
 {
-    uint32_t payload_;
-
-    ExitReason() {}
-
   public:
     enum class Fixed : uint32_t
     {
         None,            // default state, the pc is in wasm code
         FakeInterpEntry, // slow-path entry call from C++ WasmCall()
         ImportJit,       // fast-path call directly into JIT code
         ImportInterp,    // slow-path call into C++ Invoke()
         BuiltinNative,   // fast-path call directly into native C++ code
         Trap,            // call to trap handler
         DebugTrap        // call to debug trap handler
     };
 
+  private:
+    uint32_t payload_;
+
+    ExitReason() : ExitReason(Fixed::None) {}
+
+  public:
+
     MOZ_IMPLICIT ExitReason(Fixed exitReason)
       : payload_(0x0 | (uint32_t(exitReason) << 1))
     {
         MOZ_ASSERT(isFixed());
         MOZ_ASSERT_IF(isNone(), payload_ == 0);
     }
 
     explicit ExitReason(SymbolicAddress sym)
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -2887,16 +2887,17 @@ class CompileStreamTask : public Promise
     CompileStreamTask(JSContext* cx, Handle<PromiseObject*> promise,
                       CompileArgs& compileArgs, bool instantiate,
                       HandleObject importObj)
       : PromiseHelperTask(cx, promise),
         compileArgs_(&compileArgs),
         instantiate_(instantiate),
         importObj_(cx, importObj),
         streamState_(mutexid::WasmStreamStatus, Env),
+        codeSection_{},
         codeStreamEnd_(nullptr),
         exclusiveCodeStreamEnd_(mutexid::WasmCodeStreamEnd, nullptr),
         exclusiveTailBytes_(mutexid::WasmTailBytesPtr, nullptr),
         streamFailed_(false)
     {
         MOZ_ASSERT_IF(importObj_, instantiate_);
     }
 };
--- a/js/src/wasm/WasmOpIter.h
+++ b/js/src/wasm/WasmOpIter.h
@@ -233,16 +233,18 @@ Classify(OpBytes op);
 template <typename Value>
 struct LinearMemoryAddress
 {
     Value base;
     uint32_t offset;
     uint32_t align;
 
     LinearMemoryAddress()
+      : offset(0),
+        align(0)
     {}
     LinearMemoryAddress(Value base, uint32_t offset, uint32_t align)
       : base(base), offset(offset), align(align)
     {}
 };
 
 template <typename ControlItem>
 class ControlStackEntry
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -164,17 +164,18 @@ class WasmToken
       : kind_(Kind::Invalid),
         begin_(nullptr),
         end_(nullptr),
         u()
     { }
     WasmToken(Kind kind, const char16_t* begin, const char16_t* end)
       : kind_(kind),
         begin_(begin),
-        end_(end)
+        end_(end),
+        u{}
     {
         MOZ_ASSERT(kind_ != Error);
         MOZ_ASSERT(kind_ != Invalid);
         MOZ_ASSERT((kind == EndOfFile) == (begin == end));
     }
     explicit WasmToken(uint32_t index, const char16_t* begin, const char16_t* end)
       : kind_(Index),
         begin_(begin),
@@ -247,17 +248,18 @@ class WasmToken
         MOZ_ASSERT(begin != end);
         MOZ_ASSERT(kind_ == AtomicCmpXchg || kind_ == AtomicLoad || kind_ == AtomicRMW ||
                    kind_ == AtomicStore || kind_ == Wait || kind_ == Wake);
         u.threadOp_ = op;
     }
     explicit WasmToken(const char16_t* begin)
       : kind_(Error),
         begin_(begin),
-        end_(begin)
+        end_(begin),
+        u{}
     {}
     Kind kind() const {
         MOZ_ASSERT(kind_ != Kind::Invalid);
         return kind_;
     }
     const char16_t* begin() const {
         return begin_;
     }
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -792,17 +792,17 @@ class InitExpr
   private:
     Kind kind_;
     union U {
         Val val_;
         struct {
             uint32_t index_;
             ValType type_;
         } global;
-        U() {}
+        U() : global{} {}
     } u;
 
   public:
     InitExpr() = default;
 
     explicit InitExpr(Val val) : kind_(Kind::Constant) {
         u.val_ = val;
     }
@@ -915,17 +915,17 @@ class GlobalDesc
     union V {
         struct {
             union U {
                 InitExpr initial_;
                 struct {
                     ValType type_;
                     uint32_t index_;
                 } import;
-                U() {}
+                U() : import{} {}
             } val;
             unsigned offset_;
             bool isMutable_;
             bool isWasm_;
             bool isExport_;
         } var;
         Val cst_;
         V() {}
@@ -1595,17 +1595,20 @@ class CallSiteDesc
     enum Kind {
         Func,       // pc-relative call to a specific function
         Dynamic,    // dynamic callee called via register
         Symbolic,   // call to a single symbolic callee
         EnterFrame, // call to a enter frame handler
         LeaveFrame, // call to a leave frame handler
         Breakpoint  // call to instruction breakpoint
     };
-    CallSiteDesc() {}
+    CallSiteDesc()
+      : lineOrBytecode_(0),
+        kind_(0)
+    {}
     explicit CallSiteDesc(Kind kind)
       : lineOrBytecode_(0), kind_(kind)
     {
         MOZ_ASSERT(kind == Kind(kind_));
     }
     CallSiteDesc(uint32_t lineOrBytecode, Kind kind)
       : lineOrBytecode_(lineOrBytecode), kind_(kind)
     {
@@ -1616,17 +1619,17 @@ class CallSiteDesc
     Kind kind() const { return Kind(kind_); }
 };
 
 class CallSite : public CallSiteDesc
 {
     uint32_t returnAddressOffset_;
 
   public:
-    CallSite() {}
+    CallSite() : returnAddressOffset_(0) {}
 
     CallSite(CallSiteDesc desc, uint32_t returnAddressOffset)
       : CallSiteDesc(desc),
         returnAddressOffset_(returnAddressOffset)
     { }
 
     void offsetBy(int32_t delta) { returnAddressOffset_ += delta; }
     uint32_t returnAddressOffset() const { return returnAddressOffset_; }
@@ -1994,17 +1997,17 @@ class CalleeDesc
         // Like Builtin, but automatically passes Instance* as first argument.
         BuiltinInstanceMethod
     };
 
   private:
     // which_ shall be initialized in the static constructors
     MOZ_INIT_OUTSIDE_CTOR Which which_;
     union U {
-        U() {}
+        U() : funcIndex_(0) {}
         uint32_t funcIndex_;
         struct {
             uint32_t globalDataOffset_;
         } import;
         struct {
             uint32_t globalDataOffset_;
             uint32_t minLength_;
             bool external_;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2460,25 +2460,23 @@ nsDocumentViewer::CreateStyleSet(nsIDocu
     styleSet->PrependStyleSheet(SheetType::Agent, sheet);
   }
 
   sheet = cache->FormsSheet();
   if (sheet) {
     styleSet->PrependStyleSheet(SheetType::Agent, sheet);
   }
 
+  // This is the only place components.css / xul.css get loaded.
   if (aDocument->LoadsFullXULStyleSheetUpFront()) {
-    // This is the only place components.css gets loaded, unlike xul.css
     sheet = cache->XULComponentsSheet();
     if (sheet) {
       styleSet->PrependStyleSheet(SheetType::Agent, sheet);
     }
 
-    // nsXULElement::BindToTree loads xul.css on-demand if we don't load it
-    // up-front here.
     sheet = cache->XULSheet();
     if (sheet) {
       styleSet->PrependStyleSheet(SheetType::Agent, sheet);
     }
   }
 
   sheet = cache->MinimalXULSheet();
   if (sheet) {
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -751,18 +751,18 @@ nsLayoutStylesheetCache::LoadSheet(nsIUR
       ErrorLoadingSheet(aURI, "no Loader", eCrash);
       return;
     }
   }
 
   nsZipArchive::sFileCorruptedReason = nullptr;
 
   // Note: The parallel parsing code assume that UA sheets are always loaded
-  // synchrously like they are here, and thus that we'll never attempt parallel
-  // parsing on them. If that ever changes, we'll either need to find a
+  // synchronously like they are here, and thus that we'll never attempt
+  // parallel parsing on them. If that ever changes, we'll either need to find a
   // different way to prohibit parallel parsing for UA sheets, or handle
   // -moz-bool-pref and various other things in the parallel parsing code.
   nsresult rv = gCSSLoader->LoadSheetSync(aURI, aParsingMode, true, aSheet);
   if (NS_FAILED(rv)) {
     ErrorLoadingSheet(aURI,
       nsPrintfCString("LoadSheetSync failed with error %" PRIx32, static_cast<uint32_t>(rv)).get(),
       aFailureAction);
   }
--- a/mfbt/AlreadyAddRefed.h
+++ b/mfbt/AlreadyAddRefed.h
@@ -34,46 +34,22 @@ struct unused_t;
  *   off-main-thread code)
  * * The ref pointer type you're using doesn't support move construction
  *
  * Otherwise, use std::move(RefPtr/nsCOMPtr/etc).
  */
 template<class T>
 struct MOZ_TEMPORARY_CLASS MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
 {
-  /*
-   * We want to allow returning nullptr from functions returning
-   * already_AddRefed<T>, for simplicity.  But we also don't want to allow
-   * returning raw T*, instead preferring creation of already_AddRefed<T> from
-   * a reference counting smart pointer.
-   *
-   * We address the latter requirement by making the (T*) constructor explicit.
-   * But |return nullptr| won't consider an explicit constructor, so we need
-   * another constructor to handle it.  Plain old (decltype(nullptr)) doesn't
-   * cut it, because if nullptr is emulated as __null (with type int or long),
-   * passing nullptr to an int/long parameter triggers compiler warnings.  We
-   * need a type that no one can pass accidentally; a pointer-to-member-function
-   * (where no such function exists) does the trick nicely.
-   *
-   * That handles the return-value case.  What about for locals, argument types,
-   * and so on?  |already_AddRefed<T>(nullptr)| considers both overloads (and
-   * the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity.
-   * We can target true nullptr using decltype(nullptr), but we can't target
-   * emulated nullptr the same way, because passing __null to an int/long
-   * parameter triggers compiler warnings.  So just give up on this, and provide
-   * this behavior through the default constructor.
-   *
-   * We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when
-   * nullptr no longer needs to be emulated to support the ancient b2g compiler.
-   * (The () overload could also be removed, if desired, if we changed callers.)
-   */
   already_AddRefed() : mRawPtr(nullptr) {}
 
+  // For simplicity, allow returning nullptr from functions returning
+  // already_AddRefed<T>. Don't permit returning raw T*, though; it's preferred
+  // to create already_AddRefed<T> from a reference-counting smart pointer.
   MOZ_IMPLICIT already_AddRefed(decltype(nullptr)) : mRawPtr(nullptr) {}
-
   explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {}
 
   // Disallow copy constructor and copy assignment operator: move semantics used instead.
   already_AddRefed(const already_AddRefed<T>& aOther) = delete;
   already_AddRefed<T>& operator=(const already_AddRefed<T>& aOther) = delete;
 
   // WARNING: sketchiness ahead.
   //
--- a/netwerk/base/nsITimedChannel.idl
+++ b/netwerk/base/nsITimedChannel.idl
@@ -31,18 +31,22 @@ interface nsITimedChannel : nsISupports 
   // channelCreationTime will be available even with this attribute set to
   // false.
   attribute boolean timingEnabled;
 
   // The number of redirects
   attribute uint8_t redirectCount;
   attribute uint8_t internalRedirectCount;
 
-  [noscript] readonly attribute TimeStamp channelCreation;
-  [noscript] readonly attribute TimeStamp asyncOpen;
+  // These properties should only be written externally when they must be
+  // propagated across an internal redirect.  For example, when a service
+  // worker interception falls back to network we need to copy the original
+  // timing values to the new nsHttpChannel.
+  [noscript] attribute TimeStamp channelCreation;
+  [noscript] attribute TimeStamp asyncOpen;
 
   // The following are only set when the request is intercepted by a service
   // worker no matter the response is synthesized.
   [noscript] attribute TimeStamp launchServiceWorkerStart;
   [noscript] attribute TimeStamp launchServiceWorkerEnd;
   [noscript] attribute TimeStamp dispatchFetchEventStart;
   [noscript] attribute TimeStamp dispatchFetchEventEnd;
   [noscript] attribute TimeStamp handleFetchEventStart;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -196,16 +196,17 @@ HttpBaseChannel::HttpBaseChannel()
   , mInitialRwin(0)
   , mProxyResolveFlags(0)
   , mContentDispositionHint(UINT32_MAX)
   , mHttpHandler(gHttpHandler)
   , mReferrerPolicy(NS_GetDefaultReferrerPolicy())
   , mRedirectCount(0)
   , mInternalRedirectCount(0)
   , mChannelCreationTime(0)
+  , mAsyncOpenTimeOverriden(false)
   , mForcePending(false)
   , mCorsIncludeCredentials(false)
   , mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS)
   , mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW)
   , mOnStartRequestCalled(false)
   , mOnStopRequestCalled(false)
   , mUpgradableToSecure(true)
   , mAfterOnStartRequestBegun(false)
@@ -3779,24 +3780,38 @@ HttpBaseChannel::SetupReplacementChannel
         std::max(newCount, mInternalRedirectCount));
     } else {
       int8_t newCount = mRedirectCount + 1;
       newTimedChannel->SetRedirectCount(
         std::max(newCount, mRedirectCount));
       newTimedChannel->SetInternalRedirectCount(mInternalRedirectCount);
     }
 
+    TimeStamp oldAsyncOpenTime;
+    oldTimedChannel->GetAsyncOpen(&oldAsyncOpenTime);
+
+    if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
+      TimeStamp oldChannelCreationTimestamp;
+      oldTimedChannel->GetChannelCreation(&oldChannelCreationTimestamp);
+
+      if (!oldChannelCreationTimestamp.IsNull()) {
+        newTimedChannel->SetChannelCreation(oldChannelCreationTimestamp);
+      }
+
+      if (!oldAsyncOpenTime.IsNull()) {
+        newTimedChannel->SetAsyncOpen(oldAsyncOpenTime);
+      }
+    }
+
     // If the RedirectStart is null, we will use the AsyncOpen value of the
     // previous channel (this is the first redirect in the redirects chain).
     if (mRedirectStartTimeStamp.IsNull()) {
       // Only do this for real redirects.  Internal redirects should be hidden.
       if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
-        TimeStamp asyncOpen;
-        oldTimedChannel->GetAsyncOpen(&asyncOpen);
-        newTimedChannel->SetRedirectStart(asyncOpen);
+        newTimedChannel->SetRedirectStart(oldAsyncOpenTime);
       }
     } else {
       newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
     }
 
     // For internal redirects just propagate the last redirect end time
     // forward.  Otherwise the new redirect end time is the last response
     // end time.
@@ -3924,21 +3939,38 @@ HttpBaseChannel::GetTimingEnabled(bool* 
 
 NS_IMETHODIMP
 HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) {
   *_retval = mChannelCreationTimestamp;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HttpBaseChannel::SetChannelCreation(TimeStamp aValue) {
+  MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
+  TimeDuration adjust = aValue - mChannelCreationTimestamp;
+  mChannelCreationTimestamp = aValue;
+  mChannelCreationTime += (PRTime)adjust.ToMicroseconds();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) {
   *_retval = mAsyncOpenTime;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+HttpBaseChannel::SetAsyncOpen(TimeStamp aValue) {
+  MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
+  mAsyncOpenTime = aValue;
+  mAsyncOpenTimeOverriden = true;
+  return NS_OK;
+}
+
 /**
  * @return the number of redirects. There is no check for cross-domain
  * redirects. This check must be done by the consumers.
  */
 NS_IMETHODIMP
 HttpBaseChannel::GetRedirectCount(uint8_t *aRedirectCount)
 {
   *aRedirectCount = mRedirectCount;
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -671,16 +671,17 @@ protected:
   TimeStamp                         mDispatchFetchEventStart;
   TimeStamp                         mDispatchFetchEventEnd;
   TimeStamp                         mHandleFetchEventStart;
   TimeStamp                         mHandleFetchEventEnd;
   // copied from the transaction before we null out mTransaction
   // so that the timing can still be queried from OnStopRequest
   TimingStruct                      mTransactionTimings;
 
+  bool                              mAsyncOpenTimeOverriden;
   bool                              mForcePending;
 
   bool mCorsIncludeCredentials;
   uint32_t mCorsMode;
   uint32_t mRedirectMode;
 
   // These parameters are used to ensure that we do not call OnStartRequest and
   // OnStopRequest more than once.
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2497,17 +2497,20 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
   NS_ENSURE_ARG_POINTER(listener);
   NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
 
   if (MaybeWaitForUploadStreamLength(listener, aContext)) {
     return NS_OK;
   }
 
-  mAsyncOpenTime = TimeStamp::Now();
+  if (!mAsyncOpenTimeOverriden) {
+    mAsyncOpenTime = TimeStamp::Now();
+  }
+
 #ifdef MOZ_TASK_TRACER
   if (tasktracer::IsStartLogging()) {
     nsCOMPtr<nsIURI> uri;
     GetURI(getter_AddRefs(uri));
     nsAutoCString urispec;
     uri->GetSpec(urispec);
     tasktracer::AddLabel("HttpChannelChild::AsyncOpen %s", urispec.get());
   }
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -680,16 +680,26 @@ InterceptedHttpChannel::ResetInterceptio
                                       nullptr, // aLoadGroup
                                       nullptr, // aCallbacks
                                       mLoadFlags);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = SetupReplacementChannel(mURI, newChannel, true, flags);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsITimedChannel> newTimedChannel = do_QueryInterface(newChannel);
+  if (newTimedChannel) {
+    if (!mAsyncOpenTime.IsNull()) {
+      newTimedChannel->SetAsyncOpen(mAsyncOpenTime);
+    }
+    if (!mChannelCreationTimestamp.IsNull()) {
+      newTimedChannel->SetChannelCreation(mChannelCreationTimestamp);
+    }
+  }
+
   if (mRedirectMode != nsIHttpChannelInternal::REDIRECT_MODE_MANUAL) {
     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
     rv = newChannel->GetLoadFlags(&loadFlags);
     NS_ENSURE_SUCCESS(rv, rv);
     loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
     rv = newChannel->SetLoadFlags(loadFlags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
--- a/netwerk/protocol/http/NullHttpChannel.cpp
+++ b/netwerk/protocol/http/NullHttpChannel.cpp
@@ -606,23 +606,39 @@ NullHttpChannel::SetInternalRedirectCoun
 NS_IMETHODIMP
 NullHttpChannel::GetChannelCreation(mozilla::TimeStamp *aChannelCreation)
 {
   *aChannelCreation = mChannelCreationTimestamp;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+NullHttpChannel::SetChannelCreation(TimeStamp aValue) {
+  MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
+  TimeDuration adjust = aValue - mChannelCreationTimestamp;
+  mChannelCreationTimestamp = aValue;
+  mChannelCreationTime += (PRTime)adjust.ToMicroseconds();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 NullHttpChannel::GetAsyncOpen(mozilla::TimeStamp *aAsyncOpen)
 {
   *aAsyncOpen = mAsyncOpenTime;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+NullHttpChannel::SetAsyncOpen(TimeStamp aValue) {
+  MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
+  mAsyncOpenTime = aValue;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 NullHttpChannel::GetLaunchServiceWorkerStart(mozilla::TimeStamp *_retval)
 {
   MOZ_ASSERT(_retval);
   *_retval = mAsyncOpenTime;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6045,17 +6045,19 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
 
     if (mLoadGroup)
         mLoadGroup->AddRequest(this, nullptr);
 
     // record asyncopen time unconditionally and clear it if we
     // don't want it after OnModifyRequest() weighs in. But waiting for
     // that to complete would mean we don't include proxy resolution in the
     // timing.
-    mAsyncOpenTime = TimeStamp::Now();
+    if (!mAsyncOpenTimeOverriden) {
+      mAsyncOpenTime = TimeStamp::Now();
+    }
 
     // Remember we have Authorization header set here.  We need to check on it
     // just once and early, AsyncOpen is the best place.
     mCustomAuthHeader = mRequestHead.HasHeader(nsHttp::Authorization);
 
     // The common case for HTTP channels is to begin proxy resolution and return
     // at this point. The only time we know mProxyInfo already is if we're
     // proxying a non-http protocol like ftp. We don't need to discover proxy
--- a/servo/components/style/encoding_support.rs
+++ b/servo/components/style/encoding_support.rs
@@ -50,58 +50,53 @@ fn decode_stylesheet_bytes<'a>(
 }
 
 impl Stylesheet {
     /// Parse a stylesheet from a set of bytes, potentially received over the
     /// network.
     ///
     /// Takes care of decoding the network bytes and forwards the resulting
     /// string to `Stylesheet::from_str`.
-    pub fn from_bytes<R>(
+    pub fn from_bytes(
         bytes: &[u8],
         url_data: UrlExtraData,
         protocol_encoding_label: Option<&str>,
         environment_encoding: Option<&'static encoding_rs::Encoding>,
         origin: Origin,
         media: MediaList,
         shared_lock: SharedRwLock,
         stylesheet_loader: Option<&StylesheetLoader>,
-        error_reporter: &R,
+        error_reporter: Option<&ParseErrorReporter>,
         quirks_mode: QuirksMode,
-    ) -> Stylesheet
-    where
-        R: ParseErrorReporter,
-    {
+    ) -> Stylesheet {
         let string = decode_stylesheet_bytes(bytes, protocol_encoding_label, environment_encoding);
         Stylesheet::from_str(
             &string,
             url_data,
             origin,
             Arc::new(shared_lock.wrap(media)),
             shared_lock,
             stylesheet_loader,
             error_reporter,
             quirks_mode,
             0,
         )
     }
 
     /// Updates an empty stylesheet with a set of bytes that reached over the
     /// network.
-    pub fn update_from_bytes<R>(
+    pub fn update_from_bytes(
         existing: &Stylesheet,
         bytes: &[u8],
         protocol_encoding_label: Option<&str>,
         environment_encoding: Option<&'static encoding_rs::Encoding>,
         url_data: UrlExtraData,
         stylesheet_loader: Option<&StylesheetLoader>,
-        error_reporter: &R,
-    ) where
-        R: ParseErrorReporter,
-    {
+        error_reporter: Option<&ParseErrorReporter>,
+    ) {
         let string = decode_stylesheet_bytes(bytes, protocol_encoding_label, environment_encoding);
         Self::update_from_str(
             existing,
             &string,
             url_data,
             stylesheet_loader,
             error_reporter,
             0,
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -12,18 +12,18 @@ use gecko_bindings::structs::{self, RawG
 use gecko_bindings::structs::{StyleSheetInfo, nsIDocument};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
 use invalidation::media_queries::{MediaListKey, ToMediaListKey};
 use malloc_size_of::MallocSizeOfOps;
 use media_queries::{Device, MediaList};
 use properties::ComputedValues;
 use selector_parser::SnapshotMap;
 use servo_arc::Arc;
+use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use std::fmt;
-use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
 use stylist::Stylist;
 
 /// Little wrapper to a Gecko style sheet.
 #[derive(Eq, PartialEq)]
 pub struct GeckoStyleSheet(*const DomStyleSheet);
 
 impl fmt::Debug for GeckoStyleSheet {
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -12,18 +12,18 @@ use gecko_bindings::structs::root::{Rust
 use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
 use gecko_bindings::sugar::refptr::RefPtr;
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use nsstring::nsCString;
 use parser::{Parse, ParserContext};
 use servo_arc::{Arc, RawOffsetArc};
 use std::fmt::{self, Write};
 use std::mem;
+use style_traits::{CssWriter, ParseError, ToCss};
 use stylesheets::UrlExtraData;
-use style_traits::{CssWriter, ParseError, ToCss};
 use values::computed::{Context, ToComputedValue};
 
 /// A CSS url() value for gecko.
 #[css(function = "url")]
 #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
 pub struct CssUrl {
     /// The URL in unresolved string form.
     ///
--- a/servo/components/style/properties/build.py
+++ b/servo/components/style/properties/build.py
@@ -64,26 +64,26 @@ def main():
         files[kind] = {}
         for struct in STYLE_STRUCT_LIST:
             file_name = os.path.join(BASE, kind, "{}.mako.rs".format(struct))
             if kind == "shorthands" and not os.path.exists(file_name):
                 files[kind][struct] = ""
                 continue
             files[kind][struct] = render(
                 file_name,
-                product = product,
-                data = properties,
+                product=product,
+                data=properties,
             )
     properties_template = os.path.join(BASE, "properties.mako.rs")
     files["properties"] = render(
         properties_template,
-        product = product,
-        data = properties,
-        __file__ = properties_template,
-        OUT_DIR = OUT_DIR,
+        product=product,
+        data=properties,
+        __file__=properties_template,
+        OUT_DIR=OUT_DIR,
     )
     if output == "style-crate":
         write(OUT_DIR, "properties.rs", files["properties"])
         for kind in ["longhands", "shorthands"]:
             for struct in files[kind]:
                 write(
                     os.path.join(OUT_DIR, kind),
                     "{}.rs".format(struct),
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -7,29 +7,28 @@
 #![deny(missing_docs)]
 
 use context::QuirksMode;
 use cssparser::{DeclarationListParser, parse_important, ParserInput, CowRcStr};
 use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter, ParseErrorKind};
 use custom_properties::CustomPropertiesBuilder;
 use error_reporting::{ParseErrorReporter, ContextualParseError};
 use parser::ParserContext;
-use properties::animated_properties::AnimationValue;
+use properties::animated_properties::{AnimationValue, AnimationValueMap};
 use shared_lock::Locked;
 use smallbitvec::{self, SmallBitVec};
 use smallvec::SmallVec;
 use std::fmt::{self, Write};
 use std::iter::{DoubleEndedIterator, Zip};
 use std::slice::Iter;
 use str::{CssString, CssStringBorrow, CssStringWriter};
 use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
 use stylesheets::{CssRuleType, Origin, UrlExtraData};
 use super::*;
 use values::computed::Context;
-use properties::animated_properties::AnimationValueMap;
 
 /// The animation rules.
 ///
 /// The first one is for Animation cascade level, and the second one is for
 /// Transition cascade level.
 pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
                           pub Option<Arc<Locked<PropertyDeclarationBlock>>>);
 
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -19,17 +19,17 @@ use style_traits::viewport::ViewportCons
 use values::{specified, KeyframesName};
 use values::computed::{self, ToComputedValue};
 use values::computed::font::FontSize;
 
 /// A device is a structure that represents the current media a given document
 /// is displayed in.
 ///
 /// This is the struct against which media queries are evaluated.
-#[derive(MallocSizeOf)]
+#[derive(Debug, MallocSizeOf)]
 pub struct Device {
     /// The current media type used by de device.
     media_type: MediaType,
     /// The current viewport size, in CSS pixels.
     viewport_size: TypedSize2D<f32, CSSPixel>,
     /// The current device pixel ratio, from CSS pixels to device pixels.
     device_pixel_ratio: TypedScale<f32, CSSPixel, DevicePixel>,
 
--- a/servo/tests/unit/style/media_queries.rs
+++ b/servo/tests/unit/style/media_queries.rs
@@ -1,48 +1,37 @@
 /* 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 cssparser::SourceLocation;
 use euclid::TypedScale;
 use euclid::TypedSize2D;
 use servo_arc::Arc;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use style::Atom;
 use style::context::QuirksMode;
-use style::error_reporting::{ParseErrorReporter, ContextualParseError};
 use style::media_queries::*;
 use style::servo::media_queries::*;
 use style::shared_lock::SharedRwLock;
 use style::stylesheets::{AllRules, Stylesheet, StylesheetInDocument, Origin, CssRule};
 use style::values::{CustomIdent, specified};
 use style_traits::ToCss;
 
-pub struct CSSErrorReporterTest;
-
-impl ParseErrorReporter for CSSErrorReporterTest {
-    fn report_error(&self,
-                    _url: &ServoUrl,
-                    _location: SourceLocation,
-                    _error: ContextualParseError) {
-    }
-}
-
 fn test_media_rule<F>(css: &str, callback: F)
-    where F: Fn(&MediaList, &str),
+where
+    F: Fn(&MediaList, &str),
 {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let css_str = css.to_owned();
     let lock = SharedRwLock::new();
     let media_list = Arc::new(lock.wrap(MediaList::empty()));
     let stylesheet = Stylesheet::from_str(
         css, url, Origin::Author, media_list, lock,
-        None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0);
+        None, None, QuirksMode::NoQuirks, 0);
     let dummy = Device::new(MediaType::screen(), TypedSize2D::new(200.0, 100.0), TypedScale::new(1.0));
     let mut rule_count = 0;
     let guard = stylesheet.shared_lock.read();
     for rule in stylesheet.iter_rules::<AllRules>(&dummy, &guard) {
         if let CssRule::Media(ref lock) = *rule {
             rule_count += 1;
             callback(&lock.read_with(&guard).media_queries.read_with(&guard), css);
         }
@@ -51,17 +40,17 @@ fn test_media_rule<F>(css: &str, callbac
 }
 
 fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let lock = SharedRwLock::new();
     let media_list = Arc::new(lock.wrap(MediaList::empty()));
     let ss = Stylesheet::from_str(
         css, url, Origin::Author, media_list, lock,
-        None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0);
+        None, None, QuirksMode::NoQuirks, 0);
     let mut rule_count = 0;
     ss.effective_style_rules(device, &ss.shared_lock.read(), |_| rule_count += 1);
     assert!(rule_count == expected_rule_count, css.to_owned());
 }
 
 #[test]
 fn test_mq_empty() {
     test_media_rule("@media { }", |list, css| {
deleted file mode 100644
--- a/servo/tests/unit/style/parsing/length.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use cssparser::{Parser, ParserInput};
-use parsing::parse;
-use style::context::QuirksMode;
-use style::parser::{Parse, ParserContext};
-use style::stylesheets::{CssRuleType, Origin};
-use style::values::specified::length::{AbsoluteLength, Length, NoCalcLength};
-use style_traits::{ParsingMode, ToCss};
-
-#[test]
-fn test_calc() {
-    assert!(parse(Length::parse, "calc(1px+ 2px)").is_err());
-    assert!(parse(Length::parse, "calc(calc(1px) + calc(1px + 4px))").is_ok());
-    assert!(parse(Length::parse, "calc( 1px + 2px )").is_ok());
-    assert!(parse(Length::parse, "calc(1px + 2px )").is_ok());
-    assert!(parse(Length::parse, "calc( 1px + 2px)").is_ok());
-    assert!(parse(Length::parse, "calc( 1px + 2px / ( 1 + 2 - 1))").is_ok());
-}
-
-#[test]
-fn test_length_literals() {
-    assert_roundtrip_with_context!(Length::parse, "0.33px", "0.33px");
-    assert_roundtrip_with_context!(Length::parse, "0.33in", "0.33in");
-    assert_roundtrip_with_context!(Length::parse, "0.33cm", "0.33cm");
-    assert_roundtrip_with_context!(Length::parse, "0.33mm", "0.33mm");
-    assert_roundtrip_with_context!(Length::parse, "0.33q", "0.33q");
-    assert_roundtrip_with_context!(Length::parse, "0.33pt", "0.33pt");
-    assert_roundtrip_with_context!(Length::parse, "0.33pc", "0.33pc");
-}
-
-#[test]
-fn test_parsing_modes() {
-    // In default length mode, non-zero lengths must have a unit.
-    assert!(parse(Length::parse, "1").is_err());
-
-    // In SVG length mode, non-zero lengths are assumed to be px.
-    let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url,
-                                     Some(CssRuleType::Style), ParsingMode::ALLOW_UNITLESS_LENGTH,
-                                     QuirksMode::NoQuirks);
-    let mut input = ParserInput::new("1");
-    let mut parser = Parser::new(&mut input);
-    let result = Length::parse(&context, &mut parser);
-    assert!(result.is_ok());
-    assert_eq!(result.unwrap(), Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(1.))));
-}
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -16,17 +16,17 @@ where F: for<'t> Fn(&ParserContext, &mut
     parse_input(f, &mut input)
 }
 
 fn parse_input<'i: 't, 't, T, F>(f: F, input: &'t mut ParserInput<'i>) -> Result<T, ParseError<'i>>
 where F: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>> {
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
     let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Style),
                                      ParsingMode::DEFAULT,
-                                     QuirksMode::NoQuirks);
+                                     QuirksMode::NoQuirks, None);
     let mut parser = Parser::new(input);
     f(&context, &mut parser)
 }
 
 fn parse_entirely<T, F>(f: F, s: &'static str) -> Result<T, ParseError<'static>>
 where F: for<'t> Fn(&ParserContext, &mut Parser<'static, 't>) -> Result<T, ParseError<'static>> {
     let mut input = ParserInput::new(s);
     parse_entirely_input(f, &mut input)
@@ -106,17 +106,15 @@ macro_rules! parse_longhand {
 mod animation;
 mod background;
 mod border;
 mod box_;
 mod column;
 mod effects;
 mod image;
 mod inherited_text;
-mod length;
 mod outline;
 mod position;
 mod selectors;
 mod supports;
 mod text_overflow;
 mod transition_duration;
 mod transition_timing_function;
-mod value;
deleted file mode 100644
--- a/servo/tests/unit/style/parsing/value.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use cssparser::{Parser, ParserInput};
-use style::context::QuirksMode;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
-use style::values::specified::Number;
-use style_traits::ParsingMode;
-
-#[test]
-fn test_parsing_allo_all_numeric_values() {
-    // In SVG length mode, non-zero lengths are assumed to be px.
-    let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url,
-                                     Some(CssRuleType::Style), ParsingMode::ALLOW_ALL_NUMERIC_VALUES,
-                                     QuirksMode::NoQuirks);
-    let mut input = ParserInput::new("-1");
-    let mut parser = Parser::new(&mut input);
-    let result = Number::parse_non_negative(&context, &mut parser);
-    assert!(result.is_ok());
-    assert_eq!(result.unwrap(), Number::new(-1.));
-}
-
deleted file mode 100644
--- a/servo/tests/unit/style/properties/background.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use properties::parse;
-use style::properties::longhands::background_size;
-
-#[test]
-fn background_size_should_reject_negative_values() {
-    assert!(parse(|c, _, i| background_size::parse(c, i), "-40% -40%").is_err());
-}
--- a/servo/tests/unit/style/properties/mod.rs
+++ b/servo/tests/unit/style/properties/mod.rs
@@ -1,63 +1,60 @@
 /* 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 cssparser::{Parser, ParserInput};
-use media_queries::CSSErrorReporterTest;
 use style::context::QuirksMode;
-use style::parser::{ParserContext, ParserErrorContext};
+use style::parser::ParserContext;
 use style::stylesheets::{CssRuleType, Origin};
 use style_traits::{ParsingMode, ParseError};
 
 fn parse<T, F>(f: F, s: &'static str) -> Result<T, ParseError<'static>>
-    where F: for<'t> Fn(&ParserContext,
-                        &ParserErrorContext<CSSErrorReporterTest>,
-                        &mut Parser<'static, 't>) -> Result<T, ParseError<'static>>
+where
+    F: for<'t> Fn(
+        &ParserContext,
+        &mut Parser<'static, 't>,
+    ) -> Result<T, ParseError<'static>>
 {
     let mut input = ParserInput::new(s);
     parse_input(f, &mut input)
 }
 
 fn parse_input<'i: 't, 't, T, F>(f: F, input: &'t mut ParserInput<'i>) -> Result<T, ParseError<'i>>
-    where F: Fn(&ParserContext,
-                &ParserErrorContext<CSSErrorReporterTest>,
-                &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>
+where
+    F: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>,
 {
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
     let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Style),
                                      ParsingMode::DEFAULT,
-                                     QuirksMode::NoQuirks);
-    let reporter = CSSErrorReporterTest;
-    let error_context = ParserErrorContext { error_reporter: &reporter };
+                                     QuirksMode::NoQuirks, None);
     let mut parser = Parser::new(input);
-    f(&context, &error_context, &mut parser)
+    f(&context, &mut parser)
 }
 
 macro_rules! assert_roundtrip_with_context {
     ($fun:expr, $string:expr) => {
         assert_roundtrip_with_context!($fun, $string, $string);
     };
     ($fun:expr, $input:expr, $output:expr) => {{
-        let serialized = parse(|context, _, i| {
+        let serialized = parse(|context, i| {
             let parsed = $fun(context, i)
                          .expect(&format!("Failed to parse {}", $input));
             let serialized = ToCss::to_css_string(&parsed);
             assert_eq!(serialized, $output);
             Ok(serialized)
         }, $input).unwrap();
 
         let mut input = ::cssparser::ParserInput::new(&serialized);
-        let unwrapped = parse_input(|context, _, i| {
+        let unwrapped = parse_input(|context, i| {
             let re_parsed = $fun(context, i)
                             .expect(&format!("Failed to parse serialization {}", $input));
             let re_serialized = ToCss::to_css_string(&re_parsed);
             assert_eq!(serialized, re_serialized);
             Ok(())
         }, &mut input).unwrap();
         unwrapped
     }}
 }
 
-mod background;
 mod scaffolding;
 mod serialization;
--- a/servo/tests/unit/style/properties/serialization.rs
+++ b/servo/tests/unit/style/properties/serialization.rs
@@ -479,17 +479,17 @@ mod shorthand_serialization {
             // serialization of 'border' shorthand, we need to set 'border-image' as well.
             let block_text = "\
                 border-top: 4px solid; \
                 border-right: 4px solid; \
                 border-bottom: 4px solid; \
                 border-left: 4px solid; \
                 border-image: none;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "border: 4px solid;");
         }
     }
 
     mod list_style {
@@ -531,17 +531,17 @@ mod shorthand_serialization {
                 background-repeat: repeat-x; \
                 background-attachment: scroll; \
                 background-size: 70px 50px; \
                 background-position-x: 7px; \
                 background-position-y: bottom 4px; \
                 background-origin: border-box; \
                 background-clip: padding-box;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(
                 serialization,
                 "background: rgb(255, 0, 0) url(\"http://servo/test.png\") repeat-x \
                 scroll left 7px bottom 4px / 70px 50px border-box padding-box;"
             );
@@ -555,17 +555,17 @@ mod shorthand_serialization {
                 background-repeat: repeat-x; \
                 background-attachment: scroll; \
                 background-size: 70px 50px; \
                 background-position-x: 7px; \
                 background-position-y: 4px; \
                 background-origin: padding-box; \
                 background-clip: padding-box;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(
                 serialization,
                 "background: rgb(255, 0, 0) url(\"http://servo/test.png\") repeat-x \
                 scroll 7px 4px / 70px 50px padding-box;"
             );
@@ -579,17 +579,17 @@ mod shorthand_serialization {
                 background-repeat: repeat-x, repeat-y; \
                 background-attachment: scroll, scroll; \
                 background-size: 70px 50px, 20px 30px; \
                 background-position-x: 7px, 70px; \
                 background-position-y: 4px, 40px; \
                 background-origin: border-box, padding-box; \
                 background-clip: padding-box, padding-box;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(
                 serialization, "background: \
                 url(\"http://servo/test.png\") repeat-x scroll 7px 4px / 70px 50px border-box padding-box, \
                 rgb(0, 0, 255) none repeat-y scroll 70px 40px / 20px 30px padding-box;"
             );
@@ -610,40 +610,40 @@ mod shorthand_serialization {
                 background-image: url(\"http://servo/test.png\"), none; \
                 background-repeat: repeat-x, repeat-y; \
                 background-attachment: scroll, scroll; \
                 background-size: 70px 50px, 20px 30px; \
                 background-position: 7px 4px, 5px 6px; \
                 background-origin: border-box; \
                 background-clip: padding-box, padding-box;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
 
         #[test]
         fn background_position_should_be_a_valid_form_its_longhands() {
             // If there is any longhand consisted of both keyword and position,
             // the shorthand result should be the 4-value format.
             let block_text = "\
                 background-position-x: 30px;\
                 background-position-y: bottom 20px;";
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
             let serialization = block.to_css_string();
             assert_eq!(serialization, "background-position: left 30px bottom 20px;");
 
             // If there is no longhand consisted of both keyword and position,
             // the shorthand result should be the 2-value format.
             let block_text = "\
                 background-position-x: center;\
                 background-position-y: 20px;";
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
             let serialization = block.to_css_string();
             assert_eq!(serialization, "background-position: center 20px;");
         }
     }
 
     mod transform {
         pub use super::*;
         use style::values::generics::transform::TransformOperation;
@@ -719,17 +719,17 @@ mod shorthand_serialization {
                 animation-duration: 1s;\
                 animation-timing-function: ease-in;\
                 animation-delay: 0s;\
                 animation-direction: normal;\
                 animation-fill-mode: forwards;\
                 animation-iteration-count: infinite;\
                 animation-play-state: paused;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "animation: 1s ease-in 0s infinite normal forwards paused bounce;")
         }
 
         #[test]
         fn serialize_multiple_animations() {
@@ -738,17 +738,17 @@ mod shorthand_serialization {
                 animation-duration: 1s, 0.2s;\
                 animation-timing-function: ease-in, linear;\
                 animation-delay: 0s, 1s;\
                 animation-direction: normal, reverse;\
                 animation-fill-mode: forwards, backwards;\
                 animation-iteration-count: infinite, 2;\
                 animation-play-state: paused, running;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization,
                        "animation: 1s ease-in 0s infinite normal forwards paused bounce, \
                                    0.2s linear 1s 2 reverse backwards running roll;");
         }
 
@@ -764,34 +764,34 @@ mod shorthand_serialization {
                 animation-duration: 1s, 0.2s; \
                 animation-timing-function: ease-in, linear; \
                 animation-delay: 0s, 1s, 0.5s; \
                 animation-direction: normal; \
                 animation-fill-mode: forwards, backwards; \
                 animation-iteration-count: infinite, 2; \
                 animation-play-state: paused, running;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
 
         #[test]
         fn serialize_multiple_without_all_properties_returns_longhand() {
             // timing function and direction are missing, so no shorthand is returned.
             let block_text = "animation-name: bounce, roll; \
                               animation-duration: 1s, 0.2s; \
                               animation-delay: 0s, 1s; \
                               animation-fill-mode: forwards, backwards; \
                               animation-iteration-count: infinite, 2; \
                               animation-play-state: paused, running;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
     }
 
     mod transition {
@@ -799,31 +799,31 @@ mod shorthand_serialization {
 
         #[test]
         fn transition_should_serialize_all_available_properties() {
             let block_text = "transition-property: margin-left; \
                               transition-duration: 3s; \
                               transition-delay: 4s; \
                               transition-timing-function: cubic-bezier(0.2, 5, 0.5, 2);";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "transition: margin-left 3s cubic-bezier(0.2, 5, 0.5, 2) 4s;");
         }
 
         #[test]
         fn serialize_multiple_transitions() {
             let block_text = "transition-property: margin-left, width; \
                               transition-duration: 3s, 2s; \
                               transition-delay: 4s, 5s; \
                               transition-timing-function: cubic-bezier(0.2, 5, 0.5, 2), ease;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "transition: \
                 margin-left 3s cubic-bezier(0.2, 5, 0.5, 2) 4s, \
                 width 2s ease 5s;");
         }
 
@@ -835,65 +835,65 @@ mod shorthand_serialization {
             // lists have the same length (this affects background, transition and animation).
             // https://github.com/servo/servo/issues/15398 )
             // The duration below has 1 extra value.
             let block_text = "transition-property: margin-left, width; \
                               transition-duration: 3s, 2s, 4s; \
                               transition-delay: 4s, 5s; \
                               transition-timing-function: cubic-bezier(0.2, 5, 0.5, 2), ease;";
 
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
 
         #[test]
         fn transition_should_serialize_acceptable_step_timing_function() {
             let block_text = "transition-property: margin-left; \
                               transition-duration: 3s; \
                               transition-delay: 4s; \
                               transition-timing-function: steps(2, start);";
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "transition: margin-left 3s steps(2, start) 4s;");
         }
 
         #[test]
         fn transition_should_serialize_acceptable_frames_timing_function() {
             let block_text = "transition-property: margin-left; \
                               transition-duration: 3s; \
                               transition-delay: 4s; \
                               transition-timing-function: frames(2);";
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "transition: margin-left 3s frames(2) 4s;");
         }
     }
 
     mod keywords {
         pub use super::*;
         #[test]
         fn css_wide_keywords_should_be_parsed() {
             let block_text = "--a:inherit;";
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
             assert_eq!(serialization, "--a: inherit;");
         }
 
         #[test]
         fn non_keyword_custom_property_should_be_unparsed() {
             let block_text = "--main-color: #06c;";
-            let block = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), block_text).unwrap();
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
             assert_eq!(serialization, block_text);
         }
     }
 
     mod effects {
         pub use super::*;
@@ -913,14 +913,14 @@ mod shorthand_serialization {
                     blur: Some(NonNegativeLength::from_px(3f32)),
                 },
                 spread: Some(Length::from_px(4f32)),
                 inset: false,
             };
             let shadow_decl = BoxShadowList(vec![shadow_val]);
             properties.push(PropertyDeclaration::BoxShadow(shadow_decl));
             let shadow_css = "box-shadow: 1px 2px 3px 4px;";
-            let shadow = parse(|c, e, i| Ok(parse_property_declaration_list(c, e, i)), shadow_css).unwrap();
+            let shadow = parse(|c, i| Ok(parse_property_declaration_list(c, i)), shadow_css).unwrap();
 
             assert_eq!(shadow.to_css_string(), shadow_css);
         }
     }
 }
--- a/servo/tests/unit/style/rule_tree/bench.rs
+++ b/servo/tests/unit/style/rule_tree/bench.rs
@@ -50,17 +50,17 @@ fn parse_rules(css: &str) -> Vec<(StyleS
     let media = Arc::new(lock.wrap(MediaList::empty()));
 
     let s = Stylesheet::from_str(css,
                                  ServoUrl::parse("http://localhost").unwrap(),
                                  Origin::Author,
                                  media,
                                  lock,
                                  None,
-                                 &ErrorringErrorReporter,
+                                 Some(&ErrorringErrorReporter),
                                  QuirksMode::NoQuirks,
                                  0);
     let guard = s.shared_lock.read();
     let rules = s.contents.rules.read_with(&guard);
     rules.0.iter().filter_map(|rule| {
         match *rule {
             CssRule::Style(ref style_rule) => Some((
                 StyleSource::from_rule(style_rule.clone()),
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -1,15 +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 cssparser::{self, SourceLocation};
 use html5ever::{Namespace as NsAtom};
-use media_queries::CSSErrorReporterTest;
 use parking_lot::RwLock;
 use selectors::attr::*;
 use selectors::parser::*;
 use servo_arc::Arc;
 use servo_atoms::Atom;
 use servo_config::prefs::{PREFS, PrefValue};
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
@@ -66,17 +65,17 @@ fn test_parse_stylesheet() {
                 animation-name: 'foo'; /* animation properties not allowed here */
                 animation-timing-function: ease; /* … except animation-timing-function */
             }
         }";
     let url = ServoUrl::parse("about::test").unwrap();
     let lock = SharedRwLock::new();
     let media = Arc::new(lock.wrap(MediaList::empty()));
     let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, media, lock,
-                                          None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0);
+                                          None, None, QuirksMode::NoQuirks, 0);
     let mut namespaces = Namespaces::default();
     namespaces.default = Some(ns!(html));
     let expected = Stylesheet {
         contents: StylesheetContents {
             origin: Origin::UserAgent,
             namespaces: RwLock::new(namespaces),
             url_data: RwLock::new(url),
             quirks_mode: QuirksMode::NoQuirks,
@@ -340,17 +339,17 @@ fn test_report_error_stylesheet() {
     @viewport { width: 320px invalid auto; }
     ";
     let url = ServoUrl::parse("about::test").unwrap();
     let error_reporter = TestingErrorReporter::new();
 
     let lock = SharedRwLock::new();
     let media = Arc::new(lock.wrap(MediaList::empty()));
     Stylesheet::from_str(css, url.clone(), Origin::UserAgent, media, lock,
-                         None, &error_reporter, QuirksMode::NoQuirks, 5);
+                         None, Some(&error_reporter), QuirksMode::NoQuirks, 5);
 
     error_reporter.assert_messages_contain(&[
         (8, 18, "Unsupported property declaration: 'display: invalid;'"),
         (9, 27, "Unsupported property declaration: 'background-image:"),  // FIXME: column should be around 56
         (10, 17, "Unsupported property declaration: 'invalid: true;'"),
         (12, 28, "Invalid media rule"),
         (13, 30, "Unsupported @font-face descriptor declaration"),
 
@@ -382,17 +381,17 @@ fn test_no_report_unrecognized_vendor_pr
     }
     ";
     let url = ServoUrl::parse("about::test").unwrap();
     let error_reporter = TestingErrorReporter::new();
 
     let lock = SharedRwLock::new();
     let media = Arc::new(lock.wrap(MediaList::empty()));
     Stylesheet::from_str(css, url, Origin::UserAgent, media, lock,
-                         None, &error_reporter, QuirksMode::NoQuirks, 0);
+                         None, Some(&error_reporter), QuirksMode::NoQuirks, 0);
 
     error_reporter.assert_messages_contain(&[
         (4, 31, "Unsupported property declaration: '-moz-background-color: red;'"),
     ]);
 }
 
 #[test]
 fn test_source_map_url() {
@@ -401,17 +400,17 @@ fn test_source_map_url() {
         ("/*# sourceMappingURL=something */", Some("something".to_string())),
     ];
 
     for test in tests {
         let url = ServoUrl::parse("about::test").unwrap();
         let lock = SharedRwLock::new();
         let media = Arc::new(lock.wrap(MediaList::empty()));
         let stylesheet = Stylesheet::from_str(test.0, url.clone(), Origin::UserAgent, media, lock,
-                                              None, &CSSErrorReporterTest, QuirksMode::NoQuirks,
+                                              None, None, QuirksMode::NoQuirks,
                                               0);
         let url_opt = stylesheet.contents.source_map_url.read();
         assert_eq!(*url_opt, test.1);
     }
 }
 
 #[test]
 fn test_source_url() {
@@ -420,14 +419,14 @@ fn test_source_url() {
         ("/*# sourceURL=something */", Some("something".to_string())),
     ];
 
     for test in tests {
         let url = ServoUrl::parse("about::test").unwrap();
         let lock = SharedRwLock::new();
         let media = Arc::new(lock.wrap(MediaList::empty()));
         let stylesheet = Stylesheet::from_str(test.0, url.clone(), Origin::UserAgent, media, lock,
-                                              None, &CSSErrorReporterTest, QuirksMode::NoQuirks,
+                                              None, None, QuirksMode::NoQuirks,
                                               0);
         let url_opt = stylesheet.contents.source_url.read();
         assert_eq!(*url_opt, test.1);
     }
 }
--- a/servo/tests/unit/style/viewport.rs
+++ b/servo/tests/unit/style/viewport.rs
@@ -1,57 +1,56 @@
 /* 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 cssparser::{Parser, ParserInput};
 use euclid::TypedScale;
 use euclid::TypedSize2D;
-use media_queries::CSSErrorReporterTest;
 use servo_arc::Arc;
 use servo_config::prefs::{PREFS, PrefValue};
 use servo_url::ServoUrl;
 use style::context::QuirksMode;
 use style::media_queries::{Device, MediaList, MediaType};
-use style::parser::{ParserContext, ParserErrorContext};
+use style::parser::ParserContext;
 use style::shared_lock::{SharedRwLock, StylesheetGuards};
 use style::stylesheets::{CssRuleType, Stylesheet, StylesheetInDocument, Origin};
 use style::stylesheets::viewport_rule::*;
 use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
 use style::values::specified::NoCalcLength::{self, ViewportPercentage};
 use style::values::specified::ViewportPercentageLength::Vw;
 use style_traits::{ParsingMode, PinchZoomFactor};
 use style_traits::viewport::*;
 
 macro_rules! stylesheet {
-    ($css:expr, $origin:ident, $error_reporter:expr) => {
-        stylesheet!($css, $origin, $error_reporter, SharedRwLock::new())
+    ($css:expr, $origin:ident) => {
+        stylesheet!($css, $origin, SharedRwLock::new())
     };
-    ($css:expr, $origin:ident, $error_reporter:expr, $shared_lock:expr) => {
+    ($css:expr, $origin:ident, $shared_lock:expr) => {
         Arc::new(Stylesheet::from_str(
             $css,
             ServoUrl::parse("http://localhost").unwrap(),
             Origin::$origin,
             Arc::new($shared_lock.wrap(MediaList::empty())),
             $shared_lock,
             None,
-            &$error_reporter,
+            None,
             QuirksMode::NoQuirks,
             0
         ))
     }
 }
 
 fn test_viewport_rule<F>(css: &str,
                          device: &Device,
                          callback: F)
     where F: Fn(&Vec<ViewportDescriptorDeclaration>, &str)
 {
     PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
-    let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest);
+    let stylesheet = stylesheet!(css, Author);
     let mut rule_count = 0;
     stylesheet.effective_viewport_rules(&device, &stylesheet.shared_lock.read(), |rule| {
         rule_count += 1;
         callback(&rule.declarations, css);
     });
     assert!(rule_count > 0);
 }
 
@@ -254,44 +253,44 @@ fn cascading_within_viewport_rule() {
         assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto), !important);
     });
 }
 
 #[test]
 fn multiple_stylesheets_cascading() {
     PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
     let device = Device::new(MediaType::screen(), TypedSize2D::new(800., 600.), TypedScale::new(1.0));
-    let error_reporter = CSSErrorReporterTest;
     let shared_lock = SharedRwLock::new();
     let stylesheets = vec![
         stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }",
-                    UserAgent, error_reporter, shared_lock.clone()),
+                    UserAgent,
+                    shared_lock.clone()),
         stylesheet!("@viewport { min-width: 200px; min-height: 200px; }",
-                    User, error_reporter, shared_lock.clone()),
+                    User, shared_lock.clone()),
         stylesheet!("@viewport { min-width: 300px; }",
-                    Author, error_reporter, shared_lock.clone())
+                    Author, shared_lock.clone())
     ];
 
     let declarations = Cascade::from_stylesheets(
         stylesheets.iter().map(|s| (&**s, Origin::Author)),
         &StylesheetGuards::same(&shared_lock.read()),
         &device,
     ).finish();
     assert_decl_len!(declarations == 3);
     assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
     assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px));
     assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px));
 
     let stylesheets = vec![
         stylesheet!("@viewport { min-width: 100px !important; }",
-                    UserAgent, error_reporter, shared_lock.clone()),
+                    UserAgent, shared_lock.clone()),
         stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }",
-                    User, error_reporter, shared_lock.clone()),
+                    User, shared_lock.clone()),
         stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }",
-                    Author, error_reporter, shared_lock.clone())
+                    Author, shared_lock.clone())
     ];
     let declarations = Cascade::from_stylesheets(
         stylesheets.iter().map(|s| (&**s, Origin::Author)),
         &StylesheetGuards::same(&shared_lock.read()),
         &device,
     ).finish();
     assert_decl_len!(declarations == 3);
     assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important);
@@ -299,22 +298,21 @@ fn multiple_stylesheets_cascading() {
     assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
 }
 
 #[test]
 fn constrain_viewport() {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Viewport),
                                      ParsingMode::DEFAULT,
-                                     QuirksMode::NoQuirks);
-    let error_context = ParserErrorContext { error_reporter: &CSSErrorReporterTest };
+                                     QuirksMode::NoQuirks, None);
 
     macro_rules! from_css {
         ($css:expr) => {
-            &ViewportRule::parse(&context, &error_context, &mut Parser::new(&mut $css)).unwrap()
+            &ViewportRule::parse(&context, &mut Parser::new(&mut $css)).unwrap()
         }
     }
 
     let initial_viewport = TypedSize2D::new(800., 600.);
     let device = Device::new(MediaType::screen(), initial_viewport, TypedScale::new(1.0));
     let mut input = ParserInput::new("");
     assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks), None);
 
--- a/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini
@@ -1,12 +1,5 @@
 prefs: [privacy.reduceTimerPrecision:false]
 [performance-timeline.https.html]
-  expected: TIMEOUT
   [Resource Timing]
-    expected: TIMEOUT
-
-  [Test Performance Timeline API in Service Worker]
-    expected: TIMEOUT
-
-  [empty service worker fetch event included in performance timings]
-    expected: NOTRUN
-
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1432758
--- a/testing/web-platform/tests/service-workers/service-worker/resources/performance-timeline-worker.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/performance-timeline-worker.js
@@ -39,20 +39,30 @@ promise_test(function(test) {
           assert_equals(performance.getEntriesByType('resource').length, expectedResources.length);
           for (var i = 0; i < expectedResources.length; i++) {
               var entry = performance.getEntriesByType('resource')[i];
               assert_true(entry.name.endsWith(expectedResources[i]));
               assert_equals(entry.workerStart, 0);
               assert_greater_than(entry.startTime, 0);
               assert_greater_than(entry.responseEnd, entry.startTime);
           }
-          return new Promise(function(resolve) {
-              performance.onresourcetimingbufferfull = resolve;
+          return Promise.race([
+            new Promise(function(resolve) {
+              performance.onresourcetimingbufferfull = _ => {
+                resolve('bufferfull');
+              }
               performance.setResourceTimingBufferSize(expectedResources.length);
-            });
+            }),
+
+            // Race the bufferfull event against another fetch.  We should get the
+            // event before this completes.  This allows us to detect a failure
+            // to dispatch the event without timing out the entire test.
+            fetch('dummy.txt').then(resp => resp.text())
+          ]);
         })
-      .then(function() {
+      .then(function(result) {
+          assert_equals(result, 'bufferfull');
           performance.clearResourceTimings();
           assert_equals(performance.getEntriesByType('resource').length, 0);
         })
   }, 'Resource Timing');
 
 done();
--- a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp
+++ b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/UniquePtr.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsProxyRelease.h"
 #include "nsTArray.h"
 #include "mozilla/Logging.h"
+#include "mozilla/Scoped.h"
 
 namespace mozilla {
 
 // Enclose everything which is not exported in an anonymous namespace.
 namespace {
 
 /**
  * An event used to notify the main thread when an error happens.
--- a/toolkit/components/places/PlacesRemoteTabsAutocompleteProvider.jsm
+++ b/toolkit/components/places/PlacesRemoteTabsAutocompleteProvider.jsm
@@ -63,16 +63,21 @@ async function ensureItems() {
   }
   return _items;
 }
 
 // A preference used to disable the showing of icons in remote tab records.
 const PREF_SHOW_REMOTE_ICONS = "services.sync.syncedTabs.showRemoteIcons";
 let showRemoteIcons;
 
+// A preference used to disable the synced tabs from showing in awesomebar
+// matches.
+const PREF_SHOW_REMOTE_TABS = "services.sync.syncedTabs.showRemoteTabs";
+let showRemoteTabs;
+
 // An observer to invalidate _items and watch for changed prefs.
 function observe(subject, topic, data) {
   switch (topic) {
     case "weave:engine:sync:finish":
       if (data == "tabs") {
         // The tabs engine just finished syncing, so may have a different list
         // of tabs then we previously cached.
         _items = null;
@@ -83,40 +88,50 @@ function observe(subject, topic, data) {
       // Sync is being reset due to the user disconnecting - we must invalidate
       // the cache so we don't supply tabs from a different user.
       _items = null;
       break;
 
     case "nsPref:changed":
       if (data == PREF_SHOW_REMOTE_ICONS) {
         showRemoteIcons = Services.prefs.getBoolPref(PREF_SHOW_REMOTE_ICONS, true);
+      } else if (data == PREF_SHOW_REMOTE_TABS) {
+        showRemoteTabs = Services.prefs.getBoolPref(PREF_SHOW_REMOTE_TABS, true);
       }
       break;
 
     default:
       break;
   }
 }
 
 Services.obs.addObserver(observe, "weave:engine:sync:finish");
 Services.obs.addObserver(observe, "weave:service:start-over");
 
-// Observe the pref for showing remote icons and prime our bool that reflects its value.
+// Observe the prefs for showing remote icons and tabs and prime
+// our bools that reflect their values.
 Services.prefs.addObserver(PREF_SHOW_REMOTE_ICONS, observe);
+Services.prefs.addObserver(PREF_SHOW_REMOTE_TABS, observe);
 observe(null, "nsPref:changed", PREF_SHOW_REMOTE_ICONS);
+observe(null, "nsPref:changed", PREF_SHOW_REMOTE_TABS);
+
 
 // This public object is a static singleton.
 var PlacesRemoteTabsAutocompleteProvider = {
   // a promise that resolves with an array of matching remote tabs.
   async getMatches(searchString) {
     // If Sync isn't configured we bail early.
     if (!weaveXPCService || !weaveXPCService.ready || !weaveXPCService.enabled) {
       return [];
     }
 
+    if (!showRemoteTabs) {
+      return [];
+    }
+
     let re = new RegExp(escapeRegExp(searchString), "i");
     let matches = [];
     let tabsData = await ensureItems();
     for (let {tab, client} of tabsData) {
       let url = tab.url;
       let title = tab.title;
       if (url.match(re) || (title && title.match(re))) {
         let icon = showRemoteIcons ? tab.icon : null;
--- a/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js
@@ -152,16 +152,37 @@ add_task(async function test_noShowIcons
                                     // expecting the default favicon due to that pref.
                                     icon: "",
                                   }),
              ],
   });
   Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteIcons");
 });
 
+add_task(async function test_dontMatchSyncedTabs() {
+  Services.prefs.setBoolPref("services.sync.syncedTabs.showRemoteTabs", false);
+  configureEngine({
+    guid_mobile: {
+      id: "mobile",
+      tabs: [{
+        urlHistory: ["http://example.com/"],
+        title: "An Example",
+        icon: "http://favicon",
+      }],
+    }
+  });
+
+  await check_autocomplete({
+    search: "ex",
+    searchParam: "enable-actions",
+    matches: [ makeSearchMatch("ex", { heuristic: true }) ],
+  });
+  Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteTabs");
+});
+
 add_task(async function test_matches_title() {
   // URL doesn't match search expression, should still match the title.
   configureEngine({
     guid_mobile: {
       id: "mobile",
       tabs: [{
         urlHistory: ["http://foo.com/"],
         title: "An Example",
--- a/toolkit/crashreporter/google-breakpad/src/common/moz.build
+++ b/toolkit/crashreporter/google-breakpad/src/common/moz.build
@@ -7,17 +7,17 @@
 if CONFIG['OS_ARCH'] in ('Darwin', 'Linux'):
     DIRS += ['dwarf']
 
 UNIFIED_SOURCES += [
     'convert_UTF.c',
     'string_conversion.cc',
 ]
 
-if CONFIG['OS_ARCH'] != 'WINNT':
+if CONFIG['OS_ARCH'] == 'Darwin':
     UNIFIED_SOURCES += [
         'md5.cc',
     ]
 
 if CONFIG['OS_ARCH'] == 'Linux':
     HOST_DEFINES['HAVE_A_OUT_H'] = True
 elif CONFIG['OS_ARCH'] == 'Darwin':
     HOST_DEFINES['HAVE_MACH_O_NLIST_H'] = True
--- a/toolkit/themes/windows/global/button.css
+++ b/toolkit/themes/windows/global/button.css
@@ -103,15 +103,18 @@ button[type="menu-button"] {
 button.plain {
   margin: 0 !important;
   padding: 0 !important;
 }
 
 button[type="disclosure"] {
   margin: 0;
   -moz-appearance: none;
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd");
+  list-style-image: url("chrome://global/skin/tree/twisty-collapsed.svg");
+  -moz-context-properties: fill, fill-opacity;
+  fill: currentColor;
+  fill-opacity: 1;
   min-width: 0;
 }
 
 button[type="disclosure"][open="true"] {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#open");
+  list-style-image: url("chrome://global/skin/tree/twisty-expanded.svg");
 }
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -51,19 +51,11 @@ toolkit.jar:
   skin/classic/global/icons/Search-close.png               (icons/Search-close.png)
   skin/classic/global/icons/Question.png                   (icons/Question.png)
   skin/classic/global/icons/sslWarning.png                 (icons/sslWarning.png)
   skin/classic/global/icons/Warning.png                    (icons/Warning.png)
   skin/classic/global/icons/warning-large.png              (icons/warning-large.png)
   skin/classic/global/icons/windowControls.png             (icons/windowControls.png)
 * skin/classic/global/in-content/common.css                (in-content/common.css)
 * skin/classic/global/in-content/info-pages.css            (in-content/info-pages.css)
-  skin/classic/global/tree/twisty.svg                      (tree/twisty.svg)
-  skin/classic/global/tree/twisty-preWin10.svg             (tree/twisty-preWin10.svg)
-
-% override chrome://global/skin/tree/twisty.svg#clsd              chrome://global/skin/tree/twisty-preWin10.svg#clsd           osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#clsd-rtl          chrome://global/skin/tree/twisty-preWin10.svg#clsd-rtl       osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#clsd-hover        chrome://global/skin/tree/twisty-preWin10.svg#clsd-hover     osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#clsd-hover-rtl    chrome://global/skin/tree/twisty-preWin10.svg#clsd-hover-rtl osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#open              chrome://global/skin/tree/twisty-preWin10.svg#open           osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#open-rtl          chrome://global/skin/tree/twisty-preWin10.svg#open-rtl       osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#open-hover        chrome://global/skin/tree/twisty-preWin10.svg#open-hover     osversion<=6.3
-% override chrome://global/skin/tree/twisty.svg#open-hover-rtl    chrome://global/skin/tree/twisty-preWin10.svg#open-hover-rtl osversion<=6.3
+  skin/classic/global/tree/twisty-collapsed.svg            (tree/twisty-collapsed.svg)
+  skin/classic/global/tree/twisty-collapsed-rtl.svg        (tree/twisty-collapsed-rtl.svg)
+  skin/classic/global/tree/twisty-expanded.svg             (tree/twisty-expanded.svg)
--- a/toolkit/themes/windows/global/tree.css
+++ b/toolkit/themes/windows/global/tree.css
@@ -260,45 +260,33 @@ treecol:not([hideheader="true"]) > .tree
 }
 
 /* ::::: twisty :::::  */
 
 treechildren::-moz-tree-twisty {
   padding-inline-end: 1px;
   padding-top: 1px;
   width: 9px; /* The image's width is 9 pixels */
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd");
+  list-style-image: url("chrome://global/skin/tree/twisty-collapsed.svg");
+  -moz-context-properties: fill, fill-opacity;
+  fill: #b6b6b6;
+  fill-opacity: 1;
+}
+
+treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(close) {
+  list-style-image: url("chrome://global/skin/tree/twisty-collapsed-rtl.svg");
 }
 
 treechildren::-moz-tree-twisty(open) {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#open");
+  list-style-image: url("chrome://global/skin/tree/twisty-expanded.svg");
+  fill: #636363;
 }
 
 treechildren::-moz-tree-twisty(hover) {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover");
-}
-
-treechildren::-moz-tree-twisty(hover, open) {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#open-hover");
-}
-
-treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd-rtl");
-}
-
-treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(open) {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#open-rtl");
-}
-
-treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(hover) {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover-rtl");
-}
-
-treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(hover, open) {
-  list-style-image: url("chrome://global/skin/tree/twisty.svg#open-hover-rtl");
+  fill: #4ed0f9;
 }
 
 treechildren::-moz-tree-indentation {
   width: 12px;
 }
 
 /* ::::: editable tree ::::: */
 
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/windows/global/tree/twisty-collapsed-rtl.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg width="9" height="9" xmlns="http://www.w3.org/2000/svg" stroke="context-fill" stroke-opacity="context-fill-opacity" stroke-width="1.6" fill="none">
+    <path d="m 6.5,0.5 -4,4 4,4"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/windows/global/tree/twisty-collapsed.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg width="9" height="9" xmlns="http://www.w3.org/2000/svg" stroke="context-fill" stroke-opacity="context-fill-opacity" stroke-width="1.6" fill="none">
+    <path d="m 2.5,0.5 4,4 -4,4"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/windows/global/tree/twisty-expanded.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg width="9" height="9" xmlns="http://www.w3.org/2000/svg" stroke="context-fill" stroke-opacity="context-fill-opacity" stroke-width="1.6" fill="none">
+    <path d="m 8.5,2.5 -4,4 -4,-4"/>
+</svg>
deleted file mode 100644
--- a/toolkit/themes/windows/global/tree/twisty-preWin10.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="9">
-  <style>
-    use:not(:target) {
-      display: none;
-    }
-    use {
-      stroke: #74747b;
-      stroke-opacity: 0.85;
-      fill: none;
-    }
-    use[id^="open"] {
-      stroke: #636363;
-      stroke-opacity: 1;
-    }
-    use[id*="-hover"] {
-      stroke: #1cc4f7;
-      stroke-opacity: 1;
-      fill: #c0e8f9;
-    }
-  </style>
-  <defs>
-    <path id="clsd-shape" d="m 2.5,0.5 4,4 -4,4 z"/>
-    <path id="open-shape" d="M 7.5,3 7.5,7.5 3,7.5 3,6.5 6.5,3 Z"/>
-    <path id="clsd-rtl-shape" d="m 6.5,0.5 -4,4 4,4 z"/>
-    <path id="open-rtl-shape" d="m 1.5,3 0,4.5 4.5,0 0,-1 L 2.5,3 Z"/>
-  </defs>
-  <use id="clsd" xlink:href="#clsd-shape"/>
-  <use id="clsd-hover" xlink:href="#clsd-shape"/>
-  <use id="open" xlink:href="#open-shape"/>
-  <use id="open-hover" xlink:href="#open-shape"/>
-  <use id="clsd-rtl" xlink:href="#clsd-rtl-shape"/>
-  <use id="clsd-hover-rtl" xlink:href="#clsd-rtl-shape"/>
-  <use id="open-rtl" xlink:href="#open-rtl-shape"/>
-  <use id="open-hover-rtl" xlink:href="#open-rtl-shape"/>
-</svg>
deleted file mode 100644
--- a/toolkit/themes/windows/global/tree/twisty.svg
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="9">
-  <style>
-    use:not(:target) {
-      display: none;
-    }
-    use {
-      stroke: #b6b6b6;
-      stroke-width: 1.6;
-      fill: none;
-    }
-    use[id^="open"] {
-      stroke: #636363;
-    }
-    use[id*="-hover"] {
-      stroke: #4ed0f9;
-    }
-  </style>
-  <defs>
-    <path id="clsd-shape" d="m 2.5,0.5 4,4 -4,4"/>
-    <path id="open-shape" d="m 8.5,2.5 -4,4 -4,-4"/>
-    <path id="clsd-rtl-shape" d="m 6.5,0.5 -4,4 4,4"/>
-  </defs>
-  <use id="clsd" xlink:href="#clsd-shape"/>
-  <use id="clsd-hover" xlink:href="#clsd-shape"/>
-  <use id="open" xlink:href="#open-shape"/>
-  <use id="open-hover" xlink:href="#open-shape"/>
-  <use id="clsd-rtl" xlink:href="#clsd-rtl-shape"/>
-  <use id="clsd-hover-rtl" xlink:href="#clsd-rtl-shape"/>
-  <use id="open-rtl" xlink:href="#open-shape"/>
-  <use id="open-hover-rtl" xlink:href="#open-shape"/>
-</svg>