Merge mozilla-central to inbound. a=merge CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 17 Apr 2018 13:10:25 +0300
changeset 414088 e2b49506d98cfc7dba7a15ce28e9c4b35a8328ed
parent 414087 617ce8cb79fbf444b207e840a89cd1b67f5baab1 (current diff)
parent 413999 f94b64e0020225c71701930f193bd96c3ad1d150 (diff)
child 414089 71b23fab4c0b8a450cf906a725f55171c0e81638
push id33858
push userncsoregi@mozilla.com
push dateTue, 17 Apr 2018 21:55:44 +0000
treeherdermozilla-central@d6eb5597d744 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound. a=merge CLOSED TREE
devtools/client/framework/test/browser_toolbox_transport_events.js
devtools/shared/transport/tests/unit/test_transport_events.js
docshell/base/nsDocShell.cpp
extensions/cookie/nsPopupWindowManager.cpp
extensions/cookie/nsPopupWindowManager.h
js/src/shell/js.cpp
js/src/vm/JSContext.cpp
js/src/vm/JSContext.h
js/src/vm/Runtime.h
layout/painting/nsDisplayList.h
layout/style/ServoPropPrefList.h
testing/mozbase/mozprofile/tests/addonid.py
testing/mozbase/mozprofile/tests/bug758250.py
testing/mozbase/mozprofile/tests/bug785146.py
testing/mozbase/mozprofile/tests/permissions.py
testing/mozbase/mozprofile/tests/server_locations.py
testing/mozbase/mozrunner/tests/mozrunnertest.py
testing/mozbase/mozversion/tests/test_b2g.py
testing/mozbase/mozversion/tests/test_sources.py
testing/web-platform/meta/css/geometry/DOMPoint-001.html.ini
toolkit/components/payments/test/unit/test_PaymentsStore.js
toolkit/content/menulist.css
toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.dtd
toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.properties
toolkit/mozapps/extensions/content/newaddon.js
toolkit/mozapps/extensions/content/newaddon.xul
toolkit/mozapps/extensions/test/browser/browser_newaddon.js
toolkit/themes/linux/mozapps/extensions/newaddon.css
toolkit/themes/osx/mozapps/extensions/newaddon.css
toolkit/themes/shared/extensions/newaddon.inc.css
toolkit/themes/windows/mozapps/extensions/newaddon.css
xpfe/appshell/nsIPopupWindowManager.idl
--- a/accessible/ipc/DocAccessibleChildBase.cpp
+++ b/accessible/ipc/DocAccessibleChildBase.cpp
@@ -52,17 +52,17 @@ DocAccessibleChildBase::InterfacesFor(Ac
 /* static */ void
 DocAccessibleChildBase::SerializeTree(Accessible* aRoot,
                                       nsTArray<AccessibleData>& aTree)
 {
   uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
 #if defined(XP_WIN)
   int32_t msaaId = AccessibleWrap::GetChildIDFor(aRoot);
 #endif
-  uint32_t role = aRoot->Role();
+  a11y::role role = aRoot->Role();
   uint32_t childCount = aRoot->ChildCount();
   uint32_t interfaces = InterfacesFor(aRoot);
 
   // OuterDocAccessibles are special because we don't want to serialize the
   // child doc here, we'll call PDocAccessibleConstructor in
   // NotificationController.
   MOZ_ASSERT(!aRoot->IsDoc(), "documents shouldn't be serialized");
   if (aRoot->IsOuterDoc()) {
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -108,31 +108,24 @@ DocAccessibleParent::AddSubtree(ProxyAcc
                                 uint32_t aIdx, uint32_t aIdxInParent)
 {
   if (aNewTree.Length() <= aIdx) {
     NS_ERROR("bad index in serialized tree!");
     return 0;
   }
 
   const AccessibleData& newChild = aNewTree[aIdx];
-  if (newChild.Role() > roles::LAST_ROLE) {
-    NS_ERROR("invalid role");
-    return 0;
-  }
 
   if (mAccessibles.Contains(newChild.ID())) {
     NS_ERROR("ID already in use");
     return 0;
   }
 
-  auto role = static_cast<a11y::role>(newChild.Role());
-
-  ProxyAccessible* newProxy =
-    new ProxyAccessible(newChild.ID(), aParent, this, role,
-                        newChild.Interfaces());
+  ProxyAccessible* newProxy = new ProxyAccessible(
+    newChild.ID(), aParent, this, newChild.Role(), newChild.Interfaces());
 
   aParent->AddChildAt(aIdxInParent, newProxy);
   mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
   ProxyCreated(newProxy, newChild.Interfaces());
 
 #if defined(XP_WIN)
   WrapperFor(newProxy)->SetID(newChild.MsaaID());
 #endif
@@ -391,28 +384,24 @@ DocAccessibleParent::RecvSelectionEvent(
   RefPtr<xpcAccEvent> event = new xpcAccEvent(aType, xpcTarget, xpcDoc,
                                               nullptr, false);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
+DocAccessibleParent::RecvRoleChangedEvent(const a11y::role& aRole)
 {
   if (mShutdown) {
     return IPC_OK();
   }
 
- if (aRole > roles::LAST_ROLE) {
-   return IPC_FAIL(this, "Child sent bad role in RoleChangedEvent");
- }
-
- mRole = static_cast<a11y::role>(aRole);
- return IPC_OK();
+  mRole = aRole;
+  return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
 {
   // One document should never directly be the child of another.
   // We should always have at least an outer doc accessible in between.
   MOZ_ASSERT(aID);
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -101,17 +101,17 @@ public:
   virtual mozilla::ipc::IPCResult RecvFocusEvent(const uint64_t& aID,
                                                  const LayoutDeviceIntRect& aCaretRect) override;
 #endif // defined(XP_WIN)
 
   virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID,
                                                      const uint64_t& aWidgetID,
                                                      const uint32_t& aType) override;
 
-  mozilla::ipc::IPCResult RecvRoleChangedEvent(const uint32_t& aRole) final;
+  mozilla::ipc::IPCResult RecvRoleChangedEvent(const a11y::role& aRole) final;
 
   virtual mozilla::ipc::IPCResult RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
 
   void Unbind()
   {
     if (DocAccessibleParent* parent = ParentDoc()) {
       parent->RemoveChildDoc(this);
     }
--- a/accessible/ipc/IPCTypes.h
+++ b/accessible/ipc/IPCTypes.h
@@ -2,16 +2,29 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_IPCTypes_h
 #define mozilla_a11y_IPCTypes_h
 
+#include "mozilla/a11y/Role.h"
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::a11y::role>
+  : public ContiguousEnumSerializerInclusive<mozilla::a11y::role,
+                                             mozilla::a11y::role::NOTHING,
+                                             mozilla::a11y::role::LAST_ROLE>
+{
+};
+};
+
 /**
  * Since IPDL does not support preprocessing, this header file allows us to
  * define types used by PDocAccessible differently depending on platform.
  */
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
 
 // So that we don't include a bunch of other Windows junk.
--- a/accessible/ipc/other/PDocAccessible.ipdl
+++ b/accessible/ipc/other/PDocAccessible.ipdl
@@ -5,26 +5,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PFileDescriptorSet;
 include protocol PBrowser;
 
 include "mozilla/GfxMessageUtils.h";
 
 using nsIntRect from "nsRect.h";
+using mozilla::a11y::role from "mozilla/a11y/Role.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
 using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h";
 
 namespace mozilla {
 namespace a11y {
 
 struct AccessibleData
 {
   uint64_t ID;
-  uint32_t Role;
+  role Role;
   uint32_t ChildrenCount;
   uint32_t Interfaces;
 };
 
 struct ShowEventData
 {
   uint64_t ID;
   uint32_t Idx;
@@ -58,17 +59,17 @@ parent:
   async Event(uint64_t aID, uint32_t type);
   async ShowEvent(ShowEventData data, bool aFromuser);
   async HideEvent(uint64_t aRootID, bool aFromUser);
   async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
   async CaretMoveEvent(uint64_t aID, int32_t aOffset);
   async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
                         bool aIsInsert, bool aFromUser);
   async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
-  async RoleChangedEvent(uint32_t aRole);
+  async RoleChangedEvent(role aRole);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
 child:
@@ -88,17 +89,17 @@ child:
   nested(inside_sync) sync Help(uint64_t aID) returns(nsString help);
   nested(inside_sync) sync Description(uint64_t aID) returns(nsString desc);
   nested(inside_sync) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
   nested(inside_sync) sync RelationByType(uint64_t aID, uint32_t aRelationType)
     returns(uint64_t[] targets);
   nested(inside_sync) sync Relations(uint64_t aID) returns(RelationTargets[] relations);
   nested(inside_sync) sync IsSearchbox(uint64_t aID) returns(bool retval);
   nested(inside_sync) sync LandmarkRole(uint64_t aID) returns(nsString landmark);
-  nested(inside_sync) sync ARIARoleAtom(uint64_t aID) returns(nsString role);
+  nested(inside_sync) sync ARIARoleAtom(uint64_t aID) returns(nsString ariaRole);
   nested(inside_sync) sync GetLevelInternal(uint64_t aID) returns(int32_t aLevel);
   async ScrollTo(uint64_t aID, uint32_t aScrollType);
   async ScrollToPoint(uint64_t aID, uint32_t aScrollType, int32_t aX,
                       int32_t aY);
 
   // AccessibleText
 
   // TextSubstring is getText in IDL.
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -258,17 +258,17 @@ DocAccessibleChild::SendSelectionEvent(c
 
   PushDeferredEvent(MakeUnique<SerializedSelection>(this, aID,
                                                                 aWidgetID,
                                                                 aType));
   return true;
 }
 
 bool
-DocAccessibleChild::SendRoleChangedEvent(const uint32_t& aRole)
+DocAccessibleChild::SendRoleChangedEvent(const a11y::role& aRole)
 {
   if (IsConstructedInParentProcess()) {
     return PDocAccessibleChild::SendRoleChangedEvent(aRole);
   }
 
   PushDeferredEvent(MakeUnique<SerializedRoleChanged>(this, aRole));
   return true;
 }
--- a/accessible/ipc/win/DocAccessibleChild.h
+++ b/accessible/ipc/win/DocAccessibleChild.h
@@ -52,17 +52,17 @@ public:
   bool SendFocusEvent(const uint64_t& aID,
                       const LayoutDeviceIntRect& aCaretRect);
   bool SendTextChangeEvent(const uint64_t& aID, const nsString& aStr,
                            const int32_t& aStart, const uint32_t& aLen,
                            const bool& aIsInsert, const bool& aFromUser,
                            const bool aDoSyncCheck = true);
   bool SendSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID,
                           const uint32_t& aType);
-  bool SendRoleChangedEvent(const uint32_t& aRole);
+  bool SendRoleChangedEvent(const a11y::role& aRole);
 
   bool ConstructChildDocInParentProcess(DocAccessibleChild* aNewChildDoc,
                                         uint64_t aUniqueID, uint32_t aMsaaID);
 
   bool SendBindChildDoc(DocAccessibleChild* aChildDoc,
                         const uint64_t& aNewParentID);
 
 protected:
@@ -251,27 +251,27 @@ private:
 
     uint64_t  mID;
     uint64_t  mWidgetID;
     uint32_t  mType;
   };
 
   struct SerializedRoleChanged final : public DeferredEvent
   {
-    explicit SerializedRoleChanged(DocAccessibleChild* aTarget, uint32_t aRole)
+    explicit SerializedRoleChanged(DocAccessibleChild* aTarget, a11y::role aRole)
       : DeferredEvent(aTarget)
       , mRole(aRole)
     {}
 
     void Dispatch(DocAccessibleChild* aIPCDoc) override
     {
       Unused << aIPCDoc->SendRoleChangedEvent(mRole);
     }
 
-    uint32_t mRole;
+    a11y::role mRole;
   };
 
   struct SerializedEvent final : public DeferredEvent
   {
     SerializedEvent(DocAccessibleChild* aTarget, uint64_t aID, uint32_t aType)
       : DeferredEvent(aTarget)
       , mID(aID)
       , mType(aType)
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -2,29 +2,30 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PFileDescriptorSet;
 include protocol PBrowser;
 
+using mozilla::a11y::role from "mozilla/a11y/Role.h";
 using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
 using mozilla::a11y::IDispatchHolder from "mozilla/a11y/IPCTypes.h";
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using mozilla::LayoutDeviceIntRect from "Units.h";
 
 namespace mozilla {
 namespace a11y {
 
 struct AccessibleData
 {
   uint64_t ID;
   int32_t MsaaID;
-  uint32_t Role;
+  role Role;
   uint32_t ChildrenCount;
   uint32_t Interfaces;
 };
 
 struct ShowEventData
 {
   uint64_t ID;
   uint32_t Idx;
@@ -55,17 +56,17 @@ parent:
   async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
   async CaretMoveEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect,
                        int32_t aOffset);
   async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
                         bool aIsInsert, bool aFromUser);
   sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart,
                            uint32_t aLen, bool aIsInsert, bool aFromUser);
   async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
-  async RoleChangedEvent(uint32_t aRole);
+  async RoleChangedEvent(role aRole);
   async FocusEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -1253,8 +1253,65 @@ BrowserPageActions.addSearchEngine = {
         let prompt = Services.prompt.getPrompt(gBrowser.contentWindow, Ci.nsIPrompt);
         prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
         prompt.setPropertyAsBool("allowTabModal", true);
         prompt.alert(title, text);
       },
     });
   },
 };
+
+// share URL
+BrowserPageActions.shareURL = {
+  onShowingInPanel(buttonNode) {
+    this._cached = false;
+  },
+
+  onPlacedInPanel(buttonNode) {
+    let action = PageActions.actionForID("shareURL");
+    BrowserPageActions.takeActionTitleFromPanel(action);
+  },
+
+  onShowingSubview(panelViewNode) {
+    // We cache the providers + the UI if the user selects the share
+    // panel multiple times while the panel is open.
+    if (this._cached) {
+      return;
+    }
+
+    let sharingService = this._sharingService;
+    let url = gBrowser.selectedBrowser.currentURI;
+    let currentURI = gURLBar.makeURIReadable(url).displaySpec;
+    let shareProviders = sharingService.getSharingProviders(currentURI);
+    let fragment = document.createDocumentFragment();
+
+    shareProviders.forEach(function(share) {
+      let item = document.createElement("toolbarbutton");
+      item.setAttribute("label", share.menuItemTitle);
+      item.setAttribute("share-title", share.title);
+      item.setAttribute("image", share.image);
+      item.classList.add("subviewbutton", "subviewbutton-iconic");
+
+      item.addEventListener("command", event => {
+        let shareTitle = event.target.getAttribute("share-title");
+        if (shareTitle) {
+          sharingService.shareUrl(shareTitle, currentURI);
+        }
+        PanelMultiView.hidePopup(BrowserPageActions.panelNode);
+      });
+
+      fragment.appendChild(item);
+    });
+
+    let bodyNode = panelViewNode.querySelector(".panel-subview-body");
+    while (bodyNode.firstChild) {
+      bodyNode.firstChild.remove();
+    }
+    bodyNode.appendChild(fragment);
+    this._cached = true;
+  }
+};
+
+// Attach sharingService here so tests can override the implementation
+XPCOMUtils.defineLazyServiceGetter(BrowserPageActions.shareURL,
+                                   "_sharingService",
+                                   "@mozilla.org/widget/macsharingservice;1",
+                                   "nsIMacSharingService");
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -50,17 +50,17 @@ var gIdentityHandler = {
    * to be able to focus it on the popupshown event.
    */
   _popupTriggeredByKeyboard: false,
 
   /**
    * RegExp used to decide if an about url should be shown as being part of
    * the browser UI.
    */
-  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|newaddon|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
+  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
 
   get _isBroken() {
     return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
   },
 
   get _isSecure() {
     // If a <browser> is included within a chrome document, then this._state
     // will refer to the security state for the <browser> and not the top level
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -163,41 +163,34 @@ panelview[mainview] > .panel-header {
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
   visibility: hidden;
 }
 
-.tab-close-button,
-.tabbrowser-tab::after,
-.tab-background {
-  /* Explicitly set the visibility to override the value (collapsed)
-   * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
-  visibility: visible;
-}
-
+.tab-icon-image[fadein],
 .tab-close-button[fadein],
 .tabbrowser-tab[fadein]::after,
 .tab-background[fadein] {
   /* This transition is only wanted for opening tabs. */
   transition: visibility 0ms 25ms;
 }
 
+.tab-icon-image:not([fadein]),
 .tab-close-button:not([fadein]),
 .tabbrowser-tab:not([fadein])::after,
 .tab-background:not([fadein]) {
   visibility: hidden;
 }
 
 .tab-label:not([fadein]),
 .tab-throbber:not([fadein]),
-.tab-throbber-fallback:not([fadein]),
-.tab-icon-image:not([fadein]) {
+.tab-throbber-fallback:not([fadein]) {
   display: none;
 }
 
 %ifdef NIGHTLY_BUILD
 @supports -moz-bool-pref("browser.tabs.hideThrobber") {
   .tab-throbber,
   .tab-throbber-fallback {
     display: none;
@@ -1215,17 +1208,17 @@ toolbarpaletteitem[place="palette"] > #d
   overflow-x: hidden;
 }
 
 #customization-panelWrapper,
 #customization-panelWrapper > .panel-arrowcontent,
 #customization-panelHolder {
   flex-direction: column;
   display: flex;
-  min-height: calc(174px + 8em);
+  min-height: calc(174px + 9em);
 }
 
 #customization-panelWrapper {
   flex: 1 1 auto;
   height: 0; /* Don't let my contents affect ancestors' content-based sizing */
   align-items: end; /* align to the end on the cross-axis (affects arrow) */
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7349,17 +7349,17 @@ var gIdentityHandler = {
    * to be able to focus it on the popupshown event.
    */
   _popupTriggeredByKeyboard: false,
 
   /**
    * RegExp used to decide if an about url should be shown as being part of
    * the browser UI.
    */
-  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|newaddon|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
+  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
 
   get _isBroken() {
     return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
   },
 
   get _isSecure() {
     // If a <browser> is included within a chrome document, then this._state
     // will refer to the security state for the <browser> and not the top level
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -435,17 +435,18 @@
            flip="slide"
            photon="true"
            position="bottomcenter topright"
            tabspecific="true"
            noautofocus="true"
            copyURL-title="&pageAction.copyLink.label;"
            emailLink-title="&emailPageCmd.label;"
            sendToDevice-title="&pageAction.sendTabToDevice.label;"
-           sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;">
+           sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;"
+           shareURL-title="&pageAction.shareUrl.label;">
       <panelmultiview id="pageActionPanelMultiView"
                       mainViewId="pageActionPanelMainView"
                       viewCacheId="appMenu-viewCache">
         <panelview id="pageActionPanelMainView"
                    context="pageActionContextMenu"
                    class="PanelUI-subView">
           <vbox class="panel-subview-body"/>
         </panelview>
@@ -634,18 +635,17 @@
     </toolbar>
 
     <toolbar id="TabsToolbar"
              class="titlebar-color"
              fullscreentoolbar="true"
              customizable="true"
              mode="icons"
              aria-label="&tabsToolbar.label;"
-             context="toolbar-context-menu"
-             collapsed="true">
+             context="toolbar-context-menu">
       <hbox class="titlebar-placeholder" type="pre-tabs"
             skipintoolbarset="true"/>
 
       <tabs id="tabbrowser-tabs"
             flex="1"
             setfocus="false"
             tooltip="tabbrowser-tab-tooltip"
             stopwatchid="FX_TAB_CLICK_MS">
--- a/browser/base/content/test/static/browser_parsable_script.js
+++ b/browser/base/content/test/static/browser_parsable_script.js
@@ -4,16 +4,21 @@
 /* This list allows pre-existing or 'unfixable' JS issues to remain, while we
  * detect newly occurring issues in shipping JS. It is a list of regexes
  * matching files which have errors:
  */
 const kWhitelist = new Set([
   /browser\/content\/browser\/places\/controller.js$/,
 ]);
 
+const kESModuleList = new Set([
+  /toolkit\/res\/payments\/(components|containers|mixins)\/.*.js$/,
+  /toolkit\/res\/payments\/PaymentsStore.js$/,
+]);
+
 // Normally we would use reflect.jsm to get Reflect.parse. However, if
 // we do that, then all the AST data is allocated in reflect.jsm's
 // zone. That exposes a bug in our GC. The GC collects reflect.jsm's
 // zone but not the zone in which our test code lives (since no new
 // data is being allocated in it). The cross-compartment wrappers in
 // our zone that point to the AST data never get collected, and so the
 // AST data itself is never collected. We need to GC both zones at
 // once to fix the problem.
@@ -31,26 +36,45 @@ function uriIsWhiteListed(uri) {
   for (let whitelistItem of kWhitelist) {
     if (whitelistItem.test(uri.spec)) {
       return true;
     }
   }
   return false;
 }
 
-function parsePromise(uri) {
+/**
+ * Check if a URI should be parsed as an ES module.
+ *
+ * @param uri the uri to check against the ES module list
+ * @return true if the uri should be parsed as a module, otherwise parse it as a script.
+ */
+function uriIsESModule(uri) {
+  for (let whitelistItem of kESModuleList) {
+    if (whitelistItem.test(uri.spec)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+function parsePromise(uri, parseTarget) {
   let promise = new Promise((resolve, reject) => {
     let xhr = new XMLHttpRequest();
     xhr.open("GET", uri, true);
     xhr.onreadystatechange = function() {
       if (this.readyState == this.DONE) {
         let scriptText = this.responseText;
         try {
-          info("Checking " + uri);
-          Reflect.parse(scriptText, {source: uri});
+          info(`Checking ${parseTarget} ${uri}`);
+          let parseOpts = {
+            source: uri,
+            target: parseTarget,
+          };
+          Reflect.parse(scriptText, parseOpts);
           resolve(true);
         } catch (ex) {
           let errorMsg = "Script error reading " + uri + ": " + ex;
           ok(false, errorMsg);
           resolve(false);
         }
       }
     };
@@ -113,12 +137,16 @@ add_task(async function checkAllTheJS() 
 
   // We create an array of promises so we can parallelize all our parsing
   // and file loading activity:
   await throttledMapPromises(uris, uri => {
     if (uriIsWhiteListed(uri)) {
       info("Not checking whitelisted " + uri.spec);
       return undefined;
     }
-    return parsePromise(uri.spec);
+    let target = "script";
+    if (uriIsESModule(uri)) {
+      target = "module";
+    }
+    return parsePromise(uri.spec, target);
   });
   ok(true, "All files parsed");
 });
--- a/browser/base/content/test/statuspanel/browser.ini
+++ b/browser/base/content/test/statuspanel/browser.ini
@@ -1,5 +1,7 @@
 [DEFAULT]
 support-files =
   head.js
 
 [browser_show_statuspanel_twice.js]
+[browser_show_statuspanel_idn.js]
+skip-if = webrender && verify
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/statuspanel/browser_show_statuspanel_idn.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_PAGE_URL = encodeURI(`data:text/html;charset=utf-8,<a id="foo" href="http://nic.xn--rhqv96g/">abc</a><span id="bar">def</span>`);
+const TEST_STATUS_TEXT = "nic.\u4E16\u754C";
+
+/**
+ * Test that if the StatusPanel displays an IDN
+ * (Bug 1450538).
+ */
+add_task(async function test_show_statuspanel_twice() {
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URL);
+
+  let promise = promiseStatusPanelShown(window, TEST_STATUS_TEXT);
+  ContentTask.spawn(tab.linkedBrowser, null, async () => {
+    content.document.links[0].focus();
+  });
+  await promise;
+
+  await BrowserTestUtils.removeTab(tab);
+});
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -47,16 +47,18 @@ support-files =
   page_action_menu_add_search_engine_one.html
   page_action_menu_add_search_engine_many.html
   page_action_menu_add_search_engine_same_names.html
   page_action_menu_add_search_engine_0.xml
   page_action_menu_add_search_engine_1.xml
   page_action_menu_add_search_engine_2.xml
 [browser_page_action_menu_clipboard.js]
 subsuite = clipboard
+[browser_page_action_menu_share_mac.js]
+skip-if = os != "mac" # Mac only feature
 [browser_pasteAndGo.js]
 subsuite = clipboard
 [browser_removeUnsafeProtocolsFromURLBarPaste.js]
 subsuite = clipboard
 [browser_search_favicon.js]
 [browser_tabMatchesInAwesomebar.js]
 support-files =
   moz.png
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_page_action_menu_share_mac.js
@@ -0,0 +1,72 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* global sinon */
+Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
+
+// Keep track of title of service we chose to share with
+let sharedTitle;
+let sharedUrl;
+
+let mockShareData = [{
+  title: "NSA",
+  menuItemTitle: "National Security Agency",
+  image: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEA" +
+    "LAAAAAABAAEAAAICTAEAOw=="
+}];
+
+let stub = sinon.stub(BrowserPageActions.shareURL, "_sharingService").get(() => {
+  return {
+    getSharingProviders(url) {
+      return mockShareData;
+    },
+    shareUrl(title, url) {
+      sharedUrl = url;
+      sharedTitle = title;
+    }
+  };
+});
+
+registerCleanupFunction(async function() {
+  stub.restore();
+  delete window.sinon;
+  await EventUtils.synthesizeNativeMouseMove(document.documentElement, 0, 0);
+  await PlacesUtils.history.clear();
+});
+
+add_task(async function shareURL() {
+  // Open an actionable page so that the main page action button appears.  (It
+  // does not appear on about:blank for example.)
+  let url = "http://example.org/";
+
+  await BrowserTestUtils.withNewTab(url, async () => {
+    // Open the panel.
+    await promisePageActionPanelOpen();
+
+    // Click Share URL.
+    let shareURLButton = document.getElementById("pageAction-panel-shareURL");
+    let viewPromise = promisePageActionViewShown();
+    EventUtils.synthesizeMouseAtCenter(shareURLButton, {});
+
+    let view = await viewPromise;
+    let body = document.getElementById(view.id + "-body");
+
+    Assert.equal(body.childNodes.length, 1, "Has correct share receivers");
+    let shareButton = body.childNodes[0];
+    Assert.equal(shareButton.label, mockShareData[0].menuItemTitle);
+    let hiddenPromise = promisePageActionPanelHidden();
+    // Click on share, panel should hide and sharingService should be
+    // given the title of service to share with
+    EventUtils.synthesizeMouseAtCenter(shareButton, {});
+    await hiddenPromise;
+
+    Assert.equal(sharedTitle, mockShareData[0].title,
+                 "Shared with the correct title");
+    Assert.equal(sharedUrl, "http://example.org/",
+                 "Shared correct URL");
+
+  });
+});
--- a/browser/base/content/test/urlbar/browser_search_favicon.js
+++ b/browser/base/content/test/urlbar/browser_search_favicon.js
@@ -6,16 +6,20 @@ registerCleanupFunction(() => {
   Services.prefs.clearUserPref(gRestyleSearchesPref);
   Services.search.currentEngine = gOriginalEngine;
   Services.search.removeEngine(gEngine);
   return PlacesUtils.history.clear();
 });
 
 add_task(async function() {
   Services.prefs.setBoolPref(gRestyleSearchesPref, true);
+
+  // This test is sensitive to the mouse position hovering awesome
+  // bar elements, so make sure it doesnt
+  await EventUtils.synthesizeNativeMouseMove(document.documentElement, 0, 0);
 });
 
 add_task(async function() {
 
   Services.search.addEngineWithDetails("SearchEngine", "", "", "",
                                        "GET", "http://s.example.com/search");
   gEngine = Services.search.getEngineByName("SearchEngine");
   gEngine.addParam("q", "{searchTerms}", null);
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -2452,23 +2452,27 @@ file, You can obtain one at http://mozil
       <handler event="mousedown"><![CDATA[
         // Required to make the xul:label.text-link elements in the search
         // suggestions notification work correctly when clicked on Linux.
         // This is copied from the mousedown handler in
         // browser-search-autocomplete-result-popup, which apparently had a
         // similar problem.
         event.preventDefault();
 
+        if (event.button == 2) {
+          // Right mouse button currently allows to select.
+          this.input.userSelectionBehavior = "rightClick";
+          // Ignore right-clicks.
+          return;
+        }
+
         if (!this.input.speculativeConnectEnabled) {
           return;
         }
-        if (event.button == 2) {
-          // Ignore right-clicks.
-          return;
-        }
+
         // Ensure the user is clicking on an url instead of other buttons
         // on the popup.
         let elt = event.originalTarget;
         while (elt && elt.localName != "richlistitem" && elt != this) {
           elt = elt.parentNode;
         }
         if (!elt || elt.localName != "richlistitem") {
           return;
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -711,17 +711,17 @@ BrowserGlue.prototype = {
     LightweightThemeManager.addBuiltInTheme({
       id: "firefox-compact-dark@mozilla.org",
       name: gBrowserBundle.GetStringFromName("darkTheme.name"),
       description: gBrowserBundle.GetStringFromName("darkTheme.description"),
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
       textcolor: "white",
       accentcolor: "black",
       popup: "#4a4a4f",
-      popup_text: "rgba(249, 249, 250, 0.8)",
+      popup_text: "rgb(249, 249, 250)",
       popup_border: "#27272b",
       author: vendorShortName,
     });
 
     Normandy.init();
 
     // Initialize the default l10n resource sources for L10nRegistry.
     let locales = Services.locale.getPackagedLocales();
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -989,16 +989,18 @@ you can use these alternative items. Oth
 <!ENTITY pageAction.removeFromUrlbar.label "Remove from Address Bar">
 <!ENTITY pageAction.allowInUrlbar.label "Show in Address Bar">
 <!ENTITY pageAction.disallowInUrlbar.label "Don’t Show in Address Bar">
 <!ENTITY pageAction.manageExtension.label "Manage Extension…">
 
 <!ENTITY pageAction.sendTabToDevice.label "Send Tab to Device">
 <!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…">
 
+<!ENTITY pageAction.shareUrl.label "Share">
+
 <!ENTITY libraryButton.tooltip "View history, saved bookmarks, and more">
 
 <!-- LOCALIZATION NOTE: (accessibilityIndicator.tooltip): This is used to
      display a tooltip for accessibility indicator in toolbar/tabbar. It is also
      used as a textual label for the indicator used by assistive technology
      users. -->
 <!ENTITY accessibilityIndicator.tooltip "Accessibility Features Enabled">
 
--- a/browser/modules/BrowserUsageTelemetry.jsm
+++ b/browser/modules/BrowserUsageTelemetry.jsm
@@ -78,16 +78,17 @@ const URLBAR_SELECTED_RESULT_TYPES = {
  * these category names directly when they add to a histogram.
  */
 const URLBAR_SELECTED_RESULT_METHODS = {
   enter: 0,
   enterSelection: 1,
   click: 2,
   arrowEnterSelection: 3,
   tabEnterSelection: 4,
+  rightClickEnter: 5,
 };
 
 
 const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms
 
 
 function getOpenTabsAndWinsCounts() {
   let tabCount = 0;
@@ -560,16 +561,20 @@ let BrowserUsageTelemetry = {
     } else if (highlightedIndex >= 0) {
       switch (userSelectionBehavior) {
       case "tab":
         category = "tabEnterSelection";
         break;
       case "arrow":
         category = "arrowEnterSelection";
         break;
+      case "rightClick":
+        // Selected by right mouse button.
+        category = "rightClickEnter";
+        break;
       default:
         category = "enterSelection";
       }
     } else {
       category = "enter";
     }
     histogram.add(category);
   },
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -92,23 +92,16 @@ var ExtensionsUI = {
         };
         AddonManager.addAddonListener(this.sideloadListener);
       }
 
       for (let addon of sideloaded) {
         this.sideloaded.add(addon);
       }
         this._updateNotifications();
-    } else {
-      // This and all the accompanying about:newaddon code can eventually
-      // be removed.  See bug 1331521.
-      let win = RecentWindow.getMostRecentBrowserWindow();
-      for (let addon of sideloaded) {
-        win.openTrustedLinkIn(`about:newaddon?id=${addon.id}`, "tab");
-      }
     }
   },
 
   async _checkNewDistroAddons() {
     let newDistroAddons = AddonManagerPrivate.getNewDistroAddons();
     if (!newDistroAddons) {
       return;
     }
--- a/browser/modules/PageActions.jsm
+++ b/browser/modules/PageActions.jsm
@@ -1162,16 +1162,35 @@ if (Services.prefs.getBoolPref("identity
     },
     onSubviewShowing(panelViewNode) {
       browserPageActions(panelViewNode).sendToDevice
         .onShowingSubview(panelViewNode);
     },
   });
 }
 
+if (AppConstants.platform == "macosx") {
+  gBuiltInActions.push(
+  // Share URL
+  {
+    id: "shareURL",
+    title: "shareURL-title",
+    onShowingInPanel(buttonNode) {
+      browserPageActions(buttonNode).shareURL.onShowingInPanel(buttonNode);
+    },
+    onPlacedInPanel(buttonNode) {
+      browserPageActions(buttonNode).shareURL.onPlacedInPanel(buttonNode);
+    },
+    wantsSubview: true,
+    onSubviewShowing(panelViewNode) {
+        browserPageActions(panelViewNode).shareURL
+          .onShowingSubview(panelViewNode);
+    },
+  });
+}
 
 /**
  * Gets a BrowserPageActions object in a browser window.
  *
  * @param  obj
  *         Either a DOM node or a browser window.
  * @return The BrowserPageActions object in the browser window related to the
  *         given object.
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js
@@ -47,33 +47,63 @@ let searchInAwesomebar = async function(
                                                 Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH);
 };
 
 /**
  * Click one of the entries in the urlbar suggestion popup.
  *
  * @param {String} entryName
  *        The name of the elemet to click on.
+ * @param {Number} button [optional]
+ *        which button to click.
  */
-function clickURLBarSuggestion(entryName) {
+function clickURLBarSuggestion(entryName, button = 1) {
   // The entry in the suggestion list should follow the format:
   // "<search term> <engine name> Search"
   const expectedSuggestionName = entryName + " " + SUGGESTION_ENGINE_NAME + " Search";
   return BrowserTestUtils.waitForCondition(() => {
     for (let child of gURLBar.popup.richlistbox.children) {
       if (child.label === expectedSuggestionName) {
         // This entry is the search suggestion we're looking for.
-        child.click();
+        if (button == 1)
+          child.click();
+        else if (button == 2) {
+          EventUtils.synthesizeMouseAtCenter(child, {type: "mousedown", button: 2});
+        }
         return true;
       }
     }
     return false;
   }, "Waiting for the expected suggestion to appear");
 }
 
+/**
+ * Create an engine to generate search suggestions and add it as default
+ * for this test.
+ */
+async function withNewSearchEngine(taskFn) {
+  const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
+  let suggestionEngine = await new Promise((resolve, reject) => {
+    Services.search.addEngine(url, null, "", false, {
+      onSuccess(engine) { resolve(engine); },
+      onError() { reject(); }
+    });
+  });
+
+  let previousEngine = Services.search.currentEngine;
+  Services.search.currentEngine = suggestionEngine;
+
+  try {
+    await taskFn(suggestionEngine);
+  } finally {
+    Services.search.currentEngine = previousEngine;
+    Services.search.removeEngine(suggestionEngine);
+  }
+}
+
 add_task(async function setup() {
   // Create a new search engine.
   Services.search.addEngineWithDetails("MozSearch", "", "mozalias", "", "GET",
                                        "http://example.com/?q={searchTerms}");
 
   // Make it the default search engine.
   let engine = Services.search.getEngineByName("MozSearch");
   let originalEngine = Services.search.currentEngine;
@@ -115,17 +145,16 @@ add_task(async function setup() {
     Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
     Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
     await PlacesUtils.history.clear();
     Services.telemetry.setEventRecordingEnabled("navigation", false);
   });
 });
 
 add_task(async function test_simpleQuery() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
 
   let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX");
   let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE");
   let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE");
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
   let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS");
@@ -170,17 +199,16 @@ add_task(async function test_simpleQuery
   checkHistogramResults(resultMethods,
     URLBAR_SELECTED_RESULT_METHODS.enter,
     "FX_URLBAR_SELECTED_RESULT_METHOD");
 
   BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_searchAlias() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
 
   let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX");
   let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE");
   let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE");
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
   let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS");
@@ -227,17 +255,16 @@ add_task(async function test_searchAlias
     "FX_URLBAR_SELECTED_RESULT_METHOD");
 
   BrowserTestUtils.removeTab(tab);
 });
 
 // Performs a search using the first result, a one-off button, and the Return
 // (Enter) key.
 add_task(async function test_oneOff_enter() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
 
   let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX");
   let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE");
   let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE");
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
   let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS");
@@ -288,61 +315,45 @@ add_task(async function test_oneOff_ente
 
   BrowserTestUtils.removeTab(tab);
 });
 
 // Performs a search using the second result, a one-off button, and the Return
 // (Enter) key.  This only tests the FX_URLBAR_SELECTED_RESULT_METHOD histogram
 // since test_oneOff_enter covers everything else.
 add_task(async function test_oneOff_enterSelection() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
-
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  // Create an engine to generate search suggestions and add it as default
-  // for this test.
-  const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
-  let suggestionEngine = await new Promise((resolve, reject) => {
-    Services.search.addEngine(url, null, "", false, {
-      onSuccess(engine) { resolve(engine); },
-      onError() { reject(); }
-    });
-  });
+  await withNewSearchEngine(async function() {
+    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
-  let previousEngine = Services.search.currentEngine;
-  Services.search.currentEngine = suggestionEngine;
-
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+    info("Type a query. Suggestions should be generated by the test engine.");
+    let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+    await searchInAwesomebar("query");
 
-  info("Type a query. Suggestions should be generated by the test engine.");
-  let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  await searchInAwesomebar("query");
+    info("Select the second result, press Alt+Down to take us to the first one-off engine.");
+    EventUtils.synthesizeKey("KEY_ArrowDown");
+    EventUtils.synthesizeKey("KEY_ArrowDown", {altKey: true});
+    EventUtils.synthesizeKey("KEY_Enter");
+    await p;
 
-  info("Select the second result, press Alt+Down to take us to the first one-off engine.");
-  EventUtils.synthesizeKey("KEY_ArrowDown");
-  EventUtils.synthesizeKey("KEY_ArrowDown", {altKey: true});
-  EventUtils.synthesizeKey("KEY_Enter");
-  await p;
+    let resultMethods = resultMethodHist.snapshot();
+    checkHistogramResults(resultMethods,
+      URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection,
+      "FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  let resultMethods = resultMethodHist.snapshot();
-  checkHistogramResults(resultMethods,
-    URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection,
-    "FX_URLBAR_SELECTED_RESULT_METHOD");
-
-  Services.search.currentEngine = previousEngine;
-  Services.search.removeEngine(suggestionEngine);
-  BrowserTestUtils.removeTab(tab);
+    BrowserTestUtils.removeTab(tab);
+  });
 });
 
 // Performs a search using a click on a one-off button.  This only tests the
 // FX_URLBAR_SELECTED_RESULT_METHOD histogram since test_oneOff_enter covers
 // everything else.
 add_task(async function test_oneOff_click() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
 
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
   info("Type a query.");
   let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
@@ -356,202 +367,168 @@ add_task(async function test_oneOff_clic
     URLBAR_SELECTED_RESULT_METHODS.click,
     "FX_URLBAR_SELECTED_RESULT_METHOD");
 
   BrowserTestUtils.removeTab(tab);
 });
 
 // Clicks the first suggestion offered by the test search engine.
 add_task(async function test_suggestion_click() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
 
   let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX");
   let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE");
   let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE");
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
   let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS");
 
-  // Create an engine to generate search suggestions and add it as default
-  // for this test.
-  const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
-  let suggestionEngine = await new Promise((resolve, reject) => {
-    Services.search.addEngine(url, null, "", false, {
-      onSuccess(engine) { resolve(engine); },
-      onError() { reject(); }
-    });
-  });
+  await withNewSearchEngine(async function(engine) {
+    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
-  let previousEngine = Services.search.currentEngine;
-  Services.search.currentEngine = suggestionEngine;
+    info("Type a query. Suggestions should be generated by the test engine.");
+    let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+    await searchInAwesomebar("query");
+    info("Clicking the urlbar suggestion.");
+    await clickURLBarSuggestion("queryfoo");
+    await p;
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+    // Check if the scalars contain the expected values.
+    const scalars = getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true, false);
+    checkKeyedScalar(scalars, SCALAR_URLBAR, "search_suggestion", 1);
+    Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
+                "This search must only increment one entry in the scalar.");
 
-  info("Type a query. Suggestions should be generated by the test engine.");
-  let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  await searchInAwesomebar("query");
-  info("Clicking the urlbar suggestion.");
-  await clickURLBarSuggestion("queryfoo");
-  await p;
-
-  // Check if the scalars contain the expected values.
-  const scalars = getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true, false);
-  checkKeyedScalar(scalars, SCALAR_URLBAR, "search_suggestion", 1);
-  Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
-               "This search must only increment one entry in the scalar.");
+    // Make sure SEARCH_COUNTS contains identical values.
+    let searchEngineId = "other-" + engine.name;
+    checkKeyedHistogram(search_hist, searchEngineId + ".urlbar", 1);
 
-  // Make sure SEARCH_COUNTS contains identical values.
-  let searchEngineId = "other-" + suggestionEngine.name;
-  checkKeyedHistogram(search_hist, searchEngineId + ".urlbar", 1);
+    // Also check events.
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
+    events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
+    checkEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]);
-
-  // Check the histograms as well.
-  let resultIndexes = resultIndexHist.snapshot();
-  checkHistogramResults(resultIndexes, 3, "FX_URLBAR_SELECTED_RESULT_INDEX");
+    // Check the histograms as well.
+    let resultIndexes = resultIndexHist.snapshot();
+    checkHistogramResults(resultIndexes, 3, "FX_URLBAR_SELECTED_RESULT_INDEX");
 
-  let resultTypes = resultTypeHist.snapshot();
-  checkHistogramResults(resultTypes,
-    URLBAR_SELECTED_RESULT_TYPES.searchsuggestion,
-    "FX_URLBAR_SELECTED_RESULT_TYPE");
+    let resultTypes = resultTypeHist.snapshot();
+    checkHistogramResults(resultTypes,
+      URLBAR_SELECTED_RESULT_TYPES.searchsuggestion,
+      "FX_URLBAR_SELECTED_RESULT_TYPE");
 
-  let resultIndexByType = resultIndexByTypeHist.snapshot("searchsuggestion");
-  checkHistogramResults(resultIndexByType,
-    3,
-    "FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE");
+    let resultIndexByType = resultIndexByTypeHist.snapshot("searchsuggestion");
+    checkHistogramResults(resultIndexByType,
+      3,
+      "FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE");
 
-  let resultMethods = resultMethodHist.snapshot();
-  checkHistogramResults(resultMethods,
-    URLBAR_SELECTED_RESULT_METHODS.click,
-    "FX_URLBAR_SELECTED_RESULT_METHOD");
+    let resultMethods = resultMethodHist.snapshot();
+    checkHistogramResults(resultMethods,
+      URLBAR_SELECTED_RESULT_METHODS.click,
+      "FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  Services.search.currentEngine = previousEngine;
-  Services.search.removeEngine(suggestionEngine);
-  BrowserTestUtils.removeTab(tab);
+    BrowserTestUtils.removeTab(tab);
+  });
 });
 
 // Selects and presses the Return (Enter) key on the first suggestion offered by
 // the test search engine.  This only tests the FX_URLBAR_SELECTED_RESULT_METHOD
 // histogram since test_suggestion_click covers everything else.
 add_task(async function test_suggestion_arrowEnterSelection() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
-
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  // Create an engine to generate search suggestions and add it as default
-  // for this test.
-  const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
-  let suggestionEngine = await new Promise((resolve, reject) => {
-    Services.search.addEngine(url, null, "", false, {
-      onSuccess(engine) { resolve(engine); },
-      onError() { reject(); }
-    });
-  });
-
-  let previousEngine = Services.search.currentEngine;
-  Services.search.currentEngine = suggestionEngine;
-
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+  await withNewSearchEngine(async function() {
+    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
-  info("Type a query. Suggestions should be generated by the test engine.");
-  let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  await searchInAwesomebar("query");
-  info("Select the second result and press Return.");
-  EventUtils.synthesizeKey("KEY_ArrowDown");
-  EventUtils.synthesizeKey("KEY_Enter");
-  await p;
+    info("Type a query. Suggestions should be generated by the test engine.");
+    let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+    await searchInAwesomebar("query");
+    info("Select the second result and press Return.");
+    EventUtils.synthesizeKey("KEY_ArrowDown");
+    EventUtils.synthesizeKey("KEY_Enter");
+    await p;
 
-  let resultMethods = resultMethodHist.snapshot();
-  checkHistogramResults(resultMethods,
-    URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection,
-    "FX_URLBAR_SELECTED_RESULT_METHOD");
+    let resultMethods = resultMethodHist.snapshot();
+    checkHistogramResults(resultMethods,
+      URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection,
+      "FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  Services.search.currentEngine = previousEngine;
-  Services.search.removeEngine(suggestionEngine);
-  BrowserTestUtils.removeTab(tab);
+    BrowserTestUtils.removeTab(tab);
+  });
 });
 
 // Selects through tab and presses the Return (Enter) key on the first
 // suggestion offered by the test search engine.
 add_task(async function test_suggestion_tabEnterSelection() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
-
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  // Create an engine to generate search suggestions and add it as default
-  // for this test.
-  const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
-  let suggestionEngine = await new Promise((resolve, reject) => {
-    Services.search.addEngine(url, null, "", false, {
-      onSuccess(engine) { resolve(engine); },
-      onError() { reject(); }
-    });
-  });
-
-  let previousEngine = Services.search.currentEngine;
-  Services.search.currentEngine = suggestionEngine;
-
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+  await withNewSearchEngine(async function() {
+    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
-  info("Type a query. Suggestions should be generated by the test engine.");
-  let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  await searchInAwesomebar("query");
-  info("Select the second result and press Return.");
-  EventUtils.synthesizeKey("KEY_Tab");
-  EventUtils.synthesizeKey("KEY_Enter");
-  await p;
+    info("Type a query. Suggestions should be generated by the test engine.");
+    let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+    await searchInAwesomebar("query");
+    info("Select the second result and press Return.");
+    EventUtils.synthesizeKey("KEY_Tab");
+    EventUtils.synthesizeKey("KEY_Enter");
+    await p;
 
-  let resultMethods = resultMethodHist.snapshot();
-  checkHistogramResults(resultMethods,
-    URLBAR_SELECTED_RESULT_METHODS.tabEnterSelection,
-    "FX_URLBAR_SELECTED_RESULT_METHOD");
+    let resultMethods = resultMethodHist.snapshot();
+    checkHistogramResults(resultMethods,
+      URLBAR_SELECTED_RESULT_METHODS.tabEnterSelection,
+      "FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  Services.search.currentEngine = previousEngine;
-  Services.search.removeEngine(suggestionEngine);
-  BrowserTestUtils.removeTab(tab);
+    BrowserTestUtils.removeTab(tab);
+  });
 });
 
 // Selects through code and presses the Return (Enter) key on the first
 // suggestion offered by the test search engine.
 add_task(async function test_suggestion_enterSelection() {
-  // Let's reset the counts.
   Services.telemetry.clearScalars();
-
   let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
 
-  // Create an engine to generate search suggestions and add it as default
-  // for this test.
-  const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
-  let suggestionEngine = await new Promise((resolve, reject) => {
-    Services.search.addEngine(url, null, "", false, {
-      onSuccess(engine) { resolve(engine); },
-      onError() { reject(); }
-    });
+  await withNewSearchEngine(async function() {
+    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+
+    info("Type a query. Suggestions should be generated by the test engine.");
+    let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+    await searchInAwesomebar("query");
+    info("Select the second result and press Return.");
+    gURLBar.popup.selectedIndex = 1;
+    EventUtils.synthesizeKey("KEY_Enter");
+    await p;
+
+    let resultMethods = resultMethodHist.snapshot();
+    checkHistogramResults(resultMethods,
+      URLBAR_SELECTED_RESULT_METHODS.enterSelection,
+      "FX_URLBAR_SELECTED_RESULT_METHOD");
+
+    BrowserTestUtils.removeTab(tab);
   });
-
-  let previousEngine = Services.search.currentEngine;
-  Services.search.currentEngine = suggestionEngine;
-
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
+});
 
-  info("Type a query. Suggestions should be generated by the test engine.");
-  let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  await searchInAwesomebar("query");
-  info("Select the second result and press Return.");
-  gURLBar.popup.selectedIndex = 1;
-  EventUtils.synthesizeKey("KEY_Enter");
-  await p;
+// Selects through mouse right button and press the Return (Enter) key.
+add_task(async function test_suggestion_rightclick() {
+  Services.telemetry.clearScalars();
+  let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD");
+
+  await withNewSearchEngine(async function() {
+    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
-  let resultMethods = resultMethodHist.snapshot();
-  checkHistogramResults(resultMethods,
-    URLBAR_SELECTED_RESULT_METHODS.enterSelection,
-    "FX_URLBAR_SELECTED_RESULT_METHOD");
+    info("Type a query. Suggestions should be generated by the test engine.");
+    let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+    await searchInAwesomebar("query");
+    info("Right click the the second result and then press Return.");
+    await clickURLBarSuggestion("queryfoo", 2);
+    EventUtils.synthesizeKey("KEY_Enter");
+    await p;
 
-  Services.search.currentEngine = previousEngine;
-  Services.search.removeEngine(suggestionEngine);
-  BrowserTestUtils.removeTab(tab);
+    let resultMethods = resultMethodHist.snapshot();
+    checkHistogramResults(resultMethods,
+      URLBAR_SELECTED_RESULT_METHODS.rightClickEnter,
+      "FX_URLBAR_SELECTED_RESULT_METHOD");
+
+    BrowserTestUtils.removeTab(tab);
+  });
 });
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -330,16 +330,20 @@ html|input.urlbar-input {
 }
 
 .urlbar-display {
   margin-top: 0;
   margin-bottom: 0;
   color: GrayText;
 }
 
+#pageAction-panel-shareURL {
+  list-style-image: url("chrome://browser/skin/share.svg");
+}
+
 %include ../shared/urlbarSearchSuggestionsNotification.inc.css
 
 /* ----- AUTOCOMPLETE ----- */
 
 %include ../shared/autocomplete.inc.css
 %include ../shared/urlbar-autocomplete.inc.css
 
 :root {
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -51,16 +51,17 @@ browser.jar:
   skin/classic/browser/places/livemark-item.png             (places/livemark-item.png)
   skin/classic/browser/preferences/alwaysAsk.png            (preferences/alwaysAsk.png)
   skin/classic/browser/preferences/application.png          (preferences/application.png)
   skin/classic/browser/preferences/saveFile.png             (preferences/saveFile.png)
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/applications.css         (preferences/applications.css)
+  skin/classic/browser/share.svg                            (share.svg)
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabbrowser/tabDragIndicator@2x.png                (tabbrowser/tabDragIndicator@2x.png)
   skin/classic/browser/e10s-64@2x.png                                  (../shared/e10s-64@2x.png)
 
 [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/feeds/audioFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png                 chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
new file mode 100644
--- /dev/null
+++ b/browser/themes/osx/share.svg
@@ -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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M12.707 4.294l-4-4A1 1 0 0 0 8.38.077a.984.984 0 0 0-.246-.05A.938.938 0 0 0 8 0a.938.938 0 0 0-.134.027.984.984 0 0 0-.246.05A1 1 0 0 0 7.291.3l-4 4a1 1 0 0 0 1.416 1.408L7 3.415V11a1 1 0 0 0 2 0V3.415l2.293 2.293a1 1 0 0 0 1.414-1.414z"></path>
+  <path fill="context-fill" d="M14 9a1 1 0 0 0-1 1v3a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-3a1 1 0 0 0-2 0v3a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3v-3a1 1 0 0 0-1-1z"></path>
+</svg>
--- a/devtools/client/framework/components/toolbox-tabs.js
+++ b/devtools/client/framework/components/toolbox-tabs.js
@@ -8,16 +8,19 @@ const dom = require("devtools/client/sha
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const {findDOMNode} = require("devtools/client/shared/vendor/react-dom");
 const {button, div} = dom;
 
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
 const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
 
+// 26px is chevron devtools button width.(i.e. tools-chevronmenu)
+const CHEVRON_BUTTON_WIDTH = 26;
+
 class ToolboxTabs extends Component {
   // See toolbox-toolbar propTypes for details on the props used here.
   static get propTypes() {
     return {
       currentToolId: PropTypes.string,
       focusButton: PropTypes.func,
       focusedButton: PropTypes.string,
       highlightedTools: PropTypes.object,
@@ -27,140 +30,237 @@ class ToolboxTabs extends Component {
       L10N: PropTypes.object,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
-      overflow: false,
+      // Array of overflowed tool id.
+      overflowedTabIds: [],
     };
 
-    this.addFlowEvents = this.addFlowEvents.bind(this);
-    this.removeFlowEvents = this.removeFlowEvents.bind(this);
-    this.onOverflow = this.onOverflow.bind(this);
-    this.onUnderflow = this.onUnderflow.bind(this);
+    // Map with tool Id and its width size. This lifecycle is out of React's
+    // lifecycle. If a tool is registered, ToolboxTabs will add target tool id
+    // to this map. ToolboxTabs will never remove tool id from this cache.
+    this._cachedToolTabsWidthMap = new Map();
+
+    this._resizeTimerId = null;
+    this.resizeHandler = this.resizeHandler.bind(this);
+  }
+
+  componentDidMount() {
+    window.addEventListener("resize", this.resizeHandler);
+    this.updateCachedToolTabsWidthMap();
+    this.updateOverflowedTabs();
+  }
+
+  componentWillUpdate(nextProps, nextState) {
+    if (this.shouldUpdateToolboxTabs(this.props, nextProps)) {
+      // Force recalculate and render in this cycle if panel definition has
+      // changed or selected tool has changed.
+      nextState.overflowedTabIds = [];
+    }
+  }
+
+  componentDidUpdate(prevProps, prevState) {
+    if (this.shouldUpdateToolboxTabs(prevProps, this.props)) {
+      this.updateCachedToolTabsWidthMap();
+      this.updateOverflowedTabs();
+    }
   }
 
-  componentDidUpdate() {
-    this.addFlowEvents();
+  /**
+   * Check if two array of ids are the same or not.
+   */
+  equalToolIdArray(prevPanels, nextPanels) {
+    if (prevPanels.length !== nextPanels.length) {
+      return false;
+    }
+
+    // Check panel definitions even if both of array size is same.
+    // For example, the case of changing the tab's order.
+    return prevPanels.join("-") === nextPanels.join("-");
   }
 
-  componentWillUnmount() {
-    this.removeFlowEvents();
+  /**
+   * Return true if we should update the overflowed tabs.
+   */
+  shouldUpdateToolboxTabs(prevProps, nextProps) {
+    if (prevProps.currentToolId !== nextProps.currentToolId) {
+      return true;
+    }
+
+    let prevPanels = prevProps.panelDefinitions.map(def => def.id);
+    let nextPanels = nextProps.panelDefinitions.map(def => def.id);
+    return !this.equalToolIdArray(prevPanels, nextPanels);
   }
 
-  addFlowEvents() {
-    this.removeFlowEvents();
-    let node = findDOMNode(this);
-    if (node) {
-      node.addEventListener("overflow", this.onOverflow);
-      node.addEventListener("underflow", this.onUnderflow);
+  /**
+   * Update the Map of tool id and tool tab width.
+   */
+  updateCachedToolTabsWidthMap() {
+    let thisNode = findDOMNode(this);
+    for (let tab of thisNode.querySelectorAll(".devtools-tab")) {
+      let tabId = tab.id.replace("toolbox-tab-", "");
+      if (!this._cachedToolTabsWidthMap.has(tabId)) {
+        let cs = getComputedStyle(tab);
+        this._cachedToolTabsWidthMap.set(tabId, parseInt(cs.width, 10));
+      }
     }
   }
 
-  removeFlowEvents() {
+  /**
+   * Update the overflowed tab array from currently displayed tool tab.
+   * If calculated result is the same as the current overflowed tab array, this
+   * function will not update state.
+   */
+  updateOverflowedTabs() {
     let node = findDOMNode(this);
-    if (node) {
-      node.removeEventListener("overflow", this.onOverflow);
-      node.removeEventListener("underflow", this.onUnderflow);
+    const toolboxWidth = parseInt(getComputedStyle(node).width, 10);
+    let { currentToolId } = this.props;
+    let enabledTabs = this.props.panelDefinitions.map(def => def.id);
+    let sumWidth = 0;
+    let visibleTabs = [];
+
+    for (const id of enabledTabs) {
+      let width = this._cachedToolTabsWidthMap.get(id);
+      sumWidth += width;
+      if (sumWidth <= toolboxWidth) {
+        visibleTabs.push(id);
+      } else {
+        sumWidth = sumWidth - width + CHEVRON_BUTTON_WIDTH;
+
+        // If toolbox can't display the Chevron, remove the last tool tab.
+        if (sumWidth > toolboxWidth) {
+          let removeTabId = visibleTabs.pop();
+          sumWidth -= this._cachedToolTabsWidthMap.get(removeTabId);
+        }
+        break;
+      }
+    }
+
+    // If the selected tab is in overflowed tabs, insert it into a visible
+    // toolbox.
+    if (!visibleTabs.includes(currentToolId) &&
+        enabledTabs.includes(currentToolId)) {
+      let selectedToolWidth = this._cachedToolTabsWidthMap.get(currentToolId);
+      while ((sumWidth + selectedToolWidth) > toolboxWidth &&
+             visibleTabs.length > 0) {
+        let removingToolId  = visibleTabs.pop();
+        let removingToolWidth = this._cachedToolTabsWidthMap.get(removingToolId);
+        sumWidth -= removingToolWidth;
+      }
+      visibleTabs.push(currentToolId);
+    }
+
+    if (visibleTabs.length === 0) {
+      visibleTabs = [enabledTabs[0]];
+    }
+
+    let willOverflowTabs = enabledTabs.filter(id => !visibleTabs.includes(id));
+    if (!this.equalToolIdArray(this.state.overflowedTabIds, willOverflowTabs)) {
+      this.setState({ overflowedTabIds: willOverflowTabs });
     }
   }
 
-  onOverflow() {
-    this.setState({
-      overflow: true
-    });
+  resizeHandler(evt) {
+    window.cancelIdleCallback(this._resizeTimerId);
+    this._resizeTimerId = window.requestIdleCallback(() => {
+      this.updateOverflowedTabs();
+    }, { timeout: 300 });
   }
 
-  onUnderflow() {
-    this.setState({
-      overflow: false
+  /**
+   * Render a button to access overflowed tools, displayed only when the toolbar
+   * presents an overflow.
+   */
+  renderToolsChevronButton() {
+    let {
+      panelDefinitions,
+      selectTool,
+      toolbox,
+      L10N,
+    } = this.props;
+
+    return button({
+      className: "devtools-button tools-chevron-menu",
+      tabIndex: -1,
+      title: L10N.getStr("toolbox.allToolsButton.tooltip"),
+      id: "tools-chevron-menu-button",
+      onClick: ({ target }) => {
+        let menu = new Menu({
+          id: "tools-chevron-menupopup"
+        });
+
+        panelDefinitions.forEach(({id, label}) => {
+          if (this.state.overflowedTabIds.includes(id)) {
+            menu.append(new MenuItem({
+              click: () => {
+                selectTool(id);
+              },
+              id: "tools-chevron-menupopup-" + id,
+              label,
+              type: "checkbox",
+            }));
+          }
+        });
+
+        let rect = target.getBoundingClientRect();
+        let screenX = target.ownerDocument.defaultView.mozInnerScreenX;
+        let screenY = target.ownerDocument.defaultView.mozInnerScreenY;
+
+        // Display the popup below the button.
+        menu.popup(rect.left + screenX, rect.bottom + screenY, toolbox);
+        return menu;
+      },
     });
   }
 
   /**
    * Render all of the tabs, based on the panel definitions and builds out
-   * a toolbox tab for each of them. Will render an all-tabs button if the
+   * a toolbox tab for each of them. Will render the chevron button if the
    * container has an overflow.
    */
   render() {
     let {
       currentToolId,
       focusButton,
       focusedButton,
       highlightedTools,
       panelDefinitions,
       selectTool,
     } = this.props;
 
-    let tabs = panelDefinitions.map(panelDefinition => ToolboxTab({
-      key: panelDefinition.id,
-      currentToolId,
-      focusButton,
-      focusedButton,
-      highlightedTools,
-      panelDefinition,
-      selectTool,
-    }));
+    let tabs = panelDefinitions.map(panelDefinition => {
+      // Don't display overflowed tab.
+      if (!this.state.overflowedTabIds.includes(panelDefinition.id)) {
+        return ToolboxTab({
+          key: panelDefinition.id,
+          currentToolId,
+          focusButton,
+          focusedButton,
+          highlightedTools,
+          panelDefinition,
+          selectTool,
+        });
+      }
+      return null;
+    });
 
-    // A wrapper is needed to get flex sizing correct in XUL.
     return div(
       {
         className: "toolbox-tabs-wrapper"
       },
       div(
         {
           className: "toolbox-tabs"
         },
-        tabs
-      ),
-      this.state.overflow ? renderAllToolsButton(this.props) : null
+        tabs,
+        (this.state.overflowedTabIds.length > 0)
+          ? this.renderToolsChevronButton() : null
+      )
     );
   }
 }
 
 module.exports = ToolboxTabs;
-
-/**
- * Render a button to access all tools, displayed only when the toolbar presents an
- * overflow.
- */
-function renderAllToolsButton(props) {
-  let {
-    currentToolId,
-    panelDefinitions,
-    selectTool,
-    toolbox,
-    L10N,
-  } = props;
-
-  return button({
-    className: "all-tools-menu all-tabs-menu",
-    tabIndex: -1,
-    title: L10N.getStr("toolbox.allToolsButton.tooltip"),
-    onClick: ({ target }) => {
-      let menu = new Menu({
-        id: "all-tools-menupopup"
-      });
-      panelDefinitions.forEach(({id, label}) => {
-        menu.append(new MenuItem({
-          checked: currentToolId === id,
-          click: () => {
-            selectTool(id);
-          },
-          id: "all-tools-menupopup-" + id,
-          label,
-          type: "checkbox",
-        }));
-      });
-
-      let rect = target.getBoundingClientRect();
-      let screenX = target.ownerDocument.defaultView.mozInnerScreenX;
-      let screenY = target.ownerDocument.defaultView.mozInnerScreenY;
-
-      // Display the popup below the button.
-      menu.popup(rect.left + screenX, rect.bottom + screenY, toolbox);
-      return menu;
-    },
-  });
-}
--- a/devtools/client/framework/components/toolbox-toolbar.js
+++ b/devtools/client/framework/components/toolbox-toolbar.js
@@ -2,17 +2,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/. */
 "use strict";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const {div, button} = dom;
-const {openTrustedLink} = require("devtools/client/shared/link");
+const {openWebLink} = require("devtools/client/shared/link");
 
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
 const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
 const ToolboxTabs = createFactory(require("devtools/client/framework/components/toolbox-tabs"));
 
 /**
  * This is the overall component for the toolbox toolbar. It is designed to not know how
@@ -172,26 +172,26 @@ function renderToolboxButtons({focusedBu
           onKeyDown(event);
         }
       });
     });
 
   // Add the appropriate separator, if needed.
   let children = renderedButtons;
   if (renderedButtons.length) {
+    if (isStart) {
+      children.push(renderSeparator());
     // For the end group we add a separator *before* the RDM button if it
-    // exists.
-    if (rdmIndex !== -1) {
+    // exists, but only if it is not the only button.
+    } else if (rdmIndex !== -1 && visibleButtons.length > 1) {
       children.splice(
         children.length - 1,
         0,
         renderSeparator()
       );
-    } else {
-      children.push(renderSeparator());
     }
   }
 
   return div({id: `toolbox-buttons-${isStart ? "start" : "end"}`}, ...children);
 }
 
 /**
  * Render a separator.
@@ -389,29 +389,29 @@ function showMeatballMenu(
   }));
 
   if (menu.items.length) {
     menu.append(new MenuItem({ type: "separator" }));
   }
 
   // Getting started
   menu.append(new MenuItem({
-    id: "toolbox-meatball-menu-gettingstarted",
-    label: L10N.getStr("toolbox.meatballMenu.gettingStarted.label"),
+    id: "toolbox-meatball-menu-documentation",
+    label: L10N.getStr("toolbox.meatballMenu.documentation.label"),
     click: () => {
-      openTrustedLink("https://developer.mozilla.org/docs/Tools", toolbox);
+      openWebLink("https://developer.mozilla.org/docs/Tools", toolbox);
     },
   }));
 
   // Give feedback
   menu.append(new MenuItem({
-    id: "toolbox-meatball-menu-feedback",
-    label: L10N.getStr("toolbox.meatballMenu.giveFeedback.label"),
+    id: "toolbox-meatball-menu-community",
+    label: L10N.getStr("toolbox.meatballMenu.community.label"),
     click: () => {
-      openTrustedLink("https://discourse.mozilla.org/c/devtools", toolbox);
+      openWebLink("https://discourse.mozilla.org/c/devtools", toolbox);
     },
   }));
 
   const rect = menuButton.getBoundingClientRect();
   const screenX = menuButton.ownerDocument.defaultView.mozInnerScreenX;
   const screenY = menuButton.ownerDocument.defaultView.mozInnerScreenY;
 
   // Display the popup below the button.
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -108,18 +108,18 @@ skip-if = e10s # Bug 1069044 - destroyIn
 [browser_toolbox_telemetry_close.js]
 [browser_toolbox_textbox_context_menu.js]
 [browser_toolbox_theme.js]
 [browser_toolbox_theme_registration.js]
 [browser_toolbox_toggle.js]
 [browser_toolbox_tool_ready.js]
 [browser_toolbox_tool_remote_reopen.js]
 [browser_toolbox_toolbar_overflow.js]
+[browser_toolbox_toolbar_reorder_by_width.js]
 [browser_toolbox_tools_per_toolbox_registration.js]
-[browser_toolbox_transport_events.js]
 [browser_toolbox_view_source_01.js]
 [browser_toolbox_view_source_02.js]
 [browser_toolbox_view_source_03.js]
 [browser_toolbox_view_source_04.js]
 [browser_toolbox_window_reload_target.js]
 [browser_toolbox_window_shortcuts.js]
 skip-if = os == "mac" && os_version == "10.8" || os == "win" && os_version == "5.1" # Bug 851129 - Re-enable browser_toolbox_window_shortcuts.js test after leaks are fixed
 [browser_toolbox_window_title_changes.js]
--- a/devtools/client/framework/test/browser_toolbox_options.js
+++ b/devtools/client/framework/test/browser_toolbox_options.js
@@ -15,16 +15,17 @@ const {PrefObserver} = require("devtools
 
 add_task(async function() {
   const URL = "data:text/html;charset=utf8,test for dynamically registering " +
               "and unregistering tools";
   registerNewTool();
   let tab = await addTab(URL);
   let target = TargetFactory.forTab(tab);
   toolbox = await gDevTools.showToolbox(target);
+
   doc = toolbox.doc;
   await registerNewPerToolboxTool();
   await testSelectTool();
   await testOptionsShortcut();
   await testOptions();
   await testToggleTools();
 
   // Test that registered WebExtensions becomes entries in the
@@ -424,21 +425,21 @@ function checkUnregistered(toolId, defer
     ok(!doc.getElementById("toolbox-tab-" + toolId),
       "Tab removed for " + toolId);
   } else {
     ok(false, "Something went wrong, " + toolId + " was not unregistered");
   }
   deferred.resolve();
 }
 
-function checkRegistered(toolId, deferred, data) {
+async function checkRegistered(toolId, deferred, data) {
   if (data == toolId) {
     ok(true, "Correct tool added back");
     // checking tab on the toolbox
-    let button = doc.getElementById("toolbox-tab-" + toolId);
+    let button = await lookupButtonForToolId(toolId);
     ok(button, "Tab added back for " + toolId);
   } else {
     ok(false, "Something went wrong, " + toolId + " was not registered");
   }
   deferred.resolve();
 }
 
 function GetPref(name) {
@@ -450,16 +451,36 @@ function GetPref(name) {
       return Services.prefs.getIntPref(name);
     case Services.prefs.PREF_BOOL:
       return Services.prefs.getBoolPref(name);
     default:
       throw new Error("Unknown type");
   }
 }
 
+/**
+ * Find the button from specified toolId.
+ * Generally, button which access to the tool panel is in toolbox or
+ * tools menu(in the Chevron menu).
+ */
+async function lookupButtonForToolId(toolId) {
+  let button = doc.getElementById("toolbox-tab-" + toolId);
+  if (!button) {
+    // search from the tools menu.
+    let menuPopup = await openChevronMenu(toolbox);
+    button = doc.querySelector("#tools-chevron-menupopup-" + toolId);
+
+    info("Closing the tools-chevron-menupopup popup");
+    let onPopupHidden = once(menuPopup, "popuphidden");
+    menuPopup.hidePopup();
+    await onPopupHidden;
+  }
+  return button;
+}
+
 async function cleanup() {
   gDevTools.unregisterTool("test-tool");
   await toolbox.destroy();
   gBrowser.removeCurrentTab();
   for (let pref of modifiedPrefs) {
     Services.prefs.clearUserPref(pref);
   }
   toolbox = doc = panelWin = modifiedPrefs = null;
--- a/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
@@ -1,17 +1,22 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript 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_URL = "data:text/html;charset=utf8,test for dynamically " +
-                 "registering and unregistering tools";
+let TEST_URL = "data:text/html;charset=utf8,test for dynamically " +
+               "registering and unregistering tools";
+
+// The frames button is only shown if the page has at least one iframe so we
+// need to add one to the test page.
+TEST_URL += "<iframe src=\"data:text/plain,iframe\"></iframe>";
+
 var doc = null, toolbox = null, panelWin = null, modifiedPrefs = [];
 
 function test() {
   addTab(TEST_URL).then(tab => {
     let target = TargetFactory.forTab(tab);
     gDevTools.showToolbox(target)
       .then(testSelectTool)
       .then(testToggleToolboxButtons)
@@ -55,53 +60,43 @@ function testSelectTool(devtoolsToolbox)
   return deferred.promise;
 }
 
 function testPreferenceAndUIStateIsConsistent() {
   let checkNodes = [...panelWin.document.querySelectorAll(
     "#enabled-toolbox-buttons-box input[type=checkbox]")];
   let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
 
-  // The noautohide button is only displayed in the browser toolbox
-  let toolbarButtons = toolbox.toolbarButtons.filter(
-    tool => tool.id != "command-button-noautohide");
-
-  for (let tool of toolbarButtons) {
+  for (let tool of toolbox.toolbarButtons) {
     let isVisible = getBoolPref(tool.visibilityswitch);
 
     let button = toolboxButtonNodes.find(toolboxButton => toolboxButton.id === tool.id);
     is(!!button, isVisible,
       "Button visibility matches pref for " + tool.id);
 
     let check = checkNodes.filter(node => node.id === tool.id)[0];
     is(check.checked, isVisible,
       "Checkbox should be selected based on current pref for " + tool.id);
   }
 }
 
 function testToggleToolboxButtons() {
   let checkNodes = [...panelWin.document.querySelectorAll(
     "#enabled-toolbox-buttons-box input[type=checkbox]")];
 
-  // The noautohide button is only displayed in the browser toolbox, and the element
-  // picker button is not toggleable.
-  let toolbarButtons = toolbox.toolbarButtons.filter(
-    tool => tool.id != "command-button-noautohide");
-
   let visibleToolbarButtons = toolbox.toolbarButtons.filter(tool => tool.isVisible);
 
-  let toolbarButtonNodes = [...doc.querySelectorAll(".command-button")].filter(
-    btn => btn.id != "command-button-noautohide");
+  let toolbarButtonNodes = [...doc.querySelectorAll(".command-button")];
 
-  is(checkNodes.length, toolbarButtons.length,
+  is(checkNodes.length, toolbox.toolbarButtons.length,
     "All of the buttons are toggleable.");
   is(visibleToolbarButtons.length, toolbarButtonNodes.length,
     "All of the DOM buttons are toggleable.");
 
-  for (let tool of toolbarButtons) {
+  for (let tool of toolbox.toolbarButtons) {
     let id = tool.id;
     let matchedCheckboxes = checkNodes.filter(node => node.id === id);
     let matchedButtons = toolbarButtonNodes.filter(button => button.id === id);
     is(matchedCheckboxes.length, 1,
       "There should be a single toggle checkbox for: " + id);
     if (tool.isVisible) {
       is(matchedButtons.length, 1,
         "There should be a DOM button for the visible: " + id);
@@ -112,24 +107,24 @@ function testToggleToolboxButtons() {
         "There should not be a DOM button for the invisible: " + id);
     }
 
     is(matchedCheckboxes[0].nextSibling.textContent, tool.description,
       "The label for checkbox matches the tool definition.");
   }
 
   // Store modified pref names so that they can be cleared on error.
-  for (let tool of toolbarButtons) {
+  for (let tool of toolbox.toolbarButtons) {
     let pref = tool.visibilityswitch;
     modifiedPrefs.push(pref);
   }
 
   // Try checking each checkbox, making sure that it changes the preference
   for (let node of checkNodes) {
-    let tool = toolbarButtons.filter(
+    let tool = toolbox.toolbarButtons.filter(
       commandButton => commandButton.id === node.id)[0];
     let isVisible = getBoolPref(tool.visibilityswitch);
 
     testPreferenceAndUIStateIsConsistent();
     node.click();
     testPreferenceAndUIStateIsConsistent();
 
     let isVisibleAfterClick = getBoolPref(tool.visibilityswitch);
--- a/devtools/client/framework/test/browser_toolbox_toolbar_overflow.js
+++ b/devtools/client/framework/test/browser_toolbox_toolbar_overflow.js
@@ -7,80 +7,67 @@
 
 // Test that a button to access tools hidden by toolbar overflow is displayed when the
 // toolbar starts to present an overflow.
 let { Toolbox } = require("devtools/client/framework/toolbox");
 
 add_task(async function() {
   let tab = await addTab("about:blank");
 
-  info("Open devtools on the Inspector in a separate window");
-  let toolbox = await openToolboxForTab(tab, "inspector", Toolbox.HostType.WINDOW);
+  info("Open devtools on the Inspector in a bottom dock");
+  let toolbox = await openToolboxForTab(tab, "inspector", Toolbox.HostType.BOTTOM);
 
   let hostWindow = toolbox.win.parent;
   let originalWidth = hostWindow.outerWidth;
   let originalHeight = hostWindow.outerHeight;
 
   info("Resize devtools window to a width that should not trigger any overflow");
   let onResize = once(hostWindow, "resize");
-  hostWindow.resizeTo(640, 300);
+  hostWindow.resizeTo(1350, 300);
   await onResize;
+  waitUntil(() => {
+    // Wait for all buttons are displayed.
+    return toolbox.panelDefinitions.length !==
+      toolbox.doc.querySelectorAll(".devtools-tab").length;
+  });
 
-  let allToolsButton = toolbox.doc.querySelector(".all-tools-menu");
-  ok(!allToolsButton, "The all tools button is not displayed");
+  let chevronMenuButton = toolbox.doc.querySelector(".tools-chevron-menu");
+  ok(!chevronMenuButton, "The chevron menu button is not displayed");
 
   info("Resize devtools window to a width that should trigger an overflow");
   onResize = once(hostWindow, "resize");
-  hostWindow.resizeTo(300, 300);
+  hostWindow.resizeTo(800, 300);
   await onResize;
-
-  info("Wait until the all tools button is available");
-  await waitUntil(() => toolbox.doc.querySelector(".all-tools-menu"));
+  waitUntil(() => !toolbox.doc.querySelector(".tools-chevron-menu"));
 
-  allToolsButton = toolbox.doc.querySelector(".all-tools-menu");
-  ok(allToolsButton, "The all tools button is displayed");
+  info("Wait until the chevron menu button is available");
+  await waitUntil(() => toolbox.doc.querySelector(".tools-chevron-menu"));
 
-  info("Open the all-tools-menupopup and verify that the inspector button is checked");
-  let menuPopup = await openAllToolsMenu(toolbox);
+  chevronMenuButton = toolbox.doc.querySelector(".tools-chevron-menu");
+  ok(chevronMenuButton, "The chevron menu button is displayed");
+
+  info("Open the tools-chevron-menupopup and verify that the inspector button is checked");
+  let menuPopup = await openChevronMenu(toolbox);
 
-  let inspectorButton = toolbox.doc.querySelector("#all-tools-menupopup-inspector");
-  ok(inspectorButton, "The inspector button is available");
-  ok(inspectorButton.getAttribute("checked"), "The inspector button is checked");
+  let inspectorButton = toolbox.doc.querySelector("#tools-chevron-menupopup-inspector");
+  ok(!inspectorButton, "The chevron menu doesn't have the inspector button.");
+
+  let consoleButton = toolbox.doc.querySelector("#tools-chevron-menupopup-webconsole");
+  ok(!consoleButton, "The chevron menu doesn't have the console button.");
 
-  let consoleButton = toolbox.doc.querySelector("#all-tools-menupopup-webconsole");
-  ok(consoleButton, "The console button is available");
-  ok(!consoleButton.getAttribute("checked"), "The console button is not checked");
+  let storageButton = toolbox.doc.querySelector("#tools-chevron-menupopup-storage");
+  ok(storageButton, "The chevron menu has the storage button.");
 
-  info("Switch to the webconsole using the all-tools-menupopup popup");
-  let onSelected = toolbox.once("webconsole-selected");
-  consoleButton.click();
+  info("Switch to the performance using the tools-chevron-menupopup popup");
+  let onSelected = toolbox.once("storage-selected");
+  storageButton.click();
   await onSelected;
 
-  info("Closing the all-tools-menupopup popup");
+  info("Closing the tools-chevron-menupopup popup");
   let onPopupHidden = once(menuPopup, "popuphidden");
   menuPopup.hidePopup();
   await onPopupHidden;
 
-  info("Re-open the all-tools-menupopup and verify that the console button is checked");
-  menuPopup = await openAllToolsMenu(toolbox);
-
-  inspectorButton = toolbox.doc.querySelector("#all-tools-menupopup-inspector");
-  ok(!inspectorButton.getAttribute("checked"), "The inspector button is not checked");
-
-  consoleButton = toolbox.doc.querySelector("#all-tools-menupopup-webconsole");
-  ok(consoleButton.getAttribute("checked"), "The console button is checked");
-
   info("Restore the original window size");
+  onResize = once(hostWindow, "resize");
   hostWindow.resizeTo(originalWidth, originalHeight);
+  await onResize;
 });
-
-async function openAllToolsMenu(toolbox) {
-  let allToolsButton = toolbox.doc.querySelector(".all-tools-menu");
-  EventUtils.synthesizeMouseAtCenter(allToolsButton, {}, toolbox.win);
-
-  let menuPopup = toolbox.doc.querySelector("#all-tools-menupopup");
-  ok(menuPopup, "all-tools-menupopup is available");
-
-  info("Waiting for the menu popup to be displayed");
-  await waitUntil(() => menuPopup && menuPopup.state === "open");
-
-  return menuPopup;
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/browser_toolbox_toolbar_reorder_by_width.js
@@ -0,0 +1,106 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// This test will:
+//
+// * Confirm that currently selected button to access tools will not hide due to overflow.
+//   In this case, a button which is located on the left of a currently selected will hide.
+// * Confirm that a button to access tool will hide when registering a new panel.
+//
+// Note that this test is based on the tab ordinal is fixed.
+// i.e. After changed by Bug 1226272, this test might fail.
+
+let { Toolbox } = require("devtools/client/framework/toolbox");
+
+add_task(async function() {
+  let tab = await addTab("about:blank");
+
+  info("Open devtools on the Storage in a sidebar.");
+  let toolbox = await openToolboxForTab(tab, "storage", Toolbox.HostType.BOTTOM);
+
+  info("Waiting for the window to be resized");
+  let {hostWin, originalWidth, originalHeight} = await resizeWindow(toolbox, 800);
+
+  info("Wait until the tools menu button is available");
+  await waitUntil(() => toolbox.doc.querySelector(".tools-chevron-menu"));
+
+  let toolsMenuButton = toolbox.doc.querySelector(".tools-chevron-menu");
+  ok(toolsMenuButton, "The tools menu button is displayed");
+
+  info("Confirm that selected tab is not hidden.");
+  let storageButton = toolbox.doc.querySelector("#toolbox-tab-storage");
+  ok(storageButton, "The storage tab is on toolbox.");
+
+  await resizeWindow(toolbox, originalWidth, originalHeight);
+});
+
+add_task(async function() {
+  let tab = await addTab("about:blank");
+
+  info("Open devtools on the Storage in a sidebar.");
+  let toolbox = await openToolboxForTab(tab, "storage", Toolbox.HostType.BOTTOM);
+
+  info("Resize devtools window to a width that should trigger an overflow");
+  let {hostWin, originalWidth, originalHeight} = await resizeWindow(toolbox, 800);
+
+  info("Regist a new tab");
+  let onRegistered = toolbox.once("tool-registered");
+  gDevTools.registerTool({
+    id: "test-tools",
+    label: "Test Tools",
+    isMenu: true,
+    isTargetSupported: () => true,
+    build: function() {},
+  });
+  await onRegistered;
+
+  info("Open the tools menu button.");
+  let popup = await openChevronMenu(toolbox);
+
+  info("The registered new tool tab should be in the tools menu.");
+  let testToolsButton = toolbox.doc.querySelector("#tools-chevron-menupopup-test-tools");
+  ok(testToolsButton, "The tools menu has a registered new tool button.");
+
+  info("Closing the tools-chevron-menupopup popup");
+  let onPopupHidden = once(popup, "popuphidden");
+  popup.hidePopup();
+  await onPopupHidden;
+
+  info("Unregistering test-tools");
+  let onUnregistered = toolbox.once("tool-unregistered");
+  gDevTools.unregisterTool("test-tools");
+  await onUnregistered;
+
+  info("Open the tools menu button.");
+  popup = await openChevronMenu(toolbox);
+
+  info("An unregistered new tool tab should not be in the tools menu.");
+  testToolsButton = toolbox.doc.querySelector("#tools-chevron-menupopup-test-tools");
+  ok(!testToolsButton, "The tools menu doesn't have a unregistered new tool button.");
+
+  info("Closing the tools-chevron-menupopup popup");
+  onPopupHidden = once(popup, "popuphidden");
+  popup.hidePopup();
+  await onPopupHidden;
+
+  await resizeWindow(toolbox, originalWidth, originalHeight);
+});
+
+async function resizeWindow(toolbox, width, height) {
+  let hostWindow = toolbox.win.parent;
+  let originalWidth = hostWindow.outerWidth;
+  let originalHeight = hostWindow.outerHeight;
+  let toWidth = width || originalWidth;
+  let toHeight = height || originalHeight;
+
+  info("Resize devtools window to a width that should trigger an overflow");
+  let onResize = once(hostWindow, "resize");
+  hostWindow.resizeTo(toWidth, toHeight);
+  await onResize;
+
+  return {hostWindow, originalWidth, originalHeight};
+}
deleted file mode 100644
--- a/devtools/client/framework/test/browser_toolbox_transport_events.js
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript 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 { on, off } = require("devtools/shared/event-emitter");
-const { DebuggerClient } = require("devtools/shared/client/debugger-client");
-
-function test() {
-  gDevTools.on("toolbox-created", onToolboxCreated);
-  on(DebuggerClient, "connect", onDebuggerClientConnect);
-
-  addTab("about:blank").then(function() {
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    gDevTools.showToolbox(target, "webconsole").then(testResults);
-  });
-}
-
-function testResults(toolbox) {
-  testPackets(sent1, received1);
-  testPackets(sent2, received2);
-
-  cleanUp(toolbox);
-}
-
-function cleanUp(toolbox) {
-  gDevTools.off("toolbox-created", onToolboxCreated);
-  off(DebuggerClient, "connect", onDebuggerClientConnect);
-
-  toolbox.destroy().then(function() {
-    // TODO: fixme.
-    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
-    setTimeout(() => {
-      gBrowser.removeCurrentTab();
-      executeSoon(function() {
-        finish();
-      });
-    }, 1000);
-  });
-}
-
-function testPackets(sent, received) {
-  ok(sent.length > 0, "There must be at least one sent packet");
-  ok(received.length > 0, "There must be at leaset one received packet");
-
-  if (!sent.length || received.length) {
-    return;
-  }
-
-  let sentPacket = sent[0];
-  let receivedPacket = received[0];
-
-  is(receivedPacket.from, "root",
-    "The first received packet is from the root");
-  is(receivedPacket.applicationType, "browser",
-    "The first received packet has browser type");
-  is(sentPacket.type, "listTabs",
-    "The first sent packet is for list of tabs");
-}
-
-// Listen to the transport object that is associated with the
-// default Toolbox debugger client
-var sent1 = [];
-var received1 = [];
-
-function send1(packet) {
-  sent1.push(packet);
-}
-
-function onPacket1(packet) {
-  received1.push(packet);
-}
-
-function onToolboxCreated(toolbox) {
-  toolbox.target.makeRemote();
-  let client = toolbox.target.client;
-  let transport = client._transport;
-
-  transport.on("send", send1);
-  transport.on("packet", onPacket1);
-
-  client.addOneTimeListener("closed", () => {
-    transport.off("send", send1);
-    transport.off("packet", onPacket1);
-  });
-}
-
-// Listen to all debugger client object protocols.
-var sent2 = [];
-var received2 = [];
-
-function send2(packet) {
-  sent2.push(packet);
-}
-
-function onPacket2(packet) {
-  received2.push(packet);
-}
-
-function onDebuggerClientConnect(client) {
-  let transport = client._transport;
-
-  transport.on("send", send2);
-  transport.on("packet", onPacket2);
-
-  client.addOneTimeListener("closed", () => {
-    transport.off("send", send2);
-    transport.off("packet", onPacket2);
-  });
-}
--- a/devtools/client/framework/test/head.js
+++ b/devtools/client/framework/test/head.js
@@ -242,8 +242,21 @@ DevToolPanel.prototype = {
 
 /**
  * Create a simple devtools test panel that implements the minimum API needed to be
  * registered and opened in the toolbox.
  */
 function createTestPanel(iframeWindow, toolbox) {
   return new DevToolPanel(iframeWindow, toolbox);
 }
+
+async function openChevronMenu(toolbox) {
+  let chevronMenuButton = toolbox.doc.querySelector(".tools-chevron-menu");
+  EventUtils.synthesizeMouseAtCenter(chevronMenuButton, {}, toolbox.win);
+
+  let menuPopup = toolbox.doc.querySelector("#tools-chevron-menupopup");
+  ok(menuPopup, "tools-chevron-menupopup is available");
+
+  info("Waiting for the menu popup to be displayed");
+  await waitUntil(() => menuPopup && menuPopup.state === "open");
+
+  return menuPopup;
+}
--- a/devtools/client/framework/toolbox-options.js
+++ b/devtools/client/framework/toolbox-options.js
@@ -179,17 +179,17 @@ OptionsPanel.prototype = {
 
     let createCommandCheckbox = button => {
       let checkboxLabel = this.panelDoc.createElement("label");
       let checkboxSpanLabel = this.panelDoc.createElement("span");
       checkboxSpanLabel.textContent = button.description;
       let checkboxInput = this.panelDoc.createElement("input");
       checkboxInput.setAttribute("type", "checkbox");
       checkboxInput.setAttribute("id", button.id);
-      if (button.isVisible) {
+      if (Services.prefs.getBoolPref(button.visibilityswitch, true)) {
         checkboxInput.setAttribute("checked", true);
       }
       checkboxInput.addEventListener("change",
         onCheckboxClick.bind(this, checkboxInput));
 
       checkboxLabel.appendChild(checkboxInput);
       checkboxLabel.appendChild(checkboxSpanLabel);
       return checkboxLabel;
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -761,32 +761,35 @@ Toolbox.prototype = {
    *                       argument, to be called whenever the checked state changes.
    * @property {Function} teardown - Function run on toolbox close to let a chance to
    *                      unregister listeners set when `setup` was called and avoid
    *                      memory leaks. The same arguments than `setup` function are
    *                      passed to `teardown`.
    * @property {Function} isTargetSupported - Function to automatically enable/disable
    *                      the button based on the target. If the target don't support
    *                      the button feature, this method should return false.
+   * @property {Function} isCurrentlyVisible - Function to automatically
+   *                      hide/show the button based on current state.
    * @property {Function} isChecked - Optional function called to known if the button
    *                      is toggled or not. The function should return true when
    *                      the button should be displayed as toggled on.
    */
   _createButtonState: function(options) {
     let isCheckedValue = false;
     const {
       id,
       className,
       description,
       disabled,
       onClick,
       isInStartContainer,
       setup,
       teardown,
       isTargetSupported,
+      isCurrentlyVisible,
       isChecked,
       onKeyDown
     } = options;
     const toolbox = this;
     const button = {
       id,
       className,
       description,
@@ -797,16 +800,17 @@ Toolbox.prototype = {
         }
       },
       onKeyDown(event) {
         if (typeof onKeyDown == "function") {
           onKeyDown(event, toolbox);
         }
       },
       isTargetSupported,
+      isCurrentlyVisible,
       get isChecked() {
         if (typeof isChecked == "function") {
           return isChecked(toolbox);
         }
         return isCheckedValue;
       },
       set isChecked(value) {
         // Note that if options.isChecked is given, this is ignored
@@ -1235,16 +1239,19 @@ Toolbox.prototype = {
   _buildFrameButton() {
     this.frameButton = this._createButtonState({
       id: "command-button-frames",
       description: L10N.getStr("toolbox.frames.tooltip"),
       onClick: this.showFramesMenu,
       isTargetSupported: target => {
         return target.activeTab && target.activeTab.traits.frames;
       },
+      isCurrentlyVisible: () => {
+        return this.frameMap.size > 1;
+      },
       onKeyDown: this.handleKeyDownOnFramesButton
     });
 
     return this.frameButton;
   },
 
   /**
    * Toggle the picker, but also decide whether or not the highlighter should
@@ -1376,26 +1383,33 @@ Toolbox.prototype = {
   },
 
   /**
    * Ensure the visibility of each toolbox button matches the preference value.
    */
   _commandIsVisible: function(button) {
     const {
       isTargetSupported,
+      isCurrentlyVisible,
       visibilityswitch
     } = button;
 
-    let visible = Services.prefs.getBoolPref(visibilityswitch, true);
-
-    if (isTargetSupported) {
-      return visible && isTargetSupported(this.target);
+    if (!Services.prefs.getBoolPref(visibilityswitch, true)) {
+      return false;
+    }
+
+    if (isTargetSupported && !isTargetSupported(this.target)) {
+      return false;
     }
 
-    return visible;
+    if (isCurrentlyVisible && !isCurrentlyVisible()) {
+      return false;
+    }
+
+    return true;
   },
 
   /**
    * Build a panel for a tool definition.
    *
    * @param {string} toolDefinition
    *        Tool definition of the tool to build a tab for.
    */
@@ -2247,20 +2261,16 @@ Toolbox.prototype = {
    *                 id {Number}: frame ID
    *                 url {String}: frame URL
    *                 title {String}: frame title
    *                 destroy {Boolean}: Set to true if destroyed
    *                 parentID {Number}: ID of the parent frame (not set
    *                                    for top level window)
    */
   _updateFrames: function(data) {
-    if (!Services.prefs.getBoolPref("devtools.command-button-frames.enabled")) {
-      return;
-    }
-
     // We may receive this event before the toolbox is ready.
     if (!this.isReady) {
       return;
     }
 
     // Store (synchronize) data about all existing frames on the backend
     if (data.destroyAll) {
       this.frameMap.clear();
@@ -2297,16 +2307,20 @@ Toolbox.prototype = {
     let topFrameSelected = frame ? !frame.parentID : false;
     this._framesButtonChecked = false;
 
     // If non-top level frame is selected the toolbar button is
     // marked as 'checked' indicating that a child frame is active.
     if (!topFrameSelected && this.selectedFrameId) {
       this._framesButtonChecked = false;
     }
+
+    // We may need to hide/show the frames button now.
+    this.frameButton.isVisible = this._commandIsVisible(this.frameButton);
+    this.component.setToolboxButtons(this.toolbarButtons);
   },
 
   /**
    * Returns a 0-based selected frame depth.
    *
    * For example, if the root frame is selected, the returned value is 0.  For a sub-frame
    * of the root document, the returned value is 1, and so on.
    */
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -145,16 +145,17 @@ devtools.jar:
     skin/images/command-screenshot.svg (themes/images/command-screenshot.svg)
     skin/images/command-responsivemode.svg (themes/images/command-responsivemode.svg)
     skin/images/command-pick.svg (themes/images/command-pick.svg)
     skin/images/command-pick-accessibility.svg (themes/images/command-pick-accessibility.svg)
     skin/images/command-frames.svg (themes/images/command-frames.svg)
     skin/images/command-eyedropper.svg (themes/images/command-eyedropper.svg)
     skin/images/command-rulers.svg (themes/images/command-rulers.svg)
     skin/images/command-measure.svg (themes/images/command-measure.svg)
+    skin/images/command-chevron.svg (themes/images/command-chevron.svg)
     skin/markup.css (themes/markup.css)
     skin/images/editor-error.png (themes/images/editor-error.png)
     skin/images/breakpoint.svg (themes/images/breakpoint.svg)
     skin/webconsole.css (themes/webconsole.css)
     skin/images/webconsole.svg (themes/images/webconsole.svg)
     skin/images/breadcrumbs-scrollbutton.svg (themes/images/breadcrumbs-scrollbutton.svg)
     skin/animation.css (themes/animation.css)
     skin/animationinspector.css (themes/animationinspector.css)
--- a/devtools/client/locales/en-US/toolbox.properties
+++ b/devtools/client/locales/en-US/toolbox.properties
@@ -168,23 +168,23 @@ toolbox.meatballMenu.hideconsole.label=H
 toolbox.meatballMenu.noautohide.label=Disable popup auto-hide
 
 # LOCALIZATION NOTE (toolbox.meatballMenu.settings.label): This is the label for
 # the item in the "..." menu in the toolbox that brings up the Settings
 # (Options) panel.
 # The keyboard shortcut will be shown to the side of the label.
 toolbox.meatballMenu.settings.label=Settings
 
-# LOCALIZATION NOTE (toolbox.meatballMenu.gettingStarted.label): This is the
-# label for the Getting Started menu item.
-toolbox.meatballMenu.gettingStarted.label=Getting started
+# LOCALIZATION NOTE (toolbox.meatballMenu.documentation.label): This is the
+# label for the Documentation menu item.
+toolbox.meatballMenu.documentation.label=Documentation…
 
-# LOCALIZATION NOTE (toolbox.meatballMenu.giveFeedback.label): This is the label
-# for the Give feedback menu item.
-toolbox.meatballMenu.giveFeedback.label=Give feedback
+# LOCALIZATION NOTE (toolbox.meatballMenu.community.label): This is the label
+# for the Community menu item.
+toolbox.meatballMenu.community.label=Community…
 
 # LOCALIZATION NOTE (toolbox.closebutton.tooltip): This is the tooltip for
 # the close button the developer tools toolbox.
 toolbox.closebutton.tooltip=Close Developer Tools
 
 # LOCALIZATION NOTE (toolbox.allToolsButton.tooltip): This is the tooltip for the
 # "all tools" button displayed when some tools are hidden by overflow of the toolbar.
 toolbox.allToolsButton.tooltip=Select another tool
--- a/devtools/client/themes/common.css
+++ b/devtools/client/themes/common.css
@@ -233,17 +233,17 @@ checkbox:-moz-focusring {
 .devtools-menulist,
 .devtools-toolbarbutton,
 .devtools-button {
   -moz-appearance: none;
   background: transparent;
   border: 1px solid var(--toolbarbutton-border-color);
   border-radius: 2px;
   color: var(--theme-body-color);
-  transition: background 0.05s ease-in-out;
+  transition: background-color 0.05s ease-in-out;
   -moz-box-align: center;
   text-shadow: none;
   padding: 1px;
   margin: 1px;
 
   /* Button text should not wrap on multiple lines */
   white-space: nowrap;
 }
@@ -258,17 +258,16 @@ checkbox:-moz-focusring {
   color: var(--theme-toolbar-color);
   direction: ltr;
   font-size: 11px;
 }
 
 .devtools-button:empty::before {
   content: "";
   display: inline-block;
-  background-size: cover;
   background-repeat: no-repeat;
   vertical-align: middle;
 }
 
 .devtools-button.checked:empty::before {
   color: var(--theme-toolbar-checked-color);
 }
 
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/command-chevron.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 xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M8.707 7.293l-5-5a1 1 0 0 0-1.414 1.414L6.586 8l-4.293 4.293a1 1 0 1 0 1.414 1.414l5-5a1 1 0 0 0 0-1.414zm6 0l-5-5a1 1 0 0 0-1.414 1.414L12.586 8l-4.293 4.293a1 1 0 1 0 1.414 1.414l5-5a1 1 0 0 0 0-1.414z"></path>
+</svg>
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -11,16 +11,17 @@
   --command-screenshot-image: url(images/command-screenshot.svg);
   --command-responsive-image: url(images/command-responsivemode.svg);
   --command-scratchpad-image: url(images/tool-scratchpad.svg);
   --command-pick-image: url(images/command-pick.svg);
   --command-pick-accessibility-image: url(images/command-pick-accessibility.svg);
   --command-frames-image: url(images/command-frames.svg);
   --command-rulers-image: url(images/command-rulers.svg);
   --command-measure-image: url(images/command-measure.svg);
+  --command-chevron-image: url(images/command-chevron.svg);
 }
 
 /* Toolbox tabbar */
 
 .devtools-tabbar {
   -moz-appearance: none;
   display: flex;
   background: var(--theme-tab-toolbar-background);
@@ -30,18 +31,17 @@
 }
 
 .toolbox-tabs-wrapper {
   position: relative;
   display: flex;
   flex: 1;
 }
 
-.toolbox-tabs-wrapper .all-tools-menu {
-  border-inline-end: 1px solid var(--theme-splitter-color);
+.toolbox-tabs-wrapper .tools-chevron-menu {
   border-top-width: 0;
   border-bottom-width: 0;
 }
 
 .toolbox-tabs {
   position: absolute;
   top: 0;
   left: 0;
@@ -63,56 +63,39 @@
 }
 
 /* Toolbox tabs */
 
 .devtools-tab {
   position: relative;
   display: flex;
   align-items: center;
-  min-width: 32px;
   min-height: 24px;
   margin: 0;
   padding: 0;
   border: none;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
   background-color: transparent;
+  flex-shrink: 0;
 }
 
 .devtools-tab-label {
   font-size: 12px;
   mask-image: linear-gradient(to left, transparent 0, black 6px);
   /* Set the end padding on the label to make sure the label gets faded out properly */
   padding-inline-end: 10px;
   min-width: 1px;
 }
 
 .devtools-tab-label:-moz-locale-dir(rtl) {
   mask-image: linear-gradient(to right, transparent 0, black 6px);
 }
 
-/* Hide tab icons when the viewport width is limited */
-@media (max-width: 700px) {
-  .devtools-tab-label {
-    /* Set the end padding on the label to make sure the label gets faded out properly */
-    padding-inline-end: 5px;
-  }
-
-  .devtools-tab:not(.devtools-tab-icon-only) {
-    padding-inline-start: 5px !important;
-  }
-
-  /* Hide the icons */
-  .devtools-tab:not(.devtools-tab-icon-only) > img {
-    display: none;
-  }
-}
-
 .devtools-tab-icon-only {
   min-width: 24px;
 }
 
 .devtools-tab {
   color: var(--theme-toolbar-color);
 }
 
@@ -152,18 +135,30 @@
 .devtools-tab.selected > img {
   fill: var(--theme-toolbar-selected-color);
 }
 
 .devtools-tab.highlighted > img {
   fill: var(--theme-toolbar-highlighted-color);
 }
 
+#devtools-chevron-menu-button::before {
+  -moz-context-properties: fill;
+  fill: var(--theme-toolbar-photon-icon-color);
+}
+
 /* Toolbox controls */
 
+#tools-chevron-menu-button::before {
+  top: 0;
+  offset-inline-end: 0;
+  background-image: var(--command-chevron-image);
+  background-position: center;
+}
+
 #toolbox-controls {
   margin-right: 3px;
 }
 
 #toolbox-buttons-end > .devtools-separator {
   margin-inline-start: 5px;
   margin-inline-end: 5px;
 }
--- a/devtools/client/webconsole/new-webconsole.js
+++ b/devtools/client/webconsole/new-webconsole.js
@@ -250,16 +250,17 @@ NewWebConsoleFrame.prototype = {
         Services.scriptloader.loadSubScript(
           "chrome://browser/content/browser-development-helpers.js", this.window);
         shortcuts.on("CmdOrCtrl+Alt+R", this.window.DevelopmentHelpers.quickRestart);
       }
     } else if (Services.prefs.getBoolPref(PREF_SIDEBAR_ENABLED)) {
       shortcuts.on("Esc", event => {
         if (!this.jsterm.autocompletePopup || !this.jsterm.autocompletePopup.isOpen) {
           this.newConsoleOutput.dispatchSidebarClose();
+          this.jsterm.focus();
         }
       });
     }
   },
   /**
    * Handler for page location changes.
    *
    * @param string uri
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -260,16 +260,17 @@ subsuite = clipboard
 [browser_webconsole_context_menu_open_url.js]
 [browser_webconsole_context_menu_store_as_global.js]
 [browser_webconsole_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
 [browser_webconsole_csp_violation.js]
 [browser_webconsole_cspro.js]
 [browser_webconsole_document_focus.js]
 [browser_webconsole_duplicate_errors.js]
+[browser_webconsole_error_with_unicode.js]
 [browser_webconsole_errors_after_page_reload.js]
 [browser_webconsole_eval_in_debugger_stackframe.js]
 [browser_webconsole_eval_in_debugger_stackframe2.js]
 [browser_webconsole_execution_scope.js]
 [browser_webconsole_external_script_errors.js]
 [browser_webconsole_file_uri.js]
 skip-if = true #	Bug 1404382
 [browser_webconsole_filter_by_input.js]
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_close_sidebar.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_close_sidebar.js
@@ -64,16 +64,18 @@ add_task(async function() {
   await showSidebar(hud);
 
   info("Send escape to hide sidebar");
   onSidebarShown = waitForNodeMutation(wrapper, { childList: true });
   EventUtils.synthesizeKey("KEY_Escape");
   await onSidebarShown;
   sidebar = hud.ui.document.querySelector(".sidebar");
   ok(!sidebar, "Sidebar hidden after sending esc");
+  let inputNode = hud.jsterm.inputNode;
+  ok(hasFocus(inputNode), "console input is focused after closing the sidebar");
 });
 
 async function showSidebar(hud) {
   let onMessage = waitForMessage(hud, "Object");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     content.wrappedJSObject.console.log({a: 1});
   });
   await onMessage;
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_error_with_unicode.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Check if an error with Unicode characters is reported correctly.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<script>\u6e2c</script>";
+const EXPECTED_REPORT = "ReferenceError: \u6e2c is not defined";
+
+add_task(async function() {
+  let hud = await openNewTabAndConsole(TEST_URI);
+
+  // On e10s, the exception is triggered in child process
+  // and is ignored by test harness
+  if (!Services.appinfo.browserTabsRemoteAutostart) {
+    expectUncaughtException();
+  }
+
+  info("generate exception and wait for the message");
+
+  let msg = await waitFor(() => findMessage(hud, EXPECTED_REPORT));
+  ok(msg, `Message found: "${EXPECTED_REPORT}"`);
+});
--- a/devtools/shared/DevToolsUtils.js
+++ b/devtools/shared/DevToolsUtils.js
@@ -352,24 +352,32 @@ exports.isSafeJSObject = function(obj) {
   if (proto && !exports.isSafeJSObject(proto)) {
     return false;
   }
 
   // Allow non-problematic chrome objects.
   return true;
 };
 
+/**
+ * Dump with newline - This is a logging function that will only output when
+ * the preference "devtools.debugger.log" is set to true. Typically it is used
+ * for logging the remote debugging protocol calls.
+ */
 exports.dumpn = function(str) {
   if (flags.wantLogging) {
     dump("DBG-SERVER: " + str + "\n");
   }
 };
 
 /**
- * A verbose logger for low-level tracing.
+ * Dump verbose - This is a verbose logger for low-level tracing, that is typically
+ * used to provide information about the remote debugging protocol's transport
+ * mechanisms. The logging can be enabled by changing the preferences
+ * "devtools.debugger.log" and "devtools.debugger.log.verbose" to true.
  */
 exports.dumpv = function(msg) {
   if (flags.wantVerbose) {
     exports.dumpn(msg);
   }
 };
 
 /**
--- a/devtools/shared/client/debugger-client.js
+++ b/devtools/shared/client/debugger-client.js
@@ -169,21 +169,16 @@ DebuggerClient.prototype = {
    * @return Promise
    *         Resolves once connected with an array whose first element
    *         is the application type, by default "browser", and the second
    *         element is the traits object (help figure out the features
    *         and behaviors of the server we connect to. See RootActor).
    */
   connect: function(onConnected) {
     let deferred = promise.defer();
-    this.emit("connect");
-
-    // Also emit the event on the |DebuggerClient| object (not on the instance),
-    // so it's possible to track all instances.
-    EventEmitter.emit(DebuggerClient, "connect", this);
 
     this.addOneTimeListener("connected", (name, applicationType, traits) => {
       this.traits = traits;
       if (onConnected) {
         onConnected(applicationType, traits);
       }
       deferred.resolve([applicationType, traits]);
     });
--- a/devtools/shared/flags.js
+++ b/devtools/shared/flags.js
@@ -1,18 +1,29 @@
 "use strict";
 
 const Services = require("Services");
 
-/*
- * Create a writable property by tracking it with a private variable.
+/**
+ * This module controls various global flags that can be toggled on and off.
+ * These flags are generally used to change the behavior of the code during
+ * testing. They are tracked by preferences so that they are propagated
+ * between the parent and content processes. The flags are exposed via a module
+ * as a conveniene and to stop from littering preference names throughout the
+ * code ase.
+ *
+ * Each of the flags is documented where it is defined.
+ */
+
+/**
  * We cannot make a normal property writeable on `exports` because
- * the module system freezes it.
+ * the module system freezes it. This function observes a preference
+ * and provides the latest value through a getter.
  */
-function makeWritableFlag(exports, name, pref) {
+function makePrefTrackedFlag(exports, name, pref) {
   let flag;
   // We don't have access to pref in worker, so disable all logs by default
   if (isWorker) {
     flag = false;
   } else {
     flag = Services.prefs.getBoolPref(pref, false);
     let prefObserver = () => {
       flag = Services.prefs.getBoolPref(pref, false);
@@ -28,15 +39,27 @@ function makeWritableFlag(exports, name,
   }
   Object.defineProperty(exports, name, {
     get: function() {
       return flag;
     }
   });
 }
 
-makeWritableFlag(exports, "wantLogging", "devtools.debugger.log");
-makeWritableFlag(exports, "wantVerbose", "devtools.debugger.log.verbose");
+/**
+ * Setting the "devtools.debugger.log" preference to true will enable logging of
+ * the RDP calls to the debugger server.
+ */
+makePrefTrackedFlag(exports, "wantLogging", "devtools.debugger.log");
 
-// When the testing flag is set, various behaviors may be altered from
-// production mode, typically to enable easier testing or enhanced
-// debugging.
-makeWritableFlag(exports, "testing", "devtools.testing");
+/**
+ * Setting the "devtools.debugger.log.verbose" preference to true will enable a
+ * more verbose logging of the the RDP. The "devtools.debugger.log" preference
+ * must be set to true as well for this to have any effect.
+ */
+makePrefTrackedFlag(exports, "wantVerbose", "devtools.debugger.log.verbose");
+
+/**
+ * Setting the "devtools.testing" preference to true will toggle on certain
+ * behaviors that can differ from the production version of the code. These
+ * behaviors typically enable easier testing or enhanced debugging features.
+ */
+makePrefTrackedFlag(exports, "testing", "devtools.testing");
deleted file mode 100644
--- a/devtools/shared/transport/tests/unit/test_transport_events.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-function run_test() {
-  initTestDebuggerServer();
-
-  add_task(async function() {
-    await test_transport_events("socket", socket_transport);
-    await test_transport_events("local", local_transport);
-    DebuggerServer.destroy();
-  });
-
-  run_next_test();
-}
-
-async function test_transport_events(name, transportFactory) {
-  info(`Started testing of transport: ${name}`);
-
-  Assert.equal(Object.keys(DebuggerServer._connections).length, 0);
-
-  let transport = await transportFactory();
-
-  // Transport expects the hooks to be not null
-  transport.hooks = {
-    onPacket: () => {},
-    onClosed: () => {},
-  };
-
-  let rootReceived = transport.once("packet", packet => {
-    info(`Packet event: ${JSON.stringify(packet)}`);
-    Assert.equal(packet.from, "root");
-  });
-
-  transport.ready();
-  await rootReceived;
-
-  let echoSent = transport.once("send", packet => {
-    info(`Send event: ${JSON.stringify(packet)}`);
-    Assert.equal(packet.to, "root");
-    Assert.equal(packet.type, "echo");
-  });
-
-  let echoReceived = transport.once("packet", packet => {
-    info(`Packet event: ${JSON.stringify(packet)}`);
-    Assert.equal(packet.from, "root");
-    Assert.equal(packet.type, "echo");
-  });
-
-  transport.send({ to: "root", type: "echo" });
-  await echoSent;
-  await echoReceived;
-
-  let clientClosed = transport.once("close", () => {
-    info(`Close event`);
-  });
-
-  let serverClosed = DebuggerServer.once("connectionchange", type => {
-    info(`Server closed`);
-    Assert.equal(type, "closed");
-  });
-
-  transport.close();
-
-  await clientClosed;
-  await serverClosed;
-
-  info(`Finished testing of transport: ${name}`);
-}
--- a/devtools/shared/transport/tests/unit/xpcshell.ini
+++ b/devtools/shared/transport/tests/unit/xpcshell.ini
@@ -12,9 +12,8 @@ support-files =
 [test_client_server_bulk.js]
 [test_dbgsocket.js]
 [test_dbgsocket_connection_drop.js]
 [test_delimited_read.js]
 [test_no_bulk.js]
 [test_packet.js]
 [test_queue.js]
 [test_transport_bulk.js]
-[test_transport_events.js]
--- a/devtools/shared/transport/transport.js
+++ b/devtools/shared/transport/transport.js
@@ -25,17 +25,16 @@
   const DevToolsUtils = require("devtools/shared/DevToolsUtils");
   const { dumpn, dumpv } = DevToolsUtils;
   const flags = require("devtools/shared/flags");
   const StreamUtils = require("devtools/shared/transport/stream-utils");
   const { Packet, JSONPacket, BulkPacket } =
   require("devtools/shared/transport/packets");
   const promise = require("promise");
   const defer = require("devtools/shared/defer");
-  const EventEmitter = require("devtools/shared/event-emitter");
 
   DevToolsUtils.defineLazyGetter(this, "Pipe", () => {
     return CC("@mozilla.org/pipe;1", "nsIPipe", "init");
   });
 
   DevToolsUtils.defineLazyGetter(this, "ScriptableInputStream", () => {
     return CC("@mozilla.org/scriptableinputstream;1",
             "nsIScriptableInputStream", "init");
@@ -96,18 +95,16 @@
    * - onClosed(reason) - called when the connection is closed. |reason| is
    *   an optional nsresult or object, typically passed when the transport is
    *   closed due to some error in a underlying stream.
    *
    * See ./packets.js and the Remote Debugging Protocol specification for more
    * details on the format of these packets.
    */
   function DebuggerTransport(input, output) {
-    EventEmitter.decorate(this);
-
     this._input = input;
     this._scriptableInput = new ScriptableInputStream(input);
     this._output = output;
 
     // The current incoming (possibly partial) header, which will determine which
     // type of Packet |_incoming| below will become.
     this._incomingHeader = "";
     // The current incoming Packet object
@@ -129,18 +126,16 @@
      * Transmit an object as a JSON packet.
      *
      * This method returns immediately, without waiting for the entire
      * packet to be transmitted, registering event handlers as needed to
      * transmit the entire packet. Packets are transmitted in the order
      * they are passed to this method.
      */
     send: function(object) {
-      this.emit("send", object);
-
       let packet = new JSONPacket(this);
       packet.object = object;
       this._outgoing.push(packet);
       this._flushOutgoing();
     },
 
     /**
      * Transmit streaming data via a bulk packet.
@@ -179,34 +174,30 @@
      *                     The stream to copy from.
      *             @return Promise
      *                     The promise is resolved when copying completes or
      *                     rejected if any (unexpected) errors occur.
      *                     This object also emits "progress" events for each chunk
      *                     that is copied.  See stream-utils.js.
      */
     startBulkSend: function(header) {
-      this.emit("startbulksend", header);
-
       let packet = new BulkPacket(this);
       packet.header = header;
       this._outgoing.push(packet);
       this._flushOutgoing();
       return packet.streamReadyForWriting;
     },
 
     /**
      * Close the transport.
      * @param reason nsresult / object (optional)
      *        The status code or error message that corresponds to the reason for
      *        closing the transport (likely because a stream closed or failed).
      */
     close: function(reason) {
-      this.emit("close", reason);
-
       this.active = false;
       this._input.close();
       this._scriptableInput.close();
       this._output.close();
       this._destroyIncoming();
       this._destroyAllOutgoing();
       if (this.hooks) {
         this.hooks.onClosed(reason);
@@ -473,33 +464,31 @@
     /**
      * Handler triggered by an incoming JSONPacket completing it's |read| method.
      * Delivers the packet to this.hooks.onPacket.
      */
     _onJSONObjectReady: function(object) {
       DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
       // Ensure the transport is still alive by the time this runs.
         if (this.active) {
-          this.emit("packet", object);
           this.hooks.onPacket(object);
         }
       }, "DebuggerTransport instance's this.hooks.onPacket"));
     },
 
     /**
      * Handler triggered by an incoming BulkPacket entering the |read| phase for
      * the stream portion of the packet.  Delivers info about the incoming
      * streaming data to this.hooks.onBulkPacket.  See the main comment on the
      * transport at the top of this file for more details.
      */
     _onBulkReadReady: function(...args) {
       DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
       // Ensure the transport is still alive by the time this runs.
         if (this.active) {
-          this.emit("bulkpacket", ...args);
           this.hooks.onBulkPacket(...args);
         }
       }, "DebuggerTransport instance's this.hooks.onBulkPacket"));
     },
 
     /**
      * Remove all handlers and references related to the current incoming packet,
      * either because it is now complete or because the transport is closing.
@@ -523,35 +512,31 @@
    * connection it merely calls the packet dispatcher of the other side.
    *
    * @param other LocalDebuggerTransport
    *        The other endpoint for this debugger connection.
    *
    * @see DebuggerTransport
    */
   function LocalDebuggerTransport(other) {
-    EventEmitter.decorate(this);
-
     this.other = other;
     this.hooks = null;
 
     // A packet number, shared between this and this.other. This isn't used by the
     // protocol at all, but it makes the packet traces a lot easier to follow.
     this._serial = this.other ? this.other._serial : { count: 0 };
     this.close = this.close.bind(this);
   }
 
   LocalDebuggerTransport.prototype = {
     /**
      * Transmit a message by directly calling the onPacket handler of the other
      * endpoint.
      */
     send: function(packet) {
-      this.emit("send", packet);
-
       let serial = this._serial.count++;
       if (flags.wantLogging) {
         // Check 'from' first, as 'echo' packets have both.
         if (packet.from) {
           dumpn("Packet " + serial + " sent from " + uneval(packet.from));
         } else if (packet.to) {
           dumpn("Packet " + serial + " sent to " + uneval(packet.to));
         }
@@ -560,35 +545,32 @@
       let other = this.other;
       if (other) {
         DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
           // Avoid the cost of JSON.stringify() when logging is disabled.
           if (flags.wantLogging) {
             dumpn("Received packet " + serial + ": " + JSON.stringify(packet, null, 2));
           }
           if (other.hooks) {
-            other.emit("packet", packet);
             other.hooks.onPacket(packet);
           }
         }, "LocalDebuggerTransport instance's this.other.hooks.onPacket"));
       }
     },
 
     /**
      * Send a streaming bulk packet directly to the onBulkPacket handler of the
      * other endpoint.
      *
      * This case is much simpler than the full DebuggerTransport, since there is
      * no primary stream we have to worry about managing while we hand it off to
      * others temporarily.  Instead, we can just make a single use pipe and be
      * done with it.
      */
     startBulkSend: function({actor, type, length}) {
-      this.emit("startbulksend", {actor, type, length});
-
       let serial = this._serial.count++;
 
       dumpn("Sent bulk packet " + serial + " for actor " + actor);
       if (!this.other) {
         let error = new Error("startBulkSend: other side of transport missing");
         return promise.reject(error);
       }
 
@@ -611,17 +593,16 @@
             StreamUtils.copyStream(pipe.inputStream, output, length);
             deferred.resolve(copying);
             return copying;
           },
           stream: pipe.inputStream,
           done: deferred
         };
 
-        this.other.emit("bulkpacket", packet);
         this.other.hooks.onBulkPacket(packet);
 
         // Await the result of reading from the stream
         deferred.promise.then(() => pipe.inputStream.close(), this.close);
       }, "LocalDebuggerTransport instance's this.other.hooks.onBulkPacket"));
 
       // Sender
       let sendDeferred = defer();
@@ -648,18 +629,16 @@
 
       return sendDeferred.promise;
     },
 
     /**
      * Close the transport.
      */
     close: function() {
-      this.emit("close");
-
       if (this.other) {
         // Remove the reference to the other endpoint before calling close(), to
         // avoid infinite recursion.
         let other = this.other;
         this.other = null;
         other.close();
       }
       if (this.hooks) {
@@ -707,18 +686,16 @@
    *
    * |prefix| is a string included in the message names, to distinguish
    * multiple servers running in the same child process.
    *
    * This transport exchanges messages named 'debug:<prefix>:packet', where
    * <prefix> is |prefix|, whose data is the protocol packet.
    */
   function ChildDebuggerTransport(mm, prefix) {
-    EventEmitter.decorate(this);
-
     this._mm = mm;
     this._messageName = "debug:" + prefix + ":packet";
   }
 
   /*
    * To avoid confusion, we use 'message' to mean something that
    * nsIMessageSender conveys, and 'packet' to mean a remote debugging
    * protocol packet.
@@ -746,22 +723,20 @@
     },
 
     ready: function() {
       this._addListener();
     },
 
     close: function() {
       this._removeListener();
-      this.emit("close");
       this.hooks.onClosed();
     },
 
     receiveMessage: function({data}) {
-      this.emit("packet", data);
       this.hooks.onPacket(data);
     },
 
     /**
      * Helper method to ensure a given `object` can be sent across message manager
      * without being serialized to JSON.
      * See https://searchfox.org/mozilla-central/rev/6bfadf95b4a6aaa8bb3b2a166d6c3545983e179a/dom/base/nsFrameMessageManager.cpp#458-469
      */
@@ -784,17 +759,16 @@
           }
           return [key];
         }
       }
       return [];
     },
 
     send: function(packet) {
-      this.emit("send", packet);
       if (flags.testing && !this._canBeSerialized(packet)) {
         let attributes = this.pathToUnserializable(packet);
         let msg = "Following packet can't be serialized: " + JSON.stringify(packet);
         msg += "\nBecause of attributes: " + attributes.join(", ") + "\n";
         msg += "Did you pass a function or an XPCOM object in it?";
         throw new Error(msg);
       }
       try {
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -79,21 +79,16 @@ static const RedirEntry kRedirMap[] = {
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT
   },
   {
     "networking", "chrome://global/content/aboutNetworking.xhtml",
     nsIAboutModule::ALLOW_SCRIPT
   },
   {
-    "newaddon", "chrome://mozapps/content/extensions/newaddon.xul",
-    nsIAboutModule::ALLOW_SCRIPT |
-      nsIAboutModule::HIDE_FROM_ABOUTABOUT
-  },
-  {
     "performance", "chrome://global/content/aboutPerformance.xhtml",
     nsIAboutModule::ALLOW_SCRIPT
   },
   {
     "plugins", "chrome://global/content/plugins.html",
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD
   },
   {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -13685,17 +13685,17 @@ nsDocShell::OnOverLink(nsIContent* aCont
   if (!browserChrome2) {
     browserChrome = do_GetInterface(mTreeOwner);
     if (!browserChrome) {
       return rv;
     }
   }
 
   nsAutoCString spec;
-  rv = aURI->GetSpec(spec);
+  rv = aURI->GetDisplaySpec(spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 uStr(spec);
 
   mozilla::net::PredictorPredict(aURI, mCurrentURI,
                                  nsINetworkPredictor::PREDICT_LINK,
                                  aContent->NodePrincipal()->OriginAttributesRef(),
                                  nullptr);
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -180,17 +180,16 @@ const mozilla::Module::ContractIDEntry k
 #endif
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "mozilla", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "networking", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
-  { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newaddon", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "performance", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "plugins", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "serviceworkers", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
 #ifndef ANDROID
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "profiles", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
 #endif
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "srcdoc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "support", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -43,206 +43,27 @@ namespace mozilla {
 //
 // ------------------------------------------------------------------
 
 // For the aAllowList parameter of AppendStringOrStringSequence and
 // GetPropertyValuesPairs.
 enum class ListAllowance { eDisallow, eAllow };
 
 /**
- * A comparator to sort nsCSSPropertyID values such that longhands are sorted
- * before shorthands, and shorthands with fewer components are sorted before
- * shorthands with more components.
- *
- * Using this allows us to prioritize values specified by longhands (or smaller
- * shorthand subsets) when longhands and shorthands are both specified
- * on the one keyframe.
- *
- * Example orderings that result from this:
- *
- *   margin-left, margin
- *
- * and:
- *
- *   border-top-color, border-color, border-top, border
- */
-class PropertyPriorityComparator
-{
-public:
-  PropertyPriorityComparator()
-    : mSubpropertyCountInitialized(false) {}
-
-  bool Equals(nsCSSPropertyID aLhs, nsCSSPropertyID aRhs) const
-  {
-    return aLhs == aRhs;
-  }
-
-  bool LessThan(nsCSSPropertyID aLhs,
-                nsCSSPropertyID aRhs) const
-  {
-    bool isShorthandLhs = nsCSSProps::IsShorthand(aLhs);
-    bool isShorthandRhs = nsCSSProps::IsShorthand(aRhs);
-
-    if (isShorthandLhs) {
-      if (isShorthandRhs) {
-        // First, sort shorthands by the number of longhands they have.
-        uint32_t subpropCountLhs = SubpropertyCount(aLhs);
-        uint32_t subpropCountRhs = SubpropertyCount(aRhs);
-        if (subpropCountLhs != subpropCountRhs) {
-          return subpropCountLhs < subpropCountRhs;
-        }
-        // Otherwise, sort by IDL name below.
-      } else {
-        // Put longhands before shorthands.
-        return false;
-      }
-    } else {
-      if (isShorthandRhs) {
-        // Put longhands before shorthands.
-        return true;
-      }
-    }
-    // For two longhand properties, or two shorthand with the same number
-    // of longhand components, sort by IDL name.
-    return nsCSSProps::PropertyIDLNameSortPosition(aLhs) <
-           nsCSSProps::PropertyIDLNameSortPosition(aRhs);
-  }
-
-  uint32_t SubpropertyCount(nsCSSPropertyID aProperty) const
-  {
-    if (!mSubpropertyCountInitialized) {
-      PodZero(&mSubpropertyCount);
-      mSubpropertyCountInitialized = true;
-    }
-    if (mSubpropertyCount[aProperty] == 0) {
-      uint32_t count = 0;
-      CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
-          p, aProperty, CSSEnabledState::eForAllContent) {
-        ++count;
-      }
-      mSubpropertyCount[aProperty] = count;
-    }
-    return mSubpropertyCount[aProperty];
-  }
-
-private:
-  // Cache of shorthand subproperty counts.
-  mutable RangedArray<
-    uint32_t,
-    eCSSProperty_COUNT_no_shorthands,
-    eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands> mSubpropertyCount;
-  mutable bool mSubpropertyCountInitialized;
-};
-
-/**
- * Adaptor for PropertyPriorityComparator to sort objects which have
- * a mProperty member.
- */
-template <typename T>
-class TPropertyPriorityComparator : PropertyPriorityComparator
-{
-public:
-  bool Equals(const T& aLhs, const T& aRhs) const
-  {
-    return PropertyPriorityComparator::Equals(aLhs.mProperty, aRhs.mProperty);
-  }
-  bool LessThan(const T& aLhs, const T& aRhs) const
-  {
-    return PropertyPriorityComparator::LessThan(aLhs.mProperty, aRhs.mProperty);
-  }
-};
-
-/**
- * Iterator to walk through a PropertyValuePair array using the ordering
- * provided by PropertyPriorityComparator.
- */
-class PropertyPriorityIterator
-{
-public:
-  explicit PropertyPriorityIterator(
-    const nsTArray<PropertyValuePair>& aProperties)
-    : mProperties(aProperties)
-  {
-    mSortedPropertyIndices.SetCapacity(mProperties.Length());
-    for (size_t i = 0, len = mProperties.Length(); i < len; ++i) {
-      PropertyAndIndex propertyIndex = { mProperties[i].mProperty, i };
-      mSortedPropertyIndices.AppendElement(propertyIndex);
-    }
-    mSortedPropertyIndices.Sort(PropertyAndIndex::Comparator());
-  }
-
-  class Iter
-  {
-  public:
-    explicit Iter(const PropertyPriorityIterator& aParent)
-      : mParent(aParent)
-      , mIndex(0) { }
-
-    static Iter EndIter(const PropertyPriorityIterator &aParent)
-    {
-      Iter iter(aParent);
-      iter.mIndex = aParent.mSortedPropertyIndices.Length();
-      return iter;
-    }
-
-    bool operator!=(const Iter& aOther) const
-    {
-      return mIndex != aOther.mIndex;
-    }
-
-    Iter& operator++()
-    {
-      MOZ_ASSERT(mIndex + 1 <= mParent.mSortedPropertyIndices.Length(),
-                 "Should not seek past end iterator");
-      mIndex++;
-      return *this;
-    }
-
-    const PropertyValuePair& operator*()
-    {
-      MOZ_ASSERT(mIndex < mParent.mSortedPropertyIndices.Length(),
-                 "Should not try to dereference an end iterator");
-      return mParent.mProperties[mParent.mSortedPropertyIndices[mIndex].mIndex];
-    }
-
-  private:
-    const PropertyPriorityIterator& mParent;
-    size_t mIndex;
-  };
-
-  Iter begin() { return Iter(*this); }
-  Iter end()   { return Iter::EndIter(*this); }
-
-private:
-  struct PropertyAndIndex
-  {
-    nsCSSPropertyID mProperty;
-    size_t mIndex; // Index of mProperty within mProperties
-
-    typedef TPropertyPriorityComparator<PropertyAndIndex> Comparator;
-  };
-
-  const nsTArray<PropertyValuePair>& mProperties;
-  nsTArray<PropertyAndIndex> mSortedPropertyIndices;
-};
-
-/**
  * A property-values pair obtained from the open-ended properties
  * discovered on a regular keyframe or property-indexed keyframe object.
  *
  * Single values (as required by a regular keyframe, and as also supported
  * on property-indexed keyframes) are stored as the only element in
  * mValues.
  */
 struct PropertyValuesPair
 {
   nsCSSPropertyID mProperty;
   nsTArray<nsString> mValues;
-
-  typedef TPropertyPriorityComparator<PropertyValuesPair> Comparator;
 };
 
 /**
  * An additional property (for a property-values pair) found on a
  * BaseKeyframe or BasePropertyIndexedKeyframe object.
  */
 struct AdditionalProperty
 {
--- a/dom/base/gen-usecounters.py
+++ b/dom/base/gen-usecounters.py
@@ -56,22 +56,20 @@ def generate_list(f, counters):
     print_optional_macro_undeclare('USE_COUNTER_CSS_PROPERTY')
     print_optional_macro_undeclare('USE_COUNTER_CUSTOM')
 
 def generate_property_map(f, counters):
     print(AUTOGENERATED_WARNING_COMMENT, file=f)
     print('''
 enum {
   #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
-  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #define CSS_PROP(name_, id_, method_, ...) \\
     USE_COUNTER_FOR_CSS_PROPERTY_##method_ = eUseCounter_UNKNOWN,
   #include "nsCSSPropList.h"
   #undef CSS_PROP
-  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP_PUBLIC_OR_PRIVATE
 };
 ''', file=f)
     for counter in counters:
         if counter['type'] == 'property':
             prop = counter['property_name']
             print('#define USE_COUNTER_FOR_CSS_PROPERTY_%s eUseCounter_property_%s' % (prop, prop), file=f)
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -271,16 +271,17 @@ nsIBidiKeyboard *nsContentUtils::sBidiKe
 uint32_t nsContentUtils::sScriptBlockerCount = 0;
 uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
 AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr;
 uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
 
 bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
 bool nsContentUtils::sAllowXULXBL_for_file = false;
+bool nsContentUtils::sDisablePopups = false;
 
 nsString* nsContentUtils::sShiftText = nullptr;
 nsString* nsContentUtils::sControlText = nullptr;
 nsString* nsContentUtils::sMetaText = nullptr;
 nsString* nsContentUtils::sOSText = nullptr;
 nsString* nsContentUtils::sAltText = nullptr;
 nsString* nsContentUtils::sModifierSeparator = nullptr;
 
@@ -728,16 +729,19 @@ nsContentUtils::Init()
                                "dom.placeholder.show_on_focus", true);
 
   Preferences::AddBoolVarCache(&sAutoFocusEnabled,
                                "browser.autofocus", true);
 
   Preferences::AddBoolVarCache(&sIsBytecodeCacheEnabled,
                                "dom.script_loader.bytecode_cache.enabled", false);
 
+  Preferences::AddBoolVarCache(&sDisablePopups,
+                               "dom.disable_open_during_load", false);
+
   Preferences::AddIntVarCache(&sBytecodeCacheStrategy,
                               "dom.script_loader.bytecode_cache.strategy", 0);
 
   nsDependentCString buildID(mozilla::PlatformBuildID());
   sJSBytecodeMimeType = new nsCString(NS_LITERAL_CSTRING("javascript/moz-bytecode-") + buildID);
 
   Element::InitCCCallbacks();
 
@@ -11008,8 +11012,29 @@ nsContentUtils::InnerOrOuterWindowCreate
 
 /* static */ void
 nsContentUtils::InnerOrOuterWindowDestroyed()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sInnerOrOuterWindowCount > 0);
   --sInnerOrOuterWindowCount;
 }
+
+/* static */ bool
+nsContentUtils::CanShowPopup(nsIPrincipal* aPrincipal)
+{
+  MOZ_ASSERT(aPrincipal);
+  uint32_t permit;
+  nsCOMPtr<nsIPermissionManager> permissionManager =
+    services::GetPermissionManager();
+
+  if (permissionManager &&
+      NS_SUCCEEDED(permissionManager->TestPermissionFromPrincipal(aPrincipal, "popup", &permit))) {
+    if (permit == nsIPermissionManager::ALLOW_ACTION) {
+      return true;
+    }
+    if (permit == nsIPermissionManager::DENY_ACTION) {
+      return false;
+    }
+  }
+
+  return !sDisablePopups;
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3286,16 +3286,18 @@ public:
 
   // Get a serial number for a newly created inner or outer window.
   static uint32_t InnerOrOuterWindowCreated();
   // Record that an inner or outer window has been destroyed.
   static void InnerOrOuterWindowDestroyed();
   // Get the current number of inner or outer windows.
   static int32_t GetCurrentInnerOrOuterWindowCount() { return sInnerOrOuterWindowCount; }
 
+  static bool CanShowPopup(nsIPrincipal* aPrincipal);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
@@ -3413,16 +3415,17 @@ private:
   static AutoTArray<nsCOMPtr<nsIRunnable>, 8>* sBlockedScriptRunners;
   static uint32_t sRunnersCountAtFirstBlocker;
   static uint32_t sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static bool sIsHandlingKeyBoardEvent;
   static bool sAllowXULXBL_for_file;
+  static bool sDisablePopups;
   static bool sIsFullScreenApiEnabled;
   static bool sIsUnprefixedFullscreenApiEnabled;
   static bool sTrustedFullScreenOnly;
   static bool sIsCutCopyAllowed;
   static uint32_t sHandlingInputTimeout;
   static bool sIsPerformanceTimingEnabled;
   static bool sIsResourceTimingEnabled;
   static bool sIsPerformanceNavigationTimingEnabled;
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -177,20 +177,16 @@
 
 #include "nsWindowRoot.h"
 #include "nsNetCID.h"
 #include "nsIArray.h"
 
 #include "nsBindingManager.h"
 #include "nsXBLService.h"
 
-// used for popup blocking, needs to be converted to something
-// belonging to the back-end like nsIContentPolicy
-#include "nsIPopupWindowManager.h"
-
 #include "nsIDragService.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Selection.h"
 #include "nsFrameLoader.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPCOMCID.h"
 #include "mozilla/Logging.h"
 #include "prenv.h"
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -178,20 +178,16 @@
 #include "nsIArray.h"
 
 #include "XULDocument.h"
 #include "nsIDOMXULCommandDispatcher.h"
 
 #include "nsBindingManager.h"
 #include "nsXBLService.h"
 
-// used for popup blocking, needs to be converted to something
-// belonging to the back-end like nsIContentPolicy
-#include "nsIPopupWindowManager.h"
-
 #include "nsIDragService.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Selection.h"
 #include "nsFrameLoader.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPCOMCID.h"
 #include "mozilla/Logging.h"
 #include "prenv.h"
@@ -5342,35 +5338,16 @@ nsGlobalWindowOuter::GetTopWindowRoot()
   if (!piWin) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
   return window.forget();
 }
 
-static
-bool IsPopupBlocked(nsIDocument* aDoc)
-{
-  nsCOMPtr<nsIPopupWindowManager> pm =
-    do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
-
-  if (!pm) {
-    return false;
-  }
-
-  if (!aDoc) {
-    return true;
-  }
-
-  uint32_t permission = nsIPopupWindowManager::ALLOW_POPUP;
-  pm->TestPermission(aDoc->NodePrincipal(), &permission);
-  return permission == nsIPopupWindowManager::DENY_POPUP;
-}
-
 void
 nsGlobalWindowOuter::FirePopupBlockedEvent(nsIDocument* aDoc,
                                            nsIURI* aPopupURI,
                                            const nsAString& aPopupWindowName,
                                            const nsAString& aPopupWindowFeatures)
 {
   MOZ_ASSERT(aDoc);
 
@@ -5408,18 +5385,20 @@ nsGlobalWindowOuter::CanSetProperty(cons
   // If the pref is set to true, we can not set the property
   // and vice versa.
   return !Preferences::GetBool(aPrefName, true);
 }
 
 bool
 nsGlobalWindowOuter::PopupWhitelisted()
 {
-  if (!IsPopupBlocked(mDoc))
+  if (mDoc && nsContentUtils::CanShowPopup(mDoc->NodePrincipal()))
+  {
     return true;
+  }
 
   nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
   if (parent == this)
   {
     return false;
   }
 
   return nsGlobalWindowOuter::Cast(parent)->PopupWhitelisted();
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -28,17 +28,17 @@ WebGLContext::Clear(GLbitfield mask)
         GenerateWarning("Calling gl.clear(0) has no effect.");
     } else if (mRasterizerDiscardEnabled) {
         GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
     }
 
     if (mask & LOCAL_GL_COLOR_BUFFER_BIT && mBoundDrawFramebuffer) {
         if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
             for (const auto& cur : mBoundDrawFramebuffer->ColorDrawBuffers()) {
-                if (!cur->IsDefined())
+                if (!cur->HasImage())
                     continue;
 
                 switch (cur->Format()->format->componentType) {
                 case webgl::ComponentType::Float:
                 case webgl::ComponentType::NormInt:
                 case webgl::ComponentType::NormUInt:
                     break;
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -82,17 +82,16 @@
 #include "mozilla/dom/FileSystem.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileList.h"
 #include "nsIFile.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIContentPrefService2.h"
 #include "nsIMIMEService.h"
 #include "nsIObserverService.h"
-#include "nsIPopupWindowManager.h"
 #include "nsGlobalWindow.h"
 
 // input type=image
 #include "nsImageLoadingContent.h"
 #include "imgRequestProxy.h"
 
 #include "mozAutoDocUpdate.h"
 #include "nsContentCreatorFunctions.h"
@@ -690,24 +689,17 @@ HTMLInputElement::IsPopupBlocked() const
     return true;
   }
 
   // Check if page can open a popup without abuse regardless of allowed events
   if (win->GetPopupControlState() <= openBlocked) {
     return false;
   }
 
-  nsCOMPtr<nsIPopupWindowManager> pm = do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
-  if (!pm) {
-    return true;
-  }
-
-  uint32_t permission;
-  pm->TestPermission(OwnerDoc()->NodePrincipal(), &permission);
-  return permission == nsIPopupWindowManager::DENY_POPUP;
+  return !nsContentUtils::CanShowPopup(OwnerDoc()->NodePrincipal());
 }
 
 nsresult
 HTMLInputElement::InitColorPicker()
 {
   if (mPickerRunning) {
     NS_WARNING("Just one nsIColorPicker is allowed");
     return NS_ERROR_FAILURE;
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1286,21 +1286,21 @@ nsGenericHTMLElement::sBackgroundColorAt
 
 void
 nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
                                                  GenericSpecifiedValues* aData)
 {
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
   if (value && value->Type() == nsAttrValue::eEnum) {
     int32_t align = value->GetEnumValue();
-    if (!aData->PropertyIsSet(eCSSProperty_float_)) {
+    if (!aData->PropertyIsSet(eCSSProperty_float)) {
       if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
-        aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Left);
+        aData->SetKeywordValue(eCSSProperty_float, StyleFloat::Left);
       } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
-        aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Right);
+        aData->SetKeywordValue(eCSSProperty_float, StyleFloat::Right);
       }
     }
     if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) {
       switch (align) {
       case NS_STYLE_TEXT_ALIGN_LEFT:
       case NS_STYLE_TEXT_ALIGN_RIGHT:
         break;
       default:
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -14,17 +14,16 @@
 #include "nsArray.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsHashPropertyBag.h"
 #include "nsIEventTarget.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIPermissionManager.h"
-#include "nsIPopupWindowManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIIDNService.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsICryptoHash.h"
--- a/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs
+++ b/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs
@@ -21,30 +21,30 @@ const FRAME = `
   </body>
   </html>`;
 
 function handleRequest(request, response)
 {
   // avoid confusing cache behaviors
   response.setHeader("Cache-Control", "no-cache", false);
 
-  if (request.queryString === "setSameSiteCookie") {
+  if (request.queryString.includes("setSameSiteCookie")) {
     response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true);
     response.setHeader("Content-Type", "image/png");
     response.write(IMG_BYTES);
     return;
   }
 
-  if (request.queryString === "setRegularCookie") {
+  if (request.queryString.includes("setRegularCookie")) {
     response.setHeader("Set-Cookie", "myKey=regularCookie;", true);
     response.setHeader("Content-Type", "image/png");
     response.write(IMG_BYTES);
     return;
   }
 
-  if (request.queryString === "loadFrame") {
+  if (request.queryString.includes("loadFrame")) {
     response.write(FRAME);
     return;
   }
 
   // we should never get here, but just in case return something unexpected
   response.write("D'oh");
 }
--- a/dom/security/test/general/file_same_site_cookies_from_script.sjs
+++ b/dom/security/test/general/file_same_site_cookies_from_script.sjs
@@ -29,21 +29,21 @@ const GET_COOKIE_FRAME = `
   </body>
   </html>`;
 
 function handleRequest(request, response)
 {
   // avoid confusing cache behaviors
   response.setHeader("Cache-Control", "no-cache", false);
 
-  if (request.queryString === "setSameSiteCookieUsingInlineScript") {
+  if (request.queryString.includes("setSameSiteCookieUsingInlineScript")) {
     response.write(SET_COOKIE_FRAME);
     return;
   }
 
-  if (request.queryString === "getCookieFrame") {
+  if (request.queryString.includes("getCookieFrame")) {
     response.write(GET_COOKIE_FRAME);
     return;
   }
 
   // we should never get here, but just in case return something unexpected
   response.write("D'oh");
 }
--- a/dom/security/test/general/file_same_site_cookies_subrequest.sjs
+++ b/dom/security/test/general/file_same_site_cookies_subrequest.sjs
@@ -16,44 +16,44 @@ const FRAME = `
   </body>
   </html>`;
 
 function handleRequest(request, response)
 {
   // avoid confusing cache behaviors
   response.setHeader("Cache-Control", "no-cache", false);
 
-  if (request.queryString === "setStrictSameSiteCookie") {
+  if (request.queryString.includes("setStrictSameSiteCookie")) {
     response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true);
     response.setHeader("Content-Type", "image/png");
     response.write(IMG_BYTES);
     return;
   }
 
-  if (request.queryString === "setLaxSameSiteCookie") {
+  if (request.queryString.includes("setLaxSameSiteCookie")) {
     response.setHeader("Set-Cookie", "myKey=laxSameSiteCookie; samesite=lax", true);
     response.setHeader("Content-Type", "image/png");
     response.write(IMG_BYTES);
     return;
   }
 
   // save the object state of the initial request, which returns
   // async once the server has processed the img request.
-  if (request.queryString === "queryresult") {
+  if (request.queryString.includes("queryresult")) {
     response.processAsync();
     setObjectState("queryResult", response);
     return;
   }
 
-  if (request.queryString === "loadFrame") {
+  if (request.queryString.includes("loadFrame")) {
     response.write(FRAME);
     return;
   }
 
-  if (request.queryString === "checkCookie") {
+  if (request.queryString.includes("checkCookie")) {
     var cookie = "unitialized";
     if (request.hasHeader("Cookie")) {
       cookie = request.getHeader("Cookie");
     }
     else {
       cookie = "myKey=noCookie";
     }
     response.setHeader("Content-Type", "image/png");
--- a/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs
+++ b/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs
@@ -29,44 +29,44 @@ const WIN = `
   </body>
   </html>`;
 
 function handleRequest(request, response)
 {
   // avoid confusing cache behaviors
   response.setHeader("Cache-Control", "no-cache", false);
 
-  if (request.queryString === "setStrictSameSiteCookie") {
+  if (request.queryString.includes("setStrictSameSiteCookie")) {
     response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true);
     response.setHeader("Content-Type", "image/png");
     response.write(IMG_BYTES);
     return;
   }
 
-  if (request.queryString === "setLaxSameSiteCookie") {
+  if (request.queryString.includes("setLaxSameSiteCookie")) {
     response.setHeader("Set-Cookie", "myKey=laxSameSiteCookie; samesite=lax", true);
     response.setHeader("Content-Type", "image/png");
     response.write(IMG_BYTES);
     return;
   }
 
   // save the object state of the initial request, which returns
   // async once the server has processed the img request.
-  if (request.queryString === "queryresult") {
+  if (request.queryString.includes("queryresult")) {
     response.processAsync();
     setObjectState("queryResult", response);
     return;
   }
 
-  if (request.queryString === "loadFrame") {
+  if (request.queryString.includes("loadFrame")) {
     response.write(FRAME);
     return;
   }
 
-  if (request.queryString === "loadWin") {
+  if (request.queryString.includes("loadWin")) {
     var cookie = "unitialized";
     if (request.hasHeader("Cookie")) {
       cookie = request.getHeader("Cookie");
     }
     else {
       cookie = "myKey=noCookie";
     }
     response.write(WIN);
--- a/dom/security/test/general/test_same_site_cookies_cross_origin_context.html
+++ b/dom/security/test/general/test_same_site_cookies_cross_origin_context.html
@@ -19,69 +19,89 @@
  *    in the context of http://mochi.test
  * 2) We load an iframe from http://example.com and check if the cookie
  *    is available.
  * 3) We observe that:
  *    (a) same site cookie has been discarded in a cross origin context.
  *    (b) the regular cookie is available.
  */
 
+SimpleTest.registerCleanupFunction(() => {
+  SpecialPowers.clearUserPref("network.cookie.same-site.enabled");
+});
 SimpleTest.waitForExplicitFinish();
 
 const CROSS_ORIGIN = "http://example.com/";
 const PATH = "tests/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs";
 
 let curTest = 0;
 
 var tests = [
   {
-    description: "regular cookie in cross origin context",
+    description: "regular cookie in cross origin context (same-site: on)",
     imgSRC: CROSS_ORIGIN + PATH + "?setRegularCookie",
     frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=regularCookie",
   },
   {
-    description: "same-site cookie in cross origin context",
+    description: "same-site cookie in cross origin context (same-site: on)",
     imgSRC: CROSS_ORIGIN + PATH + "?setSameSiteCookie",
     frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "", // no cookie should be set
   },
+  {
+    description: "regular cookie in cross origin context (same-site: off)",
+    imgSRC: CROSS_ORIGIN + PATH + "?setRegularCookie",
+    frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=regularCookie",
+  },
+  {
+    description: "same-site cookie in cross origin context (same-site: off)",
+    imgSRC: CROSS_ORIGIN + PATH + "?setSameSiteCookie",
+    frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=strictSameSiteCookie",
+  },
 ];
 
 
 window.addEventListener("message", receiveMessage);
 function receiveMessage(event) {
   is(event.data.result, tests[curTest].result, tests[curTest].description);
   curTest += 1;
 
-  // // lets see if we ran all the tests
+  // lets see if we ran all the tests
   if (curTest == tests.length) {
     window.removeEventListener("message", receiveMessage);
     SimpleTest.finish();
     return;
   }
   // otherwise it's time to run the next test
   setCookieAndInitTest();
 }
 
 function setupQueryResultAndRunTest() {
   let testframe = document.getElementById("testframe");
-  testframe.src = tests[curTest].frameSRC;
+  testframe.src = tests[curTest].frameSRC + curTest;
 }
 
 function setCookieAndInitTest() {
+  SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled);
   var cookieImage = document.getElementById("cookieImage");
   cookieImage.onload = function() {
     ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
     setupQueryResultAndRunTest();
   }
   cookieImage.onerror = function() {
     ok(false, "could not load image for test (" + tests[curTest].description + ")");
   }
-  cookieImage.src =  tests[curTest].imgSRC;
+  cookieImage.src =  tests[curTest].imgSRC + curTest;
 }
 
 // fire up the test
 setCookieAndInitTest();
 
 </script>
 </body>
 </html>
--- a/dom/security/test/general/test_same_site_cookies_from_script.html
+++ b/dom/security/test/general/test_same_site_cookies_from_script.html
@@ -18,37 +18,56 @@
  *    inline script in top-level context of http://mochi.test.
  * 2) We load an iframe from http://example.com and check if the cookie
  *    is available.
  * 3) We observe that:
  *    (a) same site cookie is available in same origin context.
  *    (a) same site cookie has been discarded in a cross origin context.
  */
 
+SimpleTest.registerCleanupFunction(() => {
+  SpecialPowers.clearUserPref("network.cookie.same-site.enabled");
+});
 SimpleTest.waitForExplicitFinish();
 
 const SAME_ORIGIN = "http://mochi.test:8888/";
 const CROSS_ORIGIN = "http://example.com/";
 const PATH = "tests/dom/security/test/general/file_same_site_cookies_from_script.sjs";
 
 let curTest = 0;
 
 var tests = [
   {
     description: "same-site cookie inline script within same-site context",
     setCookieSrc: SAME_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript",
     getCookieSrc: SAME_ORIGIN + PATH + "?getCookieFrame",
+    sameSiteEnabled: true,
     result: "myKey=sameSiteCookieInlineScript",
   },
   {
     description: "same-site cookie inline script within cross-site context",
     setCookieSrc: CROSS_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript",
     getCookieSrc: CROSS_ORIGIN + PATH + "?getCookieFrame",
+    sameSiteEnabled: true,
     result: "", // same-site cookie should be discarded in cross site context
   },
+  {
+    description: "same-site cookie inline script within same-site context",
+    setCookieSrc: SAME_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript",
+    getCookieSrc: SAME_ORIGIN + PATH + "?getCookieFrame",
+    sameSiteEnabled: false,
+    result: "myKey=sameSiteCookieInlineScript",
+  },
+  {
+    description: "same-site cookie inline script within cross-site context",
+    setCookieSrc: CROSS_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript",
+    getCookieSrc: CROSS_ORIGIN + PATH + "?getCookieFrame",
+    sameSiteEnabled: false,
+    result: "myKey=sameSiteCookieInlineScript",
+  },
 ];
 
 window.addEventListener("message", receiveMessage);
 function receiveMessage(event) {
   is(event.data.result, tests[curTest].result, tests[curTest].description);
   curTest += 1;
 
   // lets see if we ran all the tests
@@ -58,29 +77,30 @@ function receiveMessage(event) {
     return;
   }
   // otherwise it's time to run the next test
   setCookieAndInitTest();
 }
 
 function setupQueryResultAndRunTest() {
   let getCookieFrame = document.getElementById("getCookieFrame");
-  getCookieFrame.src = tests[curTest].getCookieSrc;
+  getCookieFrame.src = tests[curTest].getCookieSrc + curTest;
 }
 
 function setCookieAndInitTest() {
+  SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled);
   var cookieFrame = document.getElementById("setCookieFrame");
   setCookieFrame.onload = function() {
     ok(true, "trying to set cookie for test (" + tests[curTest].description + ")");
     setupQueryResultAndRunTest();
   }
   setCookieFrame.onerror = function() {
     ok(false, "could not load image for test (" + tests[curTest].description + ")");
   }
-  cookieFrame.src =  tests[curTest].setCookieSrc;
+  cookieFrame.src =  tests[curTest].setCookieSrc + curTest;
 }
 
 // fire up the test
 setCookieAndInitTest();
 
 </script>
 </body>
 </html>
--- a/dom/security/test/general/test_same_site_cookies_subrequest.html
+++ b/dom/security/test/general/test_same_site_cookies_subrequest.html
@@ -22,49 +22,84 @@
  *
  * In detail:
  * We perform an XHR request to the *.sjs file which is processed async on
  * the server and waits till the image request has been processed by the server.
  * Once the image requets was processed, the server responds to the initial
  * XHR request with the expecuted result (the cookie value).
  */
 
+SimpleTest.registerCleanupFunction(() => {
+  SpecialPowers.clearUserPref("network.cookie.same-site.enabled");
+});
 SimpleTest.waitForExplicitFinish();
 
 const SAME_ORIGIN = "http://mochi.test:8888/";
 const CROSS_ORIGIN = "http://example.com/";
 const PATH = "tests/dom/security/test/general/file_same_site_cookies_subrequest.sjs";
 
 let curTest = 0;
 
 var tests = [
   {
     description: "same origin site using cookie policy 'samesite=strict'",
     imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
     frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=strictSameSiteCookie",
   },
   {
     description: "cross origin site using cookie policy 'samesite=strict'",
     imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
     frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=noCookie",
   },
   {
     description: "same origin site using cookie policy 'samesite=lax'",
     imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
     frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=laxSameSiteCookie",
   },
   {
     description: "cross origin site using cookie policy 'samesite=lax'",
     imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
     frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=noCookie",
   },
+  {
+    description: "same origin site using cookie policy 'samesite=strict'",
+    imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+    frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=strictSameSiteCookie",
+  },
+  {
+    description: "cross origin site using cookie policy 'samesite=strict'",
+    imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+    frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=strictSameSiteCookie",
+  },
+  {
+    description: "same origin site using cookie policy 'samesite=lax'",
+    imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+    frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=laxSameSiteCookie",
+  },
+  {
+    description: "cross origin site using cookie policy 'samesite=lax'",
+    imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+    frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=laxSameSiteCookie",
+  },
 ];
 
 function checkResult(aCookieVal) {
   is(aCookieVal, tests[curTest].result, tests[curTest].description);
   curTest += 1;
 
   // lets see if we ran all the tests
   if (curTest == tests.length) {
@@ -72,42 +107,43 @@ function checkResult(aCookieVal) {
     return;
   }
   // otherwise it's time to run the next test
   setCookieAndInitTest();
 }
 
 function setupQueryResultAndRunTest() {
   var myXHR = new XMLHttpRequest();
-  myXHR.open("GET", "file_same_site_cookies_subrequest.sjs?queryresult");
+  myXHR.open("GET", "file_same_site_cookies_subrequest.sjs?queryresult" + curTest);
   myXHR.onload = function(e) {
     checkResult(myXHR.responseText);
   }
   myXHR.onerror = function(e) {
     ok(false, "could not query results from server (" + e.message + ")");
   }
   myXHR.send();
 
   // give it some time and load the test frame
   SimpleTest.executeSoon(function() {
     let testframe = document.getElementById("testframe");
-    testframe.src = tests[curTest].frameSRC;
+    testframe.src = tests[curTest].frameSRC + curTest;
   });
 }
 
 function setCookieAndInitTest() {
+  SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled);
   var cookieImage = document.getElementById("cookieImage");
   cookieImage.onload = function() {
     ok(true, "set cookie for test (" + tests[curTest].description + ")");
     setupQueryResultAndRunTest();
   }
   cookieImage.onerror = function() {
     ok(false, "could not set cookie for test (" + tests[curTest].description + ")");
   }
-  cookieImage.src = tests[curTest].imgSRC;
+  cookieImage.src = tests[curTest].imgSRC + curTest;
 }
 
 // fire up the test
 setCookieAndInitTest();
 
 </script>
 </body>
 </html>
--- a/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
+++ b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
@@ -23,47 +23,82 @@
  *
  * In detail:
  * We perform an XHR request to the *.sjs file which is processed async on
  * the server and waits till the image request has been processed by the server.
  * Once the image requets was processed, the server responds to the initial
  * XHR request with the expecuted result (the cookie value).
  */
 
+SimpleTest.registerCleanupFunction(() => {
+  SpecialPowers.clearUserPref("network.cookie.same-site.enabled");
+});
 SimpleTest.waitForExplicitFinish();
 
 const SAME_ORIGIN = "http://mochi.test:8888/";
 const CROSS_ORIGIN = "http://example.com/";
 const PATH = "tests/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs";
 
 let curTest = 0;
 
 var tests = [
   {
     description: "same origin navigation using cookie policy 'samesite=strict'",
     imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
     frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=strictSameSiteCookie",
   },
   {
     description: "cross origin navigation using cookie policy 'samesite=strict'",
     imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
     frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=noCookie",
   },
   {
     description: "same origin navigation using cookie policy 'samesite=lax'",
     imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
     frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
     result: "myKey=laxSameSiteCookie",
   },
   {
     description: "cross origin navigation using cookie policy 'samesite=lax'",
     imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
     frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: true,
+    result: "myKey=laxSameSiteCookie",
+  },
+  {
+    description: "same origin navigation using cookie policy 'samesite=strict'",
+    imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+    frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=strictSameSiteCookie",
+  },
+  {
+    description: "cross origin navigation using cookie policy 'samesite=strict'",
+    imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie",
+    frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=strictSameSiteCookie",
+  },
+  {
+    description: "same origin navigation using cookie policy 'samesite=lax'",
+    imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+    frameSRC: SAME_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
+    result: "myKey=laxSameSiteCookie",
+  },
+  {
+    description: "cross origin navigation using cookie policy 'samesite=lax'",
+    imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie",
+    frameSRC: CROSS_ORIGIN + PATH + "?loadFrame",
+    sameSiteEnabled: false,
     result: "myKey=laxSameSiteCookie",
   },
 ];
 
 function checkResult(aCookieVal) {
   is(aCookieVal, tests[curTest].result, tests[curTest].description);
   curTest += 1;
 
@@ -73,42 +108,43 @@ function checkResult(aCookieVal) {
     return;
   }
   // otherwise it's time to run the next test
   setCookieAndInitTest();
 }
 
 function setupQueryResultAndRunTest() {
   var myXHR = new XMLHttpRequest();
-  myXHR.open("GET", "file_same_site_cookies_toplevel_nav.sjs?queryresult");
+  myXHR.open("GET", "file_same_site_cookies_toplevel_nav.sjs?queryresult" + curTest);
   myXHR.onload = function(e) {
     checkResult(myXHR.responseText);
   }
   myXHR.onerror = function(e) {
     ok(false, "could not query results from server (" + e.message + ")");
   }
   myXHR.send();
 
   // give it some time and load the test window
   SimpleTest.executeSoon(function() {
     let testframe = document.getElementById("testframe");
-    testframe.src = tests[curTest].frameSRC;
+    testframe.src = tests[curTest].frameSRC + curTest;
   });
 }
 
 function setCookieAndInitTest() {
+  SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled);
   var cookieImage = document.getElementById("cookieImage");
   cookieImage.onload = function() {
     ok(true, "set cookie for test (" + tests[curTest].description + ")");
     setupQueryResultAndRunTest();
   }
   cookieImage.onerror = function() {
     ok(false, "could not set cookie for test (" + tests[curTest].description + ")");
   }
-  cookieImage.src = tests[curTest].imgSRC;
+  cookieImage.src = tests[curTest].imgSRC + curTest;
 }
 
 // fire up the test
 setCookieAndInitTest();
 
 </script>
 </body>
 </html>
--- a/extensions/cookie/moz.build
+++ b/extensions/cookie/moz.build
@@ -6,17 +6,16 @@
 
 TEST_DIRS += ['test']
 
 UNIFIED_SOURCES += [
     'nsCookieModule.cpp',
     'nsCookiePermission.cpp',
     'nsPermission.cpp',
     'nsPermissionManager.cpp',
-    'nsPopupWindowManager.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/caps',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/extensions/cookie/nsCookieModule.cpp
+++ b/extensions/cookie/nsCookieModule.cpp
@@ -2,42 +2,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/. */
 
 
 #include "mozilla/ModuleUtils.h"
 #include "nsIServiceManager.h"
 #include "nsPermissionManager.h"
-#include "nsPopupWindowManager.h"
 #include "nsICategoryManager.h"
 #include "nsCookiePermission.h"
 #include "nsString.h"
 
 // Define the constructor function for the objects
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPermissionManager,
   nsPermissionManager::GetXPCOMSingleton)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPopupWindowManager, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePermission)
 
 NS_DEFINE_NAMED_CID(NS_PERMISSIONMANAGER_CID);
-NS_DEFINE_NAMED_CID(NS_POPUPWINDOWMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_COOKIEPERMISSION_CID);
 
 
 static const mozilla::Module::CIDEntry kCookieCIDs[] = {
     { &kNS_PERMISSIONMANAGER_CID, false, nullptr, nsIPermissionManagerConstructor },
-    { &kNS_POPUPWINDOWMANAGER_CID, false, nullptr, nsPopupWindowManagerConstructor },
     { &kNS_COOKIEPERMISSION_CID, false, nullptr, nsCookiePermissionConstructor },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kCookieContracts[] = {
     { NS_PERMISSIONMANAGER_CONTRACTID, &kNS_PERMISSIONMANAGER_CID },
-    { NS_POPUPWINDOWMANAGER_CONTRACTID, &kNS_POPUPWINDOWMANAGER_CID },
     { NS_COOKIEPERMISSION_CONTRACTID, &kNS_COOKIEPERMISSION_CID },
     { nullptr }
 };
 
 static const mozilla::Module kCookieModule = {
     mozilla::Module::kVersion,
     kCookieCIDs,
     kCookieContracts
deleted file mode 100644
--- a/extensions/cookie/nsPopupWindowManager.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsPopupWindowManager.h"
-
-#include "nsCRT.h"
-#include "nsIServiceManager.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
-#include "nsIPrincipal.h"
-#include "nsIURI.h"
-#include "mozilla/Services.h"
-
-/**
- * The Popup Window Manager maintains popup window permissions by website.
- */
-
-static const char kPopupDisablePref[] = "dom.disable_open_during_load";
-
-//*****************************************************************************
-//*** nsPopupWindowManager object management and nsISupports
-//*****************************************************************************
-
-nsPopupWindowManager::nsPopupWindowManager() :
-  mPolicy(ALLOW_POPUP)
-{
-}
-
-nsPopupWindowManager::~nsPopupWindowManager()
-{
-}
-
-NS_IMPL_ISUPPORTS(nsPopupWindowManager,
-                  nsIPopupWindowManager,
-                  nsIObserver,
-                  nsISupportsWeakReference)
-
-nsresult
-nsPopupWindowManager::Init()
-{
-  nsresult rv;
-  mPermissionManager = mozilla::services::GetPermissionManager();
-
-  nsCOMPtr<nsIPrefBranch> prefBranch =
-    do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
-  if (NS_SUCCEEDED(rv)) {
-    bool permission;
-    rv = prefBranch->GetBoolPref(kPopupDisablePref, &permission);
-    if (NS_FAILED(rv)) {
-      permission = true;
-    }
-    mPolicy = permission ? (uint32_t) DENY_POPUP : (uint32_t) ALLOW_POPUP;
-
-    prefBranch->AddObserver(kPopupDisablePref, this, true);
-  }
-
-  return NS_OK;
-}
-
-//*****************************************************************************
-//*** nsPopupWindowManager::nsIPopupWindowManager
-//*****************************************************************************
-
-NS_IMETHODIMP
-nsPopupWindowManager::TestPermission(nsIPrincipal* aPrincipal,
-                                     uint32_t *aPermission)
-{
-  NS_ENSURE_ARG_POINTER(aPrincipal);
-  NS_ENSURE_ARG_POINTER(aPermission);
-
-  uint32_t permit;
-  *aPermission = mPolicy;
-
-  if (mPermissionManager) {
-    if (NS_SUCCEEDED(mPermissionManager->TestPermissionFromPrincipal(aPrincipal, "popup", &permit))) {
-      // Share some constants between interfaces?
-      if (permit == nsIPermissionManager::ALLOW_ACTION) {
-        *aPermission = ALLOW_POPUP;
-      } else if (permit == nsIPermissionManager::DENY_ACTION) {
-        *aPermission = DENY_POPUP;
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-//*****************************************************************************
-//*** nsPopupWindowManager::nsIObserver
-//*****************************************************************************
-NS_IMETHODIMP
-nsPopupWindowManager::Observe(nsISupports *aSubject,
-                              const char *aTopic,
-                              const char16_t *aData)
-{
-  nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
-  NS_ASSERTION(!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic),
-               "unexpected topic - we only deal with pref changes!");
-
-  if (prefBranch) {
-    // refresh our local copy of the "disable popups" pref
-    bool permission = true;
-    prefBranch->GetBoolPref(kPopupDisablePref, &permission);
-
-    mPolicy = permission ? (uint32_t) DENY_POPUP : (uint32_t) ALLOW_POPUP;
-  }
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/extensions/cookie/nsPopupWindowManager.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsPopupWindowManager_h__
-#define nsPopupWindowManager_h__
-
-#include "nsCOMPtr.h"
-
-#include "nsIObserver.h"
-#include "nsIPermissionManager.h"
-#include "nsIPopupWindowManager.h"
-#include "nsWeakReference.h"
-
-class nsPopupWindowManager : public nsIPopupWindowManager,
-                             public nsIObserver,
-                             public nsSupportsWeakReference {
-
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIPOPUPWINDOWMANAGER
-  NS_DECL_NSIOBSERVER
-
-  nsPopupWindowManager();
-  nsresult Init();
-
-private:
-  virtual ~nsPopupWindowManager();
-
-  uint32_t                       mPolicy;
-  nsCOMPtr<nsIPermissionManager> mPermissionManager;
-};
-
-// {822bcd11-6432-48be-9e9d-36f7804b7747}
-#define NS_POPUPWINDOWMANAGER_CID \
- {0x822bcd11, 0x6432, 0x48be, {0x9e, 0x9d, 0x36, 0xf7, 0x80, 0x4b, 0x77, 0x47}}
-
-#endif /* nsPopupWindowManager_h__ */
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -1130,20 +1130,52 @@ struct ScrollableLayerGuid {
       }
       if (mPresShellId == other.mPresShellId) {
         return mScrollId < other.mScrollId;
       }
     }
     return false;
   }
 
-  PLDHashNumber Hash() const
+  // Helper structs to use as hash/equality functions in std::unordered_map. e.g.
+  // std::unordered_map<ScrollableLayerGuid,
+  //                    ValueType,
+  //                    ScrollableLayerGuid::HashFn> myMap;
+  // std::unordered_map<ScrollableLayerGuid,
+  //                    ValueType,
+  //                    ScrollableLayerGuid::HashIgnoringPresShellFn,
+  //                    ScrollableLayerGuid::EqualIgnoringPresShellFn> myMap;
+
+  struct HashFn
   {
-    return HashGeneric(uint64_t(mLayersId), mPresShellId, mScrollId);
-  }
+    std::size_t operator()(const ScrollableLayerGuid& aGuid) const
+    {
+      return HashGeneric(uint64_t(aGuid.mLayersId),
+                         aGuid.mPresShellId,
+                         aGuid.mScrollId);
+    }
+  };
+
+  struct HashIgnoringPresShellFn
+  {
+    std::size_t operator()(const ScrollableLayerGuid& aGuid) const
+    {
+      return HashGeneric(uint64_t(aGuid.mLayersId),
+                         aGuid.mScrollId);
+    }
+  };
+
+  struct EqualIgnoringPresShellFn
+  {
+    bool operator()(const ScrollableLayerGuid& lhs, const ScrollableLayerGuid& rhs) const
+    {
+      return lhs.mLayersId == rhs.mLayersId
+          && lhs.mScrollId == rhs.mScrollId;
+    }
+  };
 };
 
 template <int LogLevel>
 gfx::Log<LogLevel>& operator<<(gfx::Log<LogLevel>& log, const ScrollableLayerGuid& aGuid) {
   return log << '(' << uint64_t(aGuid.mLayersId) << ',' << aGuid.mPresShellId << ',' << aGuid.mScrollId << ')';
 }
 
 struct ZoomConstraints {
@@ -1194,23 +1226,15 @@ struct ZoomConstraints {
   }
 
   bool operator!=(const ZoomConstraints& other) const
   {
     return !(*this == other);
   }
 };
 
-struct ScrollableLayerGuidHash
-{
-  std::size_t operator()(const ScrollableLayerGuid& Guid) const
-  {
-    return Guid.Hash();
-  }
-};
-
 
 typedef Maybe<ZoomConstraints> MaybeZoomConstraints;
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_FRAMEMETRICS_H */
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -96,18 +96,24 @@ struct APZCTreeManager::TreeBuildingStat
 
   // A list of nodes that need to be destroyed at the end of the tree building.
   // This is initialized with all nodes in the old tree, and nodes are removed
   // from it as we reuse them in the new tree.
   nsTArray<RefPtr<HitTestingTreeNode>> mNodesToDestroy;
 
   // This map is populated as we place APZCs into the new tree. Its purpose is
   // to facilitate re-using the same APZC for different layers that scroll
-  // together (and thus have the same ScrollableLayerGuid).
-  std::unordered_map<ScrollableLayerGuid, AsyncPanZoomController*, ScrollableLayerGuidHash> mApzcMap;
+  // together (and thus have the same ScrollableLayerGuid). The presShellId
+  // doesn't matter for this purpose, and we move the map to the APZCTreeManager
+  // after we're done building, so it's useful to have the presshell-ignoring
+  // map for that.
+  std::unordered_map<ScrollableLayerGuid,
+                     RefPtr<AsyncPanZoomController>,
+                     ScrollableLayerGuid::HashIgnoringPresShellFn,
+                     ScrollableLayerGuid::EqualIgnoringPresShellFn> mApzcMap;
 
   // As the tree is traversed, the top element of this stack tracks whether
   // the parent scroll node has a perspective transform.
   std::stack<bool> mParentHasPerspective;
 
   // During the tree building process, the perspective transform component
   // of the ancestor transforms of some APZCs can be "deferred" to their
   // children, meaning they are added to the children's ancestor transforms
@@ -224,16 +230,17 @@ private:
 };
 
 APZCTreeManager::APZCTreeManager(LayersId aRootLayersId)
     : mInputQueue(new InputQueue()),
       mRootLayersId(aRootLayersId),
       mSampler(nullptr),
       mUpdater(nullptr),
       mTreeLock("APZCTreeLock"),
+      mMapLock("APZCMapLock"),
       mHitResultForInputBlock(CompositorHitTestInfo::eInvisibleToHitTest),
       mRetainedTouchIdentifier(-1),
       mInScrollbarTouchDrag(false),
       mApzcTreeLog("apzctree"),
       mTestDataLock("APZTestDataLock"),
       mDPI(160.0)
 {
   RefPtr<APZCTreeManager> self(this);
@@ -468,16 +475,22 @@ APZCTreeManager::UpdateHitTestingTreeImp
             }
           });
     }
   }
 
   // We do not support tree structures where the root node has siblings.
   MOZ_ASSERT(!(mRootNode && mRootNode->GetPrevSibling()));
 
+  { // scope lock and update our mApzcMap before we destroy all the unused
+    // APZC instances
+    MutexAutoLock lock(mMapLock);
+    mApzcMap = Move(state.mApzcMap);
+  }
+
   for (size_t i = 0; i < state.mNodesToDestroy.Length(); i++) {
     APZCTM_LOG("Destroying node at %p with APZC %p\n",
         state.mNodesToDestroy[i].get(),
         state.mNodesToDestroy[i]->GetApzc());
     state.mNodesToDestroy[i]->Destroy();
   }
 
 #if ENABLE_APZCTM_LOGGING
@@ -538,17 +551,22 @@ APZCTreeManager::PushStateToWR(wr::Trans
 
   RecursiveMutexAutoLock lock(mTreeLock);
 
   // During the first pass through the tree, we build a cache of guid->HTTN so
   // that we can find the relevant APZC instances quickly in subsequent passes,
   // such as the one below to generate scrollbar transforms. Without this, perf
   // could end up being O(n^2) instead of O(n log n) because we'd have to search
   // the tree to find the corresponding APZC every time we hit a thumb node.
-  std::unordered_map<ScrollableLayerGuid, HitTestingTreeNode*, ScrollableLayerGuidHash> httnMap;
+  // We use the presShell-ignoring map because when we do a lookup in the map
+  // for the scrollbar, we don't have (or care about) the presShellId.
+  std::unordered_map<ScrollableLayerGuid,
+                     HitTestingTreeNode*,
+                     ScrollableLayerGuid::HashIgnoringPresShellFn,
+                     ScrollableLayerGuid::EqualIgnoringPresShellFn> httnMap;
 
   bool activeAnimations = false;
   LayersId lastLayersId{(uint64_t)-1};
   wr::WrPipelineId lastPipelineId;
 
   // We iterate backwards here because the HitTestingTreeNode is optimized
   // for backwards iteration. The equivalent code in AsyncCompositionManager
   // iterates forwards, but the direction shouldn't really matter in practice
@@ -577,20 +595,17 @@ APZCTreeManager::PushStateToWR(wr::Trans
             // that has already been torn down. In that case just skip over
             // those layers.
             return;
           }
           lastPipelineId = wrBridge->PipelineId();
           lastLayersId = aNode->GetLayersId();
         }
 
-        // Use a 0 presShellId because when we do a lookup in this map for the
-        // scrollbar below we don't have (or care about) the presShellId.
-        ScrollableLayerGuid guid(lastLayersId, 0, apzc->GetGuid().mScrollId);
-        httnMap.emplace(guid, aNode);
+        httnMap.emplace(apzc->GetGuid(), aNode);
 
         ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform(
             AsyncPanZoomController::eForCompositing).mTranslation;
         // The positive translation means the painted content is supposed to
         // move down (or to the right), and that corresponds to a reduction in
         // the scroll offset. Since we are effectively giving WR the async
         // scroll delta here, we want to negate the translation.
         ParentLayerPoint asyncScrollDelta = -layerTranslation;
@@ -2339,21 +2354,20 @@ GuidComparatorIgnoringPresShell(const Sc
   return aOne.mLayersId == aTwo.mLayersId
       && aOne.mScrollId == aTwo.mScrollId;
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTargetAPZC(const LayersId& aLayersId,
                                const FrameMetrics::ViewID& aScrollId)
 {
-  RecursiveMutexAutoLock lock(mTreeLock);
+  MutexAutoLock lock(mMapLock);
   ScrollableLayerGuid guid(aLayersId, 0, aScrollId);
-  RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
-  MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
-  RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
+  auto it = mApzcMap.find(guid);
+  RefPtr<AsyncPanZoomController> apzc = (it != mApzcMap.end() ? it->second : nullptr);
   return apzc.forget();
 }
 
 already_AddRefed<HitTestingTreeNode>
 APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid,
                                GuidComparator aComparator) const
 {
   mTreeLock.AssertCurrentThreadIn();
@@ -2425,21 +2439,17 @@ APZCTreeManager::GetAPZCAtPointWR(const 
   gfx::CompositorHitTestInfo hitInfo;
   bool hitSomething = wr->HitTest(wr::ToWorldPoint(aHitTestPoint),
       pipelineId, scrollId, hitInfo);
   if (!hitSomething) {
     return result.forget();
   }
 
   LayersId layersId = wr::AsLayersId(pipelineId);
-  RefPtr<HitTestingTreeNode> node = GetTargetNode(
-      ScrollableLayerGuid(layersId, 0, scrollId),
-      &GuidComparatorIgnoringPresShell);
-  MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
-  result = node ? node->GetApzc() : nullptr;
+  result = GetTargetAPZC(layersId, scrollId);
   if (!result) {
     // It falls back to the root
     // Re-enable these assertions once bug 1391318 is fixed. For now there are
     // race conditions with the WR hit-testing code that make these assertions
     // fail.
     //MOZ_ASSERT(scrollId == FrameMetrics::NULL_SCROLL_ID);
     result = FindRootApzcForLayersId(layersId);
     //MOZ_ASSERT(result);
@@ -2497,41 +2507,19 @@ APZCTreeManager::BuildOverscrollHandoffC
       }
       apzc = apzc->GetParent();
       continue;
     }
 
     // Guard against a possible infinite-loop condition. If we hit this, the
     // layout code that generates the handoff parents did something wrong.
     MOZ_ASSERT(apzc->GetScrollHandoffParentId() != apzc->GetGuid().mScrollId);
-
-    // Find the AsyncPanZoomController instance with a matching layersId and
-    // the scroll id that matches apzc->GetScrollHandoffParentId().
-    // As an optimization, we start by walking up the APZC tree from 'apzc'
-    // until we reach the top of the layer subtree for this layers id.
-    AsyncPanZoomController* scrollParent = nullptr;
-    AsyncPanZoomController* parent = apzc;
-    while (!parent->HasNoParentWithSameLayersId()) {
-      parent = parent->GetParent();
-      // While walking up to find the root of the subtree, if we encounter the
-      // handoff parent, we don't actually need to do the search so we can
-      // just abort here.
-      if (parent->GetGuid().mScrollId == apzc->GetScrollHandoffParentId()) {
-        scrollParent = parent;
-        break;
-      }
-    }
-    // If that heuristic didn't turn up the scroll parent, do a full tree search.
-    if (!scrollParent) {
-      ScrollableLayerGuid guid(parent->GetGuid().mLayersId, 0, apzc->GetScrollHandoffParentId());
-      RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
-      MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
-      scrollParent = node ? node->GetApzc() : nullptr;
-    }
-    apzc = scrollParent;
+    RefPtr<AsyncPanZoomController> scrollParent =
+        GetTargetAPZC(apzc->GetGuid().mLayersId, apzc->GetScrollHandoffParentId());
+    apzc = scrollParent.get();
   }
 
   // Now adjust the chain to account for scroll grabbing. Sorting is a bit
   // of an overkill here, but scroll grabbing will likely be generalized
   // to scroll priorities, so we might as well do it this way.
   result->SortByScrollPriority();
 
   // Print the overscroll chain for debugging.
@@ -2572,20 +2560,20 @@ APZCTreeManager::GetTargetApzcForNode(Hi
   for (const HitTestingTreeNode* n = aNode;
        n && n->GetLayersId() == aNode->GetLayersId();
        n = n->GetParent()) {
     if (n->GetApzc()) {
       APZCTM_LOG("Found target %p using ancestor lookup\n", n->GetApzc());
       return n->GetApzc();
     }
     if (n->GetFixedPosTarget() != FrameMetrics::NULL_SCROLL_ID) {
-      ScrollableLayerGuid guid(n->GetLayersId(), 0, n->GetFixedPosTarget());
-      RefPtr<HitTestingTreeNode> fpNode = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
-      APZCTM_LOG("Found target node %p using fixed-pos lookup on %" PRIu64 "\n", fpNode.get(), n->GetFixedPosTarget());
-      return fpNode ? fpNode->GetApzc() : nullptr;
+      RefPtr<AsyncPanZoomController> fpTarget =
+          GetTargetAPZC(n->GetLayersId(), n->GetFixedPosTarget());
+      APZCTM_LOG("Found target APZC %p using fixed-pos lookup on %" PRIu64 "\n", fpTarget.get(), n->GetFixedPosTarget());
+      return fpTarget.get();
     }
   }
   return nullptr;
 }
 
 AsyncPanZoomController*
 APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
                                 const ScreenPoint& aHitTestPoint,
@@ -2655,20 +2643,20 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti
         if (n->GetScrollbarDirection() == ScrollDirection::eVertical) {
           *aOutHitResult |= CompositorHitTestInfo::eScrollbarVertical;
         }
 
         // If we hit a scrollbar, target the APZC for the content scrolled
         // by the scrollbar. (The scrollbar itself doesn't scroll with the
         // scrolled content, so it doesn't carry the scrolled content's
         // scroll metadata).
-        ScrollableLayerGuid guid(n->GetLayersId(), 0, n->GetScrollTargetId());
-        if (RefPtr<HitTestingTreeNode> scrollTarget = GetTargetNode(guid, &GuidComparatorIgnoringPresShell)) {
-          MOZ_ASSERT(scrollTarget->GetApzc());
-          return scrollTarget->GetApzc();
+        RefPtr<AsyncPanZoomController> scrollTarget =
+            GetTargetAPZC(n->GetLayersId(), n->GetScrollTargetId());
+        if (scrollTarget) {
+          return scrollTarget.get();
         }
       }
     }
 
     AsyncPanZoomController* result = GetTargetApzcForNode(resultNode);
     if (!result) {
       result = FindRootApzcForLayersId(resultNode->GetLayersId());
       MOZ_ASSERT(result);
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -47,35 +47,35 @@ class AsyncPanZoomController;
 class APZCTreeManagerParent;
 class APZSampler;
 class APZUpdater;
 class CompositorBridgeParent;
 class OverscrollHandoffChain;
 struct OverscrollHandoffState;
 class FocusTarget;
 struct FlingHandoffState;
-struct ScrollableLayerGuidHash;
 class LayerMetricsWrapper;
 class InputQueue;
 class GeckoContentController;
 class HitTestingTreeNode;
 class WebRenderScrollDataWrapper;
 struct AncestorTransform;
 struct ScrollThumbData;
 
 /**
  * ****************** NOTE ON LOCK ORDERING IN APZ **************************
  *
  * There are two main kinds of locks used by APZ: APZCTreeManager::mTreeLock
  * ("the tree lock") and AsyncPanZoomController::mRecursiveMutex ("APZC locks").
- * There is also the APZCTreeManager::mTestDataLock ("test lock").
+ * There is also the APZCTreeManager::mTestDataLock ("test lock") and
+ * APZCTreeManager::mMapLock ("map lock").
  *
  * To avoid deadlock, we impose a lock ordering between these locks, which is:
  *
- *      tree lock -> APZC locks -> test lock
+ *      tree lock -> map lock -> APZC locks -> test lock
  *
  * The interpretation of the lock ordering is that if lock A precedes lock B
  * in the ordering sequence, then you must NOT wait on A while holding B.
  *
  * **************************************************************************
  */
 
 /**
@@ -728,20 +728,32 @@ private:
    * This lock does not need to be held while manipulating a single APZC instance in
    * isolation (that is, if its tree pointers are not being accessed or mutated). The
    * lock also needs to be held when accessing the mRootNode instance variable, as that
    * is considered part of the APZC tree management state.
    * IMPORTANT: See the note about lock ordering at the top of this file. */
   mutable mozilla::RecursiveMutex mTreeLock;
   RefPtr<HitTestingTreeNode> mRootNode;
 
+  /* A map for quick access to get APZC instances by guid, without having to
+   * acquire the tree lock. mMapLock must be acquired while accessing or
+   * modifying mApzcMap.
+   */
+  mutable mozilla::Mutex mMapLock;
+  std::unordered_map<ScrollableLayerGuid,
+                     RefPtr<AsyncPanZoomController>,
+                     ScrollableLayerGuid::HashIgnoringPresShellFn,
+                     ScrollableLayerGuid::EqualIgnoringPresShellFn> mApzcMap;
+
   /* Holds the zoom constraints for scrollable layers, as determined by the
    * the main-thread gecko code. This can only be accessed on the updater
    * thread. */
-  std::unordered_map<ScrollableLayerGuid, ZoomConstraints, ScrollableLayerGuidHash> mZoomConstraints;
+  std::unordered_map<ScrollableLayerGuid,
+                     ZoomConstraints,
+                     ScrollableLayerGuid::HashFn> mZoomConstraints;
   /* A list of keyboard shortcuts to use for translating keyboard inputs into
    * keyboard actions. This is gathered on the main thread from XBL bindings.
    * This must only be accessed on the controller thread.
    */
   KeyboardMap mKeyboardMap;
   /* This tracks the focus targets of chrome and content and whether we have
    * a current focus target or whether we are waiting for a new confirmation.
    */
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs
+++ b/gfx/webrender_bindings/src/moz2d_renderer.rs
@@ -233,17 +233,19 @@ fn dump_blob_index(blob: &[u8], dirty_re
                     ""
                  }
         );
     }
 }
 
 fn check_result(result: &[u8]) -> () {
     let mut index = BlobReader::new(result);
-    assert!(index.reader.has_more(), "Unexpectedly empty result. This blob should just have been deleted");
+    // we might get an empty result here because sub groups are not tightly bound
+    // and we'll sometimes have display items that end up with empty bounds in
+    // the blob image.
     while index.reader.has_more() {
         let e = index.read_entry();
         dlog!("result bounds: {} {} {:?}", e.end, e.extra_end, e.bounds);
     }
 }
 
 // We use a BTree as a kind of multi-map, by appending an integer "cache_order" to the key.
 // This lets us use multiple items with matching bounds in the map and allows
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -1172,17 +1172,17 @@ ToDisassemblySource(JSContext* cx, Handl
         if (obj.is<RegExpObject>()) {
             JSString* source = obj.as<RegExpObject>().toString(cx);
             if (!source)
                 return false;
             return bytes->encodeLatin1(cx, source);
         }
     }
 
-    return !!ValueToPrintable(cx, v, bytes, true);
+    return !!ValueToPrintableLatin1(cx, v, bytes, true);
 }
 
 static bool
 ToDisassemblySource(JSContext* cx, HandleScope scope, JSAutoByteString* bytes)
 {
     UniqueChars source = JS_smprintf("%s {", ScopeKindString(scope->kind()));
     if (!source) {
         ReportOutOfMemory(cx);
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -1413,17 +1413,17 @@ LiveEnvironmentVal::staticAsserts()
 /*****************************************************************************/
 
 namespace {
 
 static void
 ReportOptimizedOut(JSContext* cx, HandleId id)
 {
     JSAutoByteString printable;
-    if (ValueToPrintable(cx, IdToValue(id), &printable)) {
+    if (ValueToPrintableLatin1(cx, IdToValue(id), &printable)) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_OPTIMIZED_OUT,
                                    printable.ptr());
     }
 }
 
 /*
  * DebugEnvironmentProxy is the handler for DebugEnvironmentProxy proxy
  * objects. Having a custom handler (rather than trying to reuse js::Wrapper)
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -175,17 +175,18 @@ enum class GetNameMode { Normal, TypeOf 
 template <GetNameMode mode>
 inline bool
 FetchName(JSContext* cx, HandleObject receiver, HandleObject holder, HandlePropertyName name,
           Handle<PropertyResult> prop, MutableHandleValue vp)
 {
     if (!prop) {
         switch (mode) {
           case GetNameMode::Normal:
-            return ReportIsNotDefined(cx, name);
+            ReportIsNotDefined(cx, name);
+            return false;
           case GetNameMode::TypeOf:
             vp.setUndefined();
             return true;
         }
     }
 
     /* Take the slow path if shape was not found in a native object. */
     if (!receiver->isNative() || !holder->isNative()) {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -5061,17 +5061,17 @@ js::NewArrayOperationWithTemplate(JSCont
 }
 
 void
 js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandleId id)
 {
     MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
                errorNumber == JSMSG_BAD_CONST_ASSIGN);
     JSAutoByteString printable;
-    if (ValueToPrintable(cx, IdToValue(id), &printable))
+    if (ValueToPrintableLatin1(cx, IdToValue(id), &printable))
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, printable.ptr());
 }
 
 void
 js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandlePropertyName name)
 {
     RootedId id(cx, NameToId(name));
     ReportRuntimeLexicalError(cx, errorNumber, id);
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -875,32 +875,30 @@ js::ReportErrorNumberUCArray(JSContext* 
         return false;
     }
 
     ReportError(cx, &report, callback, userRef);
 
     return warning;
 }
 
-bool
+void
 js::ReportIsNotDefined(JSContext* cx, HandleId id)
 {
     JSAutoByteString printable;
-    if (ValueToPrintable(cx, IdToValue(id), &printable)) {
-        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED,
-                                   printable.ptr());
-    }
-    return false;
+    if (!ValueToPrintableUTF8(cx, IdToValue(id), &printable))
+        return;
+    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, printable.ptr());
 }
 
-bool
+void
 js::ReportIsNotDefined(JSContext* cx, HandlePropertyName name)
 {
     RootedId id(cx, NameToId(name));
-    return ReportIsNotDefined(cx, id);
+    ReportIsNotDefined(cx, id);
 }
 
 bool
 js::ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v,
                             HandleString fallback)
 {
     bool ok;
 
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -1026,20 +1026,20 @@ ReportUsageErrorASCII(JSContext* cx, Han
  * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
  * is true.
  * Returns false otherwise.
  */
 extern bool
 PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
            JSErrorReport* report, bool reportWarnings);
 
-extern bool
+extern void
 ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
 
-extern bool
+extern void
 ReportIsNotDefined(JSContext* cx, HandleId id);
 
 /*
  * Report an attempt to access the property of a null or undefined value (v).
  */
 extern bool
 ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v, HandleString fallback);
 
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2306,18 +2306,20 @@ enum IsNameLookup { NotNameLookup = fals
  *     Gecko code.)
  */
 static bool
 GetNonexistentProperty(JSContext* cx, HandleId id, IsNameLookup nameLookup, MutableHandleValue vp)
 {
     vp.setUndefined();
 
     // If we are doing a name lookup, this is a ReferenceError.
-    if (nameLookup)
-        return ReportIsNotDefined(cx, id);
+    if (nameLookup) {
+        ReportIsNotDefined(cx, id);
+        return false;
+    }
 
     // Give a strict warning if foo.bar is evaluated by a script for an object
     // foo with no property named 'bar'.
     //
     // Don't warn if extra warnings not enabled or for random getprop
     // operations.
     if (MOZ_LIKELY(!cx->compartment()->behaviors().extraWarnings(cx)))
         return true;
@@ -2376,18 +2378,20 @@ GeneralizedGetProperty(JSContext* cx, Ha
         //
         // If we get here, we've reached a non-native object. Fall back on the
         // algorithm as specified, with two separate lookups. (Note that we
         // throw ReferenceErrors regardless of strictness, technically a bug.)
 
         bool found;
         if (!HasProperty(cx, obj, id, &found))
             return false;
-        if (!found)
-            return ReportIsNotDefined(cx, id);
+        if (!found) {
+            ReportIsNotDefined(cx, id);
+            return false;
+        }
     }
 
     return GetProperty(cx, obj, receiver, id, vp);
 }
 
 static inline bool
 GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, const Value& receiver,
                        IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -1904,32 +1904,47 @@ JSString::fillWithRepresentatives(JSCont
     MOZ_ASSERT(index == 22);
     return true;
 }
 
 
 /*** Conversions *********************************************************************************/
 
 const char*
-js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
+js::ValueToPrintableLatin1(JSContext* cx, const Value& vArg, JSAutoByteString* bytes,
+                           bool asSource)
 {
     RootedValue v(cx, vArg);
     JSString* str;
     if (asSource)
         str = ValueToSource(cx, v);
     else
         str = ToString<CanGC>(cx, v);
     if (!str)
         return nullptr;
     str = QuoteString(cx, str, 0);
     if (!str)
         return nullptr;
     return bytes->encodeLatin1(cx, str);
 }
 
+const char*
+js::ValueToPrintableUTF8(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
+{
+    RootedValue v(cx, vArg);
+    JSString* str;
+    if (asSource)
+        str = ValueToSource(cx, v);
+    else
+        str = ToString<CanGC>(cx, v);
+    if (!str)
+        return nullptr;
+    return bytes->encodeUtf8(cx, RootedString(cx, str));
+}
+
 template <AllowGC allowGC>
 JSString*
 js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
 {
     /* As with ToObjectSlow, callers must verify that |arg| isn't a string. */
     MOZ_ASSERT(!arg.isString());
 
     Value v = arg;
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -1583,19 +1583,31 @@ HasSubstringAt(JSLinearString* text, JSL
 JSString*
 SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt);
 
 
 /*** Conversions *********************************************************************************/
 
 /*
  * Convert a value to a printable C string.
+ *
+ * As the function name implies, any characters in a converted printable string will be Latin1
+ * characters. If there are any non-Latin1 characters in the original value, then those characters
+ * will be changed to Unicode escape sequences(I.e. \udddd, dddd are 4 hex digits) in the printable
+ * string.
  */
 extern const char*
-ValueToPrintable(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
+ValueToPrintableLatin1(JSContext* cx, const Value&, JSAutoByteString* bytes,
+                       bool asSource = false);
+
+/*
+ * Convert a value to a printable C string encoded in UTF-8.
+ */
+extern const char*
+ValueToPrintableUTF8(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
 
 /*
  * Convert a non-string value to a string, returning null after reporting an
  * error, otherwise returning a new string reference.
  */
 template <AllowGC allowGC>
 extern JSString*
 ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -442,36 +442,31 @@ nsSubDocumentFrame::BuildDisplayList(nsD
       haveDisplayPort ||
       presContext->IsRootContentDocument() ||
       (sf && sf->IsScrollingActive(aBuilder)))
   {
     needsOwnLayer = true;
   }
 
   if (aBuilder->IsRetainingDisplayList()) {
-    // The value of needsOwnLayer can change between builds without
-    // an invalidation recorded for this frame (like if the root
-    // scrollframe becomes active). If this happens,
-    // then we need to notify the builder so that merging can
-    // happen correctly.
-    if (!mPreviouslyNeededLayer ||
-        mPreviouslyNeededLayer.value() != needsOwnLayer) {
-      dirty = visible;
-      aBuilder->MarkCurrentFrameModifiedDuringBuilding();
-    }
-    mPreviouslyNeededLayer = Some(needsOwnLayer);
-
     // Caret frame changed, rebuild the entire subdoc.
     // We could just invalidate the old and new frame
     // areas and save some work here. RetainedDisplayListBuilder
     // does this, so we could teach it to find and check all
     // subdocs in advance.
     if (mPreviousCaret != aBuilder->GetCaretFrame()) {
       dirty = visible;
-      aBuilder->MarkCurrentFrameModifiedDuringBuilding();
+      aBuilder->RebuildAllItemsInCurrentSubtree();
+      // Mark the old caret frame as invalid so that we remove the
+      // old nsDisplayCaret. We don't mark the current frame as invalid
+      // since we want the nsDisplaySubdocument to retain it's place
+      // in the retained display list.
+      if (mPreviousCaret) {
+        aBuilder->MarkFrameModifiedDuringBuilding(mPreviousCaret);
+      }
     }
     mPreviousCaret = aBuilder->GetCaretFrame();
   }
 
   nsDisplayList childItems;
 
   {
     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -163,17 +163,16 @@ protected:
   nsIFrame* ObtainIntrinsicSizeFrame();
 
   nsView* GetViewInternal() const override { return mOuterView; }
   void SetViewInternal(nsView* aView) override { mOuterView = aView; }
 
   RefPtr<nsFrameLoader> mFrameLoader;
   nsView* mOuterView;
   nsView* mInnerView;
-  Maybe<bool> mPreviouslyNeededLayer;
   bool mIsInline;
   bool mPostedReflowCallback;
   bool mDidCreateDoc;
   bool mCallingShow;
   WeakFrame mPreviousCaret;
 };
 
 #endif /* NSSUBDOCUMENTFRAME_H_ */
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -66,29 +66,16 @@ MarkFramesWithItemsAndImagesModified(nsD
       }
     }
     if (i->GetChildren()) {
       MarkFramesWithItemsAndImagesModified(i->GetChildren());
     }
   }
 }
 
-static bool
-IsAnyAncestorModified(nsIFrame* aFrame)
-{
-  nsIFrame* f = aFrame;
-  while (f) {
-    if (f->IsFrameModified()) {
-      return true;
-    }
-    f = nsLayoutUtils::GetCrossDocParentFrame(f);
-  }
-  return false;
-}
-
 static AnimatedGeometryRoot*
 SelectAGRForFrame(nsIFrame* aFrame, AnimatedGeometryRoot* aParentAGR)
 {
   if (!aFrame->IsStackingContext()) {
     return aParentAGR;
   }
 
   if (!aFrame->HasOverrideDirtyRegion()) {
@@ -192,16 +179,34 @@ RetainedDisplayListBuilder::IncrementSub
   MOZ_ASSERT(subDocFrame);
 
   nsIPresShell* presShell = subDocFrame->GetSubdocumentPresShellForPainting(0);
   MOZ_ASSERT(presShell);
 
   mBuilder.IncrementPresShellPaintCount(presShell);
 }
 
+static bool
+AnyContentAncestorModified(nsIFrame* aFrame,
+                           nsIFrame* aStopAtFrame = nullptr)
+{
+  for (nsIFrame* f = aFrame; f;
+       f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
+    if (f->IsFrameModified()) {
+      return true;
+    }
+
+    if (aStopAtFrame && f == aStopAtFrame) {
+      break;
+    }
+  }
+
+  return false;
+}
+
 static void
 UpdateASR(nsDisplayItem* aItem,
           Maybe<const ActiveScrolledRoot*>& aContainerASR)
 {
   if (!aContainerASR) {
     return;
   }
 
@@ -300,17 +305,17 @@ public:
     result.AppendToTop(&mMergedItems);
     result.mDAG = Move(mMergedDAG);
     result.mKeyLookup.SwapElements(mMergedKeyLookup);
     return result;
   }
 
   bool IsChanged(nsDisplayItem* aItem) {
     return aItem->HasDeletedFrame() || !aItem->CanBeReused() ||
-           IsAnyAncestorModified(aItem->FrameForInvalidation());
+           AnyContentAncestorModified(aItem->FrameForInvalidation());
   }
 
   void UpdateContainerASR(nsDisplayItem* aItem)
   {
     const ActiveScrolledRoot* itemClipASR =
       aItem->GetClipChain() ? aItem->GetClipChain()->mASR : nullptr;
 
     const ActiveScrolledRoot* finiteBoundsASR = ActiveScrolledRoot::PickDescendant(
@@ -742,17 +747,18 @@ ProcessFrame(nsIFrame* aFrame, nsDisplay
       aOverflow.IntersectRect(aOverflow, currentFrame->GetVisualOverflowRectRelativeToSelf());
     }
 
     if (aOverflow.IsEmpty()) {
       break;
     }
 
     if (currentFrame != aBuilder.RootReferenceFrame() &&
-        currentFrame->IsStackingContext()) {
+        currentFrame->IsStackingContext() &&
+        currentFrame->IsFixedPosContainingBlock()) {
       CRR_LOG("Frame belongs to stacking context frame %p\n", currentFrame);
       // If we found an intermediate stacking context with an existing display item
       // then we can store the dirty rect there and stop. If we couldn't find one then
       // we need to keep bubbling up to the next stacking context.
       nsDisplayItem* wrapperItem = GetFirstDisplayItemWithChildren(currentFrame);
       if (!wrapperItem) {
         continue;
       }
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1742,16 +1742,22 @@ public:
     if (MarkFrameModifiedDuringBuilding(const_cast<nsIFrame*>(mCurrentFrame))) {
       mInInvalidSubtree = true;
       mDirtyRect = mVisibleRect;
       return true;
     }
     return false;
   }
 
+  void RebuildAllItemsInCurrentSubtree()
+  {
+    mInInvalidSubtree = true;
+    mDirtyRect = mVisibleRect;
+  }
+
   /**
    * This is a convenience function to ease the transition until AGRs and ASRs
    * are unified.
    */
   AnimatedGeometryRoot* AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR);
 
   bool HitTestIsForVisibility() const {
     return mHitTestIsForVisibility;
--- a/layout/reftests/display-list/retained-dl-style-change-stacking-context-1.html
+++ b/layout/reftests/display-list/retained-dl-style-change-stacking-context-1.html
@@ -12,22 +12,18 @@
   }
 </style>
 </head>
 <body>
   <div id="first" style="background-color:green; width:200px; height:200px" class="reftest-no-display-list"></div>
   <div style="transform:translateZ(1px)">
     <div id="second" style="background-color:red"></div>
   </div>
-  <div style="position:fixed; left:100px">
-    <div id="third" style="background-color:red"></div>
-  </div>
 </body>
 <script>
 function doTest() {
   document.getElementById("second").style.backgroundColor = "green";
-  document.getElementById("third").style.backgroundColor = "green";
   document.documentElement.removeAttribute("class");
 }
 
 window.addEventListener("MozReftestInvalidate", doTest);
 </script>
 </html>
--- a/layout/style/GenerateCSSPropsGenerated.py
+++ b/layout/style/GenerateCSSPropsGenerated.py
@@ -13,22 +13,22 @@ def get_properties(preprocessorHeader):
     cpp = list(buildconfig.substs['CPP'])
     cpp += shellutil.split(buildconfig.substs['ACDEFINES'])
     cpp.append(preprocessorHeader)
     preprocessed = subprocess.check_output(cpp)
     properties = [{"name":p[0], "prop":p[1], "id":p[2],
                    "flags":p[3], "pref":p[4], "proptype":p[5]}
                   for (i, p) in enumerate(eval(preprocessed))]
 
-    # Sort the list so that longhand and logical properties are intermingled
-    # first, shorthand properties follow, then aliases appear last.  This matches
-    # the order of the nsCSSPropertyID enum.
+    # Sort the list so that longhand properties are intermingled first,
+    # shorthand properties follow, then aliases appear last.
+    # This matches the order of the nsCSSPropertyID enum.
 
     def property_compare(x, y):
-        property_order = {"longhand": 0, "logical": 0, "shorthand": 1, "alias": 2}
+        property_order = {"longhand": 0, "shorthand": 1, "alias": 2}
         return property_order[x["proptype"]] - property_order[y["proptype"]]
 
     properties = sorted(properties, cmp=property_compare)
 
     for i, p in enumerate(properties):
         p["index"] = i
 
     # Record each property's IDL name.
--- a/layout/style/PythonCSSProps.h
+++ b/layout/style/PythonCSSProps.h
@@ -15,24 +15,21 @@
 #define PROP_STRINGIFY(X) PROP_STRINGIFY_INTERNAL(X)
 
 #define DO_PROP(name, method, id, flags, pref, proptype) \
   [ #name, #method, #id, PROP_STRINGIFY(flags), pref, proptype ],
 #define CSS_PROP(name, id, method, flags, pref, ...) \
   DO_PROP(name, method, id, flags, pref, "longhand")
 #define CSS_PROP_SHORTHAND(name, id, method, flags, pref) \
   DO_PROP(name, method, id, flags, pref, "shorthand")
-#define CSS_PROP_LOGICAL(name, id, method, flags, pref, ...) \
-  DO_PROP(name, method, id, flags, pref, "logical")
 #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
 
 #include "nsCSSPropList.h"
 
 #undef CSS_PROP_PUBLIC_OR_PRIVATE
-#undef CSS_PROP_LOGICAL
 #undef CSS_PROP_SHORTHAND
 #undef CSS_PROP
 
 #define CSS_PROP_ALIAS(name, aliasid_, id, method, pref) \
   DO_PROP(name, method, id, 0, pref, "alias")
 
 #include "nsCSSPropAliasList.h"
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -44,17 +44,16 @@ args = [
     "-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1",
 ]
 "arch=x86" = ["--target=i686-pc-win32"]
 "arch=x86_64" = ["--target=x86_64-pc-win32"]
 
 [structs]
 headers = [
     "nsStyleStruct.h",
-    "mozilla/ServoPropPrefList.h",
     "mozilla/StyleAnimationValue.h",
     "gfxFontConstants.h",
     "gfxFontFeatures.h",
     "nsThemeConstants.h",
     "mozilla/css/Loader.h",
     "mozilla/css/SheetLoadData.h",
     "mozilla/dom/AnimationEffectReadOnlyBinding.h",
     "mozilla/dom/HTMLSlotElement.h",
@@ -200,17 +199,16 @@ whitelist-vars = [
     "NODE_.*",
     "ELEMENT_.*",
     "NS_FONT_.*",
     "NS_STYLE_.*",
     "NS_MATHML_.*",
     "NS_RADIUS_.*",
     "BORDER_COLOR_.*",
     "BORDER_STYLE_.*",
-    "mozilla::SERVO_PREF_.*",
     "CSS_PSEUDO_ELEMENT_.*",
     "SERVO_CSS_PSEUDO_ELEMENT_FLAGS_.*",
     "kNameSpaceID_.*",
     "kGenericFont_.*",
     "kPresContext_.*",
     "nsContentUtils_.*",
     "GECKO_IS_NIGHTLY",
 ]
deleted file mode 100644
--- a/layout/style/ServoPropPrefList.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_ServoPropPrefList_h
-#define mozilla_ServoPropPrefList_h
-
-namespace mozilla {
-
-#define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
-    const bool SERVO_PREF_ENABLED_##id_ = !(sizeof(pref_) == 1);
-#define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_)  \
-    const bool SERVO_PREF_ENABLED_##id_ = !(sizeof(pref_) == 1);
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
-#include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
-#undef CSS_PROP
-#undef CSS_PROP_SHORTHAND
-
-#define CSS_PROP_ALIAS(aliasname_, aliasid_, id_, method_, pref_)  \
-    const bool SERVO_PREF_ENABLED_##aliasid_ = !(sizeof(pref_) == 1);
-#define CSS_PROP_ALIAS_LIST_INCLUDE_LOGICAL
-#include "nsCSSPropAliasList.h"
-#undef CSS_PROP_ALIAS_LIST_INCLUDE_LOGICAL
-#undef CSS_PROP_ALIAS
-
-}
-
-#endif // mozilla_ServoPropPrefList_h
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1454140.html
@@ -0,0 +1,4 @@
+<!-- A -->
+<table background="
+#"><base href=Y:
+<!-- A -->
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -267,8 +267,9 @@ load 1418059.html
 test-pref(dom.animations-api.core.enabled,true) load 1418867.html
 pref(dom.webcomponents.shadowdom.enabled,true) load 1419554.html
 load 1426312.html
 load 1439793.html
 load 1409183.html
 pref(dom.webcomponents.shadowdom.enabled,true) load 1445682.html
 load 1450691.html
 pref(dom.webcomponents.shadowdom.enabled,true) load 1453206.html
+load 1454140.html
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -93,17 +93,16 @@ EXPORTS.mozilla += [
     'ServoFontFeatureValuesRule.h',
     'ServoImportRule.h',
     'ServoKeyframeRule.h',
     'ServoKeyframesRule.h',
     'ServoMediaList.h',
     'ServoMediaRule.h',
     'ServoNamespaceRule.h',
     'ServoPageRule.h',
-    'ServoPropPrefList.h',
     'ServoSpecifiedValues.h',
     'ServoStyleRule.h',
     'ServoStyleSet.h',
     'ServoStyleSetInlines.h',
     'ServoStyleSheet.h',
     'ServoSupportsRule.h',
     'ServoTraversalStatistics.h',
     'ServoTypes.h',
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -13,17 +13,17 @@
 
   This file contains the list of all parsed CSS properties.  It is
   designed to be used as inline input through the magic of C
   preprocessing.  All entries must be enclosed in the appropriate
   CSS_PROP_* macro which will have cruel and unusual things done to it.
   It is recommended (but not strictly necessary) to keep all entries in
   alphabetical order.
 
-  The arguments to CSS_PROP, CSS_PROP_LOGICAL and CSS_PROP_* are:
+  The arguments to CSS_PROP are:
 
   -. 'name' entries represent a CSS property name and *must* use only
   lowercase characters.
 
   -. 'id' should be the same as 'name' except that all hyphens ('-')
   in 'name' are converted to underscores ('_') in 'id'. For properties
   on a standards track, any '-moz-' prefix is removed in 'id'. This
   lets us do nice things with the macros without having to copy/convert
@@ -47,29 +47,21 @@
   or if the boolean property whose name is 'pref' is set to true.
 
   -. 'parsevariant', to be passed to ParseVariant in the parser.
 
   -. 'kwtable', which is either nullptr or the name of the appropriate
   keyword table member of class nsCSSProps, for use in
   nsCSSProps::LookupPropertyValue.
 
-  -. 'stylestruct_' [used only for CSS_PROP and CSS_PROP_LOGICAL, not
-  CSS_PROP_*] gives the name of the style struct.  Can be used to make
-  nsStyle##stylestruct_ and eStyleStruct_##stylestruct_
-
   -. 'animtype_' gives the animation type (see nsStyleAnimType) of this
   property.
 
   CSS_PROP_SHORTHAND only takes 1-5.
 
-  CSS_PROP_LOGICAL should be used instead of CSS_PROP_struct when
-  defining logical properties.  Logical shorthand properties should
-  still be defined with CSS_PROP_SHORTHAND.
-
  ******/
 
 
 /*************************************************************************/
 
 
 // All includers must explicitly define CSS_PROP_SHORTHAND if they
 // want it.
@@ -82,36 +74,16 @@
   CSS_PROP_PUBLIC_OR_PRIVATE(Moz ## name_, name_)
 
 // Callers may define CSS_PROP_LIST_EXCLUDE_INTERNAL if they want to
 // exclude internal properties that are not represented in the DOM (only
 // the DOM style code defines this).  All properties defined in an
 // #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL section must have the
 // CSS_PROPERTY_INTERNAL flag set.
 
-// When capturing all properties by defining CSS_PROP, callers must also
-// define one of the following three macros:
-//
-//   CSS_PROP_LIST_EXCLUDE_LOGICAL
-//     Does not include logical properties (defined with CSS_PROP_LOGICAL,
-//     such as margin-inline-start) when capturing properties to CSS_PROP.
-//
-//   CSS_PROP_LIST_INCLUDE_LOGICAL
-//     Does include logical properties when capturing properties to
-//     CSS_PROP.
-//
-//   CSS_PROP_LOGICAL
-//     Captures logical properties separately to CSS_PROP_LOGICAL.
-//
-// (CSS_PROP_LIST_EXCLUDE_LOGICAL is used for example to ensure
-// gPropertyCountInStruct and gPropertyIndexInStruct do not allocate any
-// storage to logical properties, since the result of the cascade, stored
-// in an nsRuleData, does not need to store both logical and physical
-// property values.)
-
 // Callers may also define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
 // to exclude properties that are not considered to be components of the 'all'
 // shorthand property.  Currently this excludes 'direction' and 'unicode-bidi',
 // as required by the CSS Cascading and Inheritance specification, and any
 // internal properties that cannot be changed by using CSS syntax.  For example,
 // the internal '-moz-system-font' property is not excluded, as it is set by the
 // 'font' shorthand, while '-x-lang' is excluded as there is no way to set this
 // internal property from a style sheet.
@@ -120,53 +92,24 @@
 // macro.
 #ifdef CSS_PROP
 
 #define USED_CSS_PROP
 // We still need this extra level so that CSS_PROP_DOMPROP_PREFIXED has
 // a chance to be expanded.
 #define CSS_PROP_(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_)
 
-// And similarly for logical properties.  An includer can define
-// CSS_PROP_LOGICAL to capture all logical properties, but otherwise they
-// are included in CSS_PROP (as long as CSS_PROP_LIST_INCLUDE_LOGICAL is
-// defined).
-#if defined(CSS_PROP_LOGICAL) && defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) || defined(CSS_PROP_LOGICAL) && defined(CSS_PROP_LIST_INCLUDE_LOGICAL) || defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) && defined(CSS_PROP_LIST_INCLUDE_LOGICAL)
-#error Do not define more than one of CSS_PROP_LOGICAL, CSS_PROP_LIST_EXCLUDE_LOGICAL and CSS_PROP_LIST_INCLUDE_LOGICAL when capturing properties using CSS_PROP.
-#endif
-
-#ifndef CSS_PROP_LOGICAL
-#ifdef CSS_PROP_LIST_INCLUDE_LOGICAL
-#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_)
-#else
-#ifndef CSS_PROP_LIST_EXCLUDE_LOGICAL
-#error Must define exactly one of CSS_PROP_LOGICAL, CSS_PROP_LIST_EXCLUDE_LOGICAL and CSS_PROP_LIST_INCLUDE_LOGICAL when capturing properties using CSS_PROP.
-#endif
-#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) /* nothing */
-#endif
-#define DEFINED_CSS_PROP_LOGICAL
-#endif
-
 #else /* !defined(CSS_PROP) */
 
 // An includer who does not define CSS_PROP can define any or all of the
 // per-struct macros that are equivalent to it, and the rest will be
 // ignored.
 
-#if defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) || defined(CSS_PROP_LIST_INCLUDE_LOGICAL)
-#error Do not define CSS_PROP_LIST_EXCLUDE_LOGICAL or CSS_PROP_LIST_INCLUDE_LOGICAL when not capturing properties using CSS_PROP.
-#endif
-
 #define CSS_PROP_(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) /* nothing */
 
-#ifndef CSS_PROP_LOGICAL
-#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) /* nothing */
-#define DEFINED_CSS_PROP_LOGICAL
-#endif
-
 #endif /* !defined(CSS_PROP) */
 
 /*************************************************************************/
 
 // For notes XXX bug 3935 below, the names being parsed do not correspond
 // to the constants used internally.  It would be nice to bring the
 // constants into line sometime.
 
@@ -438,17 +381,17 @@ CSS_PROP_(
     -moz-binding,
     _moz_binding,
     CSS_PROP_DOMPROP_PREFIXED(Binding),
     0,
     "",
     VARIANT_HUO,
     nullptr,
     eStyleAnimType_None) // XXX bug 3935
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     block-size,
     block_size,
     BlockSize,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -459,68 +402,68 @@ CSS_PROP_SHORTHAND(
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_SHORTHAND(
     border-block-end,
     border_block_end,
     BorderBlockEnd,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-block-end-color,
     border_block_end_color,
     BorderBlockEndColor,
     0,
     "",
     VARIANT_HC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-block-end-style,
     border_block_end_style,
     BorderBlockEndStyle,
     0,
     "",
     VARIANT_HK,
     kBorderStyleKTable,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-block-end-width,
     border_block_end_width,
     BorderBlockEndWidth,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable,
     eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     border-block-start,
     border_block_start,
     BorderBlockStart,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-block-start-color,
     border_block_start_color,
     BorderBlockStartColor,
     0,
     "",
     VARIANT_HC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-block-start-style,
     border_block_start_style,
     BorderBlockStartStyle,
     0,
     "",
     VARIANT_HK,
     kBorderStyleKTable,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-block-start-width,
     border_block_start_width,
     BorderBlockStartWidth,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable,
     eStyleAnimType_None)
@@ -642,68 +585,68 @@ CSS_PROP_(
     nullptr,
     eStyleAnimType_Discrete)
 CSS_PROP_SHORTHAND(
     border-inline-end,
     border_inline_end,
     BorderInlineEnd,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-inline-end-color,
     border_inline_end_color,
     BorderInlineEndColor,
     0,
     "",
     VARIANT_HC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-inline-end-style,
     border_inline_end_style,
     BorderInlineEndStyle,
     0,
     "",
     VARIANT_HK,
     kBorderStyleKTable,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-inline-end-width,
     border_inline_end_width,
     BorderInlineEndWidth,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable,
     eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     border-inline-start,
     border_inline_start,
     BorderInlineStart,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-inline-start-color,
     border_inline_start_color,
     BorderInlineStartColor,
     0,
     "",
     VARIANT_HC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-inline-start-style,
     border_inline_start_style,
     BorderInlineStartStyle,
     0,
     "",
     VARIANT_HK,
     kBorderStyleKTable,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     border-inline-start-width,
     border_inline_start_width,
     BorderInlineStartWidth,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKL | VARIANT_CALC,
     kBorderWidthKTable,
     eStyleAnimType_None)
@@ -1324,17 +1267,17 @@ CSS_PROP_(
     FlexWrap,
     0,
     "",
     VARIANT_HK,
     kFlexWrapKTable,
     eStyleAnimType_Discrete)
 CSS_PROP_(
     float,
-    float_,
+    float,
     CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float),
     0,
     "",
     VARIANT_HK,
     kFloatKTable,
     eStyleAnimType_Discrete)
 CSS_PROP_(
     -moz-float-edge,
@@ -1766,17 +1709,17 @@ CSS_PROP_(
     ime-mode,
     ime_mode,
     ImeMode,
     0,
     "",
     VARIANT_HK,
     kIMEModeKTable,
     eStyleAnimType_Discrete)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     inline-size,
     inline_size,
     InlineSize,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable,
     eStyleAnimType_None)
@@ -1901,26 +1844,26 @@ CSS_PROP_(
     nullptr,
     eStyleAnimType_Discrete)
 CSS_PROP_SHORTHAND(
     margin,
     margin,
     Margin,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     margin-block-end,
     margin_block_end,
     MarginBlockEnd,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     margin-block-start,
     margin_block_start,
     MarginBlockStart,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -1928,26 +1871,26 @@ CSS_PROP_(
     margin-bottom,
     margin_bottom,
     MarginBottom,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_Sides_Bottom)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     margin-inline-end,
     margin_inline_end,
     MarginInlineEnd,
     0,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     margin-inline-start,
     margin_inline_start,
     MarginInlineStart,
     0,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -2136,17 +2079,17 @@ CSS_PROP_(
     CSS_PROPERTY_INTERNAL |
         CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     VARIANT_HK,
     kMathVariantKTable,
     eStyleAnimType_None)
 #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 #endif // CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     max-block-size,
     max_block_size,
     MaxBlockSize,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLPO | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -2154,17 +2097,17 @@ CSS_PROP_(
     max-height,
     max_height,
     MaxHeight,
     0,
     "",
     VARIANT_HKLPO | VARIANT_CALC,
     kWidthKTable,
     eStyleAnimType_Coord)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     max-inline-size,
     max_inline_size,
     MaxInlineSize,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HKLPO | VARIANT_CALC,
     kWidthKTable,
     eStyleAnimType_None)
@@ -2172,17 +2115,17 @@ CSS_PROP_(
     max-width,
     max_width,
     MaxWidth,
     0,
     "",
     VARIANT_HKLPO | VARIANT_CALC,
     kWidthKTable,
     eStyleAnimType_Coord)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     min-block-size,
     min_block_size,
     MinBlockSize,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -2202,17 +2145,17 @@ CSS_PROP_(
     min-height,
     min_height,
     MinHeight,
     0,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable,
     eStyleAnimType_Coord)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     min-inline-size,
     min_inline_size,
     MinInlineSize,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHKLP | VARIANT_CALC,
     kWidthKTable,
     eStyleAnimType_None)
@@ -2247,44 +2190,44 @@ CSS_PROP_(
     object-position,
     object_position,
     ObjectPosition,
     CSS_PROPERTY_PARSE_FUNCTION,
     "",
     VARIANT_CALC,
     kImageLayerPositionKTable,
     eStyleAnimType_Custom)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     offset-block-end,
     offset_block_end,
     OffsetBlockEnd,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     offset-block-start,
     offset_block_start,
     OffsetBlockStart,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     offset-inline-end,
     offset_inline_end,
     OffsetInlineEnd,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     offset-inline-start,
     offset_inline_start,
     OffsetInlineStart,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -2458,26 +2401,26 @@ CSS_PROP_(
     kOverflowSubKTable,
     eStyleAnimType_Discrete)
 CSS_PROP_SHORTHAND(
     padding,
     padding,
     Padding,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     padding-block-end,
     padding_block_end,
     PaddingBlockEnd,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     padding-block-start,
     padding_block_start,
     PaddingBlockStart,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -2485,26 +2428,26 @@ CSS_PROP_(
     padding-bottom,
     padding_bottom,
     PaddingBottom,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_Sides_Bottom)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     padding-inline-end,
     padding_inline_end,
     PaddingInlineEnd,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
-CSS_PROP_LOGICAL(
+CSS_PROP_(
     padding-inline-start,
     padding_inline_start,
     PaddingInlineStart,
     CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_HLP | VARIANT_CALC,
     nullptr,
     eStyleAnimType_None)
@@ -3537,14 +3480,10 @@ CSS_PROP_(
     eStyleAnimType_Coord)
 
 #undef CSS_PROP_
 
 #ifdef DEFINED_CSS_PROP_SHORTHAND
 #undef CSS_PROP_SHORTHAND
 #undef DEFINED_CSS_PROP_SHORTHAND
 #endif
-#ifdef DEFINED_CSS_PROP_LOGICAL
-#undef CSS_PROP_LOGICAL
-#undef DEFINED_CSS_PROP_LOGICAL
-#endif
 
 #undef CSS_PROP_DOMPROP_PREFIXED
--- a/layout/style/nsCSSPropertyID.h
+++ b/layout/style/nsCSSPropertyID.h
@@ -17,19 +17,17 @@
 
    To change the list of properties, see nsCSSPropList.h
 
  */
 enum nsCSSPropertyID {
   eCSSProperty_UNKNOWN = -1,
 
   #define CSS_PROP(name_, id_, ...) eCSSProperty_##id_,
-  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #include "nsCSSPropList.h"
-  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP
 
   eCSSProperty_COUNT_no_shorthands,
   // Make the count continue where it left off:
   eCSSProperty_COUNT_DUMMY = eCSSProperty_COUNT_no_shorthands - 1,
 
   #define CSS_PROP_SHORTHAND(name_, id_, ...) eCSSProperty_##id_,
   #include "nsCSSPropList.h"
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -36,42 +36,36 @@ typedef nsCSSProps::KTableEntry KTableEn
 // By wrapping internal-only properties in this macro, we are not
 // exposing them in the CSSOM. Since currently it is not necessary to
 // allow accessing them in that way, it is easier and cheaper to just
 // do this rather than exposing them conditionally.
 #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
   static_assert(!((flags_) & CSS_PROPERTY_ENABLED_MASK) || pref_[0], \
                 "Internal-only property '" #name_ "' should be wrapped in " \
                 "#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL");
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #define CSS_PROP_LIST_EXCLUDE_INTERNAL
 #include "nsCSSPropList.h"
 #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 
 #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
   static_assert(!((flags_) & CSS_PROPERTY_ENABLED_IN_CHROME) || \
                 ((flags_) & CSS_PROPERTY_ENABLED_IN_UA_SHEETS), \
                 "Property '" #name_ "' is enabled in chrome, so it should " \
                 "also be enabled in UA sheets");
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 
 // required to make the symbol external, so that TestCSSPropertyLookup.cpp can link with it
 extern const char* const kCSSRawProperties[];
 
 // define an array of all CSS properties
 const char* const kCSSRawProperties[eCSSProperty_COUNT_with_aliases] = {
 #define CSS_PROP(name_, ...) #name_,
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) #name_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP_SHORTHAND
 #define CSS_PROP_ALIAS(aliasname_, aliasid_, id_, method_, pref_) #aliasname_,
 #include "nsCSSPropAliasList.h"
 #undef CSS_PROP_ALIAS
 };
@@ -184,19 +178,17 @@ nsCSSProps::AddRefTable(void)
       #define OBSERVE_PROP(pref_, id_)                                        \
         if (pref_[0]) {                                                       \
           Preferences::AddBoolVarCache(&gPropertyEnabled[id_],                \
                                        pref_);                                \
         }
 
       #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
         OBSERVE_PROP(pref_, eCSSProperty_##id_)
-      #define CSS_PROP_LIST_INCLUDE_LOGICAL
       #include "nsCSSPropList.h"
-      #undef CSS_PROP_LIST_INCLUDE_LOGICAL
       #undef CSS_PROP
 
       #define  CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \
         OBSERVE_PROP(pref_, eCSSProperty_##id_)
       #include "nsCSSPropList.h"
       #undef CSS_PROP_SHORTHAND
 
       #define CSS_PROP_ALIAS(aliasname_, aliasid_, propid_, aliasmethod_, pref_)    \
@@ -237,21 +229,19 @@ nsCSSProps::AddRefTable(void)
       }
 
       // Assert that CSS_PROPERTY_INTERNAL is used on properties in
       // #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL sections of nsCSSPropList.h
       // and on no others.
       static nsCSSPropertyID nonInternalProperties[] = {
         #define CSS_PROP(name_, id_, ...)           eCSSProperty_##id_,
         #define CSS_PROP_SHORTHAND(name_, id_, ...) eCSSProperty_##id_,
-        #define CSS_PROP_LIST_INCLUDE_LOGICAL
         #define CSS_PROP_LIST_EXCLUDE_INTERNAL
         #include "nsCSSPropList.h"
         #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
-        #undef CSS_PROP_LIST_INCLUDE_LOGICAL
         #undef CSS_PROP_SHORTHAND
         #undef CSS_PROP
       };
       MOZ_ASSERT(ArrayLength(nonInternalProperties) <= eCSSProperty_COUNT);
 
       bool found[eCSSProperty_COUNT];
       PodArrayZero(found);
       for (nsCSSPropertyID p : nonInternalProperties) {
@@ -2223,19 +2213,17 @@ nsCSSProps::ValueToKeyword(int32_t aValu
     return nsCSSKeywords::GetStringValue(keyword);
   }
 }
 
 /* static */ const KTableEntry* const
 nsCSSProps::kKeywordTableTable[eCSSProperty_COUNT_no_shorthands] = {
   #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \
                    kwtable_, ...) kwtable_,
-  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #include "nsCSSPropList.h"
-  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP
 };
 
 const nsCString&
 nsCSSProps::LookupPropertyValue(nsCSSPropertyID aProp, int32_t aValue)
 {
   MOZ_ASSERT(aProp >= 0 && aProp < eCSSProperty_COUNT,
              "property out of range");
@@ -2272,40 +2260,34 @@ bool nsCSSProps::GetColorName(int32_t aP
   return rv;
 }
 
 const nsStyleAnimType
 nsCSSProps::kAnimTypeTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, \
                  parsevariant_, kwtable_, animtype_) \
   animtype_,
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 };
 
 const uint32_t nsCSSProps::kFlagsTable[eCSSProperty_COUNT] = {
 #define CSS_PROP(name_, id_, method_, flags_, ...) flags_,
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) flags_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP_SHORTHAND
 };
 
 static const nsCSSPropertyID gAllSubpropTable[] = {
 #define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #define CSS_PROP(name_, id_, ...) eCSSProperty_##id_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSPropertyID gAnimationSubpropTable[] = {
   eCSSProperty_animation_duration,
   eCSSProperty_animation_timing_function,
   eCSSProperty_animation_delay,
@@ -2749,19 +2731,17 @@ nsCSSProps::gPropertyEnabled[eCSSPropert
   // value is, it will later be changed in nsCSSProps::AddRefTable().
   // If the property has "ENABLED_IN" flags but doesn't have a pref,
   // it is an internal property which is disabled elsewhere.
   #define IS_ENABLED_BY_DEFAULT(flags_) \
     (!((flags_) & CSS_PROPERTY_ENABLED_MASK))
 
   #define CSS_PROP(name_, id_, method_, flags_, ...) \
     IS_ENABLED_BY_DEFAULT(flags_),
-  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #include "nsCSSPropList.h"
-  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP
 
   #define  CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \
     IS_ENABLED_BY_DEFAULT(flags_),
   #include "nsCSSPropList.h"
   #undef CSS_PROP_SHORTHAND
 
   #define CSS_PROP_ALIAS(aliasname_, aliasid_, propid_, aliasmethod_, pref_) \
@@ -2772,28 +2752,24 @@ nsCSSProps::gPropertyEnabled[eCSSPropert
   #undef IS_ENABLED_BY_DEFAULT
 };
 
 #include "../../dom/base/PropertyUseCounterMap.inc"
 
 /* static */ const UseCounter
 nsCSSProps::gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands] = {
   #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
-  #define CSS_PROP_LIST_INCLUDE_LOGICAL
   #define CSS_PROP(name_, id_, method_, ...) \
     static_cast<UseCounter>(USE_COUNTER_FOR_CSS_PROPERTY_##method_),
   #include "nsCSSPropList.h"
   #undef CSS_PROP
-  #undef CSS_PROP_LIST_INCLUDE_LOGICAL
   #undef CSS_PROP_PUBLIC_OR_PRIVATE
 };
 
 const uint32_t
 nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, ...) \
   parsevariant_,
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 };
 
 #include "nsCSSPropsGenerated.inc"
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -7178,31 +7178,27 @@ nsComputedDOMStyle::RegisterPrefChangeCa
   // entries iterated in nsComputedDOMStylePropertyList.h.
   ComputedStyleMap* data = GetComputedStyleMap();
 #define REGISTER_CALLBACK(pref_)                                             \
   if (pref_[0]) {                                                            \
     Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data);   \
   }
 #define CSS_PROP(prop_, id_, method_, flags_, pref_, ...) \
   REGISTER_CALLBACK(pref_)
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #undef REGISTER_CALLBACK
 }
 
 /* static */ void
 nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
 {
   ComputedStyleMap* data = GetComputedStyleMap();
 #define UNREGISTER_CALLBACK(pref_)                                             \
   if (pref_[0]) {                                                              \
     Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data);   \
   }
 #define CSS_PROP(prop_, id_, method_, flags_, pref_, ...) \
   UNREGISTER_CALLBACK(pref_)
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #include "nsCSSPropList.h"
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #undef UNREGISTER_CALLBACK
 }
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -124,17 +124,17 @@ COMPUTED_STYLE_PROP(cursor,             
 COMPUTED_STYLE_PROP(direction,                     Direction)
 COMPUTED_STYLE_PROP(display,                       Display)
 COMPUTED_STYLE_PROP(empty_cells,                   EmptyCells)
 COMPUTED_STYLE_PROP(flex_basis,                    FlexBasis)
 COMPUTED_STYLE_PROP(flex_direction,                FlexDirection)
 COMPUTED_STYLE_PROP(flex_grow,                     FlexGrow)
 COMPUTED_STYLE_PROP(flex_shrink,                   FlexShrink)
 COMPUTED_STYLE_PROP(flex_wrap,                     FlexWrap)
-COMPUTED_STYLE_PROP(float_,                        Float)
+COMPUTED_STYLE_PROP(float,                         Float)
 //// COMPUTED_STYLE_PROP(font,                     Font)
 COMPUTED_STYLE_PROP(font_family,                   FontFamily)
 COMPUTED_STYLE_PROP(font_feature_settings,         FontFeatureSettings)
 COMPUTED_STYLE_PROP(font_kerning,                  FontKerning)
 COMPUTED_STYLE_PROP(font_language_override,        FontLanguageOverride)
 COMPUTED_STYLE_PROP(font_optical_sizing,           FontOpticalSizing)
 COMPUTED_STYLE_PROP(font_size,                     FontSize)
 COMPUTED_STYLE_PROP(font_size_adjust,              FontSizeAdjust)
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -93,27 +93,25 @@ public:
   void                                                                       \
   Set##method_(const nsAString& aValue, nsIPrincipal* aSubjectPrincipal,     \
                mozilla::ErrorResult& rv)                                     \
   {                                                                          \
     rv = SetPropertyValue(eCSSProperty_##id_, aValue, aSubjectPrincipal);    \
   }
 
 #define CSS_PROP_LIST_EXCLUDE_INTERNAL
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 #define CSS_PROP_SHORTHAND(name_, id_, method_, ...)  CSS_PROP(name_, id_, method_, )
 #include "nsCSSPropList.h"
 
 #define CSS_PROP_ALIAS(aliasname_, aliasid_, propid_, aliasmethod_, ...)  \
   CSS_PROP(X, propid_, aliasmethod_, )
 #include "nsCSSPropAliasList.h"
 #undef CSS_PROP_ALIAS
 
 #undef CSS_PROP_SHORTHAND
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
 #undef CSS_PROP
 #undef CSS_PROP_PUBLIC_OR_PRIVATE
 
   virtual void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName) override;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2170,18 +2170,22 @@ nsStyleImageRequest::Resolve(
 
   mResolved = true;
 
   nsIDocument* doc = aPresContext->Document();
   nsIURI* docURI = doc->GetDocumentURI();
   if (GetImageValue()->HasRef()) {
     bool isEqualExceptRef = false;
     RefPtr<nsIURI> imageURI = GetImageURI();
-    imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
-    if (isEqualExceptRef) {
+    if (!imageURI) {
+      return false;
+    }
+
+    if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) &&
+        isEqualExceptRef) {
       // Prevent loading an internal resource.
       return true;
     }
   }
 
   // TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the
   // lack of non-http image caching in imagelib (bug 1406134), which causes
   // stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
--- a/layout/style/test/ListCSSProperties.cpp
+++ b/layout/style/test/ListCSSProperties.cpp
@@ -16,40 +16,36 @@ struct PropertyInfo {
     const char *pref;
 };
 
 const PropertyInfo gLonghandProperties[] = {
 
 #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
 #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \
     { #name_, #method_, pref_ },
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 
 #include "nsCSSPropList.h"
 
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #undef CSS_PROP_PUBLIC_OR_PRIVATE
 
 };
 
 /*
  * These are the properties for which domName in the above list should
  * be used.  They're in the same order as the above list, with some
  * items skipped.
  */
 const char* gLonghandPropertiesWithDOMProp[] = {
 
 #define CSS_PROP_LIST_EXCLUDE_INTERNAL
 #define CSS_PROP(name_, ...) #name_,
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 
 #include "nsCSSPropList.h"
 
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
 #undef CSS_PROP
 #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
 
 };
 
 const PropertyInfo gShorthandProperties[] = {
 
 #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -202,8 +202,9 @@ load 1322537-2.html
 load 1322852.html
 load 1348564.svg
 load 1402109.html
 load 1402124.html
 load 1402486.html
 load conditional-outer-svg-nondirty-reflow-assert.xhtml
 load extref-test-1.xhtml
 load blob-merging-and-retained-display-list.html
+load grouping-empty-bounds.html
new file mode 100644
--- /dev/null
+++ b/layout/svg/crashtests/grouping-empty-bounds.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en" class='reftest-wait'>
+<meta charset="utf-8">
+<title>This testcase might create a non-empty display list with an empty set of drawing commands / items in the EventRecorder</title>
+
+<style>
+
+body {
+  margin: 0;
+}
+
+.animated-opacity {
+  animation: opacity-animation 1s linear alternate infinite;
+}
+
+@keyframes opacity-animation {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+
+</style>
+
+<svg style="width: 100px; height: 100px;">
+  <rect class="animated-opacity" x="0" y="0" width="100" height="100"/>
+  <rect x="0" y="0" width="10" height="10" id="toremove"/>
+  <g transform="translate(10 10)"><rect x="120" y="0" width="1" height="1"/></g>
+</svg>
+
+<script>
+
+window.addEventListener("MozReftestInvalidate", () => {
+  var elem = document.getElementById("toremove");
+  elem.parentNode.removeChild(elem);
+  document.documentElement.removeAttribute('class');
+});
+
+</script>
--- a/mobile/android/app/src/photon/res/values/styles.xml
+++ b/mobile/android/app/src/photon/res/values/styles.xml
@@ -473,17 +473,17 @@
         <item name="android:textAppearance">@style/TextAppearance.UrlBar.Title</item>
         <item name="android:textColor">@color/url_bar_title</item>
         <item name="android:textColorHint">@color/url_bar_title_hint</item>
         <item name="android:textColorHighlight">@color/url_bar_title_highlight</item>
         <item name="android:textSelectHandle">@drawable/handle_middle</item>
         <item name="android:textSelectHandleLeft">@drawable/handle_start</item>
         <item name="android:textSelectHandleRight">@drawable/handle_end</item>
         <item name="android:textCursorDrawable">@null</item>
-        <item name="android:singleLine">true</item>
+        <item name="android:maxLines">1</item>
         <item name="android:gravity">center_vertical|left|start</item>
         <item name="android:hint">@string/url_bar_default_text</item>
     </style>
 
     <!-- URL bar - Image Button -->
     <style name="UrlBar.ImageButtonBase" parent="UrlBar.Button">
         <item name="android:scaleType">center</item>
         <item name="android:layout_gravity">center_vertical</item>
--- a/mobile/android/chrome/content/config.js
+++ b/mobile/android/chrome/content/config.js
@@ -567,25 +567,16 @@ Pref.prototype = {
   reset: function AC_reset() {
     Services.prefs.clearUserPref(this.name);
   },
 
   test: function AC_test(aValue) {
     return aValue ? aValue.test(this.name) : true;
   },
 
-  escapeHTML: function(input) {
-    return input.replace(/&/g, "&amp;")
-                .replace(/</g, "&lt;")
-                .replace(/>/g, "&gt;")
-                .replace(/"/g, "&quot;")
-                .replace(/'/g, "&#x27;")
-                .replace(/\//g, "&#x2F;");
-  },
-
   // Get existing or create new LI node for the pref
   getOrCreateNewLINode: function AC_getOrCreateNewLINode() {
     if (!this.li) {
       this.li = document.createElement("li");
 
       this.li.className = "pref-item";
       this.li.setAttribute("name", this.name);
 
@@ -600,42 +591,70 @@ Pref.prototype = {
       this.li.addEventListener("contextmenu",
         function(aEvent) {
           AboutConfig.contextMenuLINode = AboutConfig.getLINodeForEvent(aEvent);
         }
       );
 
       this.li.setAttribute("contextmenu", "prefs-context-menu");
 
-      // Create list item outline, bind to object actions
-      this.li.unsafeSetInnerHTML(
-        "<div class='pref-name' " +
-            "onclick='AboutConfig.selectOrToggleBoolPref(event);'>" +
-            this.escapeHTML(this.name) +
-        "</div>" +
-        "<div class='pref-item-line'>" +
-          "<input class='pref-value' value='' " +
-            "onblur='AboutConfig.setIntOrStringPref(event);' " +
-            "onclick='AboutConfig.selectOrToggleBoolPref(event);'>" +
-          "</input>" +
-          "<div class='pref-button reset' " +
-            "onclick='AboutConfig.resetDefaultPref(event);'>" +
-            gStringBundle.GetStringFromName("pref.resetButton") +
-          "</div>" +
-          "<div class='pref-button toggle' " +
-            "onclick='AboutConfig.toggleBoolPref(event);'>" +
-            gStringBundle.GetStringFromName("pref.toggleButton") +
-          "</div>" +
-          "<div class='pref-button up' " +
-            "onclick='AboutConfig.incrOrDecrIntPref(event, 1);'>" +
-          "</div>" +
-          "<div class='pref-button down' " +
-            "onclick='AboutConfig.incrOrDecrIntPref(event, -1);'>" +
-          "</div>" +
-        "</div>");
+      let prefName = document.createElement("div");
+      prefName.className = "pref-name";
+      prefName.addEventListener("click", function(event) {
+        AboutConfig.selectOrToggleBoolPref(event);
+      });
+      prefName.textContent = this.name;
+
+      this.li.appendChild(prefName);
+
+      let prefItemLine = document.createElement("div");
+      prefItemLine.className = "pref-item-line";
+
+      let prefValue = document.createElement("input");
+      prefValue.className = "pref-value";
+      prefValue.addEventListener("blur", function(event) {
+        AboutConfig.setIntOrStringPref(event);
+      });
+      prefValue.addEventListener("click", function(event) {
+        AboutConfig.selectOrToggleBoolPref(event);
+      });
+      prefValue.value = "";
+      prefItemLine.appendChild(prefValue);
+
+      let resetButton = document.createElement("div");
+      resetButton.className = "pref-button reset";
+      resetButton.addEventListener("click", function(event) {
+        AboutConfig.resetDefaultPref(event);
+      });
+      resetButton.textContent = gStringBundle.GetStringFromName("pref.resetButton");
+      prefItemLine.appendChild(resetButton);
+
+      let toggleButton = document.createElement("div");
+      toggleButton.className = "pref-button toggle";
+      toggleButton.addEventListener("click", function(event) {
+        AboutConfig.toggleBoolPref(event);
+      });
+      toggleButton.textContent = gStringBundle.GetStringFromName("pref.toggleButton");
+      prefItemLine.appendChild(toggleButton);
+
+      let upButton = document.createElement("div");
+      upButton.className = "pref-button up";
+      upButton.addEventListener("click", function(event) {
+        AboutConfig.incrOrDecrIntPref(event, 1);
+      });
+      prefItemLine.appendChild(upButton);
+
+      let downButton = document.createElement("div");
+      downButton.className = "pref-button down";
+      downButton.addEventListener("click", function(event) {
+        AboutConfig.incrOrDecrIntPref(event, -1);
+      });
+      prefItemLine.appendChild(downButton);
+
+      this.li.appendChild(prefItemLine);
 
       // Delay providing the list item values, until the LI is returned and added to the document
       setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY);
     }
 
     return this.li;
   },
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2150,16 +2150,17 @@ pref("network.proxy.failover_timeout",  
 pref("network.online",                      true); //online/offline
 pref("network.cookie.cookieBehavior",       0); // 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign
 #ifdef ANDROID
 pref("network.cookie.cookieBehavior",       0); // Keep the old default of accepting all cookies
 #endif
 pref("network.cookie.thirdparty.sessionOnly", false);
 pref("network.cookie.thirdparty.nonsecureSessionOnly", false);
 pref("network.cookie.leave-secure-alone",   true);
+pref("network.cookie.same-site.enabled",    true); // Honor the SameSite cookie attribute
 pref("network.cookie.ipc.sync",             false);
 pref("network.cookie.lifetimePolicy",       0); // 0-accept, 1-dontUse 2-acceptForSession, 3-acceptForNDays
 pref("network.cookie.prefsMigrated",        false);
 pref("network.cookie.lifetime.days",        90); // Ignored unless network.cookie.lifetimePolicy is 3.
 
 // The PAC file to load.  Ignored unless network.proxy.type is 2.
 pref("network.proxy.autoconfig_url", "");
 // Strip off paths when sending URLs to PAC scripts
@@ -2524,26 +2525,31 @@ pref("extensions.blocklist.detailsURL", 
 pref("extensions.blocklist.itemURL", "https://blocked.cdn.mozilla.net/%blockID%.html");
 // Controls what level the blocklist switches from warning about items to forcibly
 // blocking them.
 pref("extensions.blocklist.level", 2);
 // Blocklist via settings server (Kinto)
 pref("services.blocklist.bucket", "blocklists");
 pref("services.blocklist.onecrl.collection", "certificates");
 pref("services.blocklist.onecrl.checked", 0);
+pref("services.blocklist.onecrl.signer", "onecrl.content-signature.mozilla.org");
 pref("services.blocklist.addons.collection", "addons");
 pref("services.blocklist.addons.checked", 0);
+pref("services.blocklist.addons.signer", "onecrl.content-signature.mozilla.org");
 pref("services.blocklist.plugins.collection", "plugins");
 pref("services.blocklist.plugins.checked", 0);
+pref("services.blocklist.plugins.signer", "onecrl.content-signature.mozilla.org");
 pref("services.blocklist.pinning.enabled", true);
 pref("services.blocklist.pinning.bucket", "pinning");
 pref("services.blocklist.pinning.collection", "pins");
 pref("services.blocklist.pinning.checked", 0);
+pref("services.blocklist.pinning.signer", "pinning-preload.content-signature.mozilla.org");
 pref("services.blocklist.gfx.collection", "gfx");
 pref("services.blocklist.gfx.checked", 0);
+pref("services.blocklist.gfx.signer", "onecrl.content-signature.mozilla.org");
 // Enable blocklists via the services settings mechanism
 pref("services.blocklist.update_enabled", true);
 
 // Modifier key prefs: default to Windows settings,
 // menu access key = alt, accelerator key = control.
 // Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js
 pref("ui.key.accelKey", 17);
 pref("ui.key.menuAccessKey", 18);
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -309,17 +309,17 @@ CookieServiceChild::GetCookieStringFromC
       continue;
 
     // if the cookie is secure and the host scheme isn't, we can't send it
     if (cookie->IsSecure() && !isSecure)
       continue;
 
     int32_t sameSiteAttr = 0;
     cookie->GetSameSite(&sameSiteAttr);
-    if (aIsSameSiteForeign) {
+    if (aIsSameSiteForeign && nsCookieService::IsSameSiteEnabled()) {
       // it if's a cross origin request and the cookie is same site only (strict)
       // don't send it
       if (sameSiteAttr == nsICookie2::SAMESITE_STRICT) {
         continue;
       }
       // if it's a cross origin request, the cookie is same site lax, but it's not
       // a top-level navigation, don't send it
       if (sameSiteAttr == nsICookie2::SAMESITE_LAX && !aIsSafeTopLevelNav) {
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -71,16 +71,17 @@ using namespace mozilla::net;
         nsCookieKey(baseDomain, OriginAttributes())
 
 /******************************************************************************
  * nsCookieService impl:
  * useful types & constants
  ******************************************************************************/
 
 static StaticRefPtr<nsCookieService> gCookieService;
+bool nsCookieService::sSameSiteEnabled = false;
 
 // XXX_hack. See bug 178993.
 // This is a hack to hide HttpOnly cookies from older browsers
 #define HTTP_ONLY_PREFIX "#HttpOnly_"
 
 #define COOKIES_FILE "cookies.sqlite"
 #define COOKIES_SCHEMA_VERSION 9
 
@@ -3070,16 +3071,28 @@ nsCookieService::DomainMatches(nsCookie*
   // first, check for an exact host or domain cookie match, e.g. "google.com"
   // or ".google.com"; second a subdomain match, e.g.
   // host = "mail.google.com", cookie domain = ".google.com".
   return aCookie->RawHost() == aHost ||
       (aCookie->IsDomain() && StringEndsWith(aHost, aCookie->Host()));
 }
 
 bool
+nsCookieService::IsSameSiteEnabled()
+{
+  static bool prefInitialized = false;
+  if (!prefInitialized) {
+    Preferences::AddBoolVarCache(&sSameSiteEnabled,
+                                 "network.cookie.same-site.enabled", false);
+    prefInitialized = true;
+  }
+  return sSameSiteEnabled;
+}
+
+bool
 nsCookieService::PathMatches(nsCookie* aCookie,
                              const nsACString& aPath)
 {
   // calculate cookie path length, excluding trailing '/'
   uint32_t cookiePathLen = aCookie->Path().Length();
   if (cookiePathLen > 0 && aCookie->Path().Last() == '/')
     --cookiePathLen;
 
@@ -3199,17 +3212,17 @@ nsCookieService::GetCookiesForURI(nsIURI
       continue;
 
     // if the cookie is secure and the host scheme isn't, we can't send it
     if (cookie->IsSecure() && !isSecure)
       continue;
 
     int32_t sameSiteAttr = 0;
     cookie->GetSameSite(&sameSiteAttr);
-    if (aIsSameSiteForeign) {
+    if (aIsSameSiteForeign && IsSameSiteEnabled()) {
       // it if's a cross origin request and the cookie is same site only (strict)
       // don't send it
       if (sameSiteAttr == nsICookie2::SAMESITE_STRICT) {
         continue;
       }
       // if it's a cross origin request, the cookie is same site lax, but it's not
       // a top-level navigation, don't send it
       if (sameSiteAttr == nsICookie2::SAMESITE_LAX && !aIsSafeTopLevelNav) {
@@ -3466,18 +3479,19 @@ nsCookieService::CanSetCookie(nsIURI*   
       "non-https cookie can't set secure flag");
     Telemetry::Accumulate(Telemetry::COOKIE_LEAVE_SECURE_ALONE,
                           BLOCKED_SECURE_SET_FROM_HTTP);
     return newCookie;
   }
 
   // If the new cookie is same-site but in a cross site context,
   // browser must ignore the cookie.
-  if (aCookieAttributes.sameSite != nsICookie2::SAMESITE_UNSET &&
-      aThirdPartyUtil) {
+  if ((aCookieAttributes.sameSite != nsICookie2::SAMESITE_UNSET) &&
+      aThirdPartyUtil &&
+      IsSameSiteEnabled()) {
     bool isThirdParty = false;
     aThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isThirdParty);
     if (isThirdParty) {
       COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
                         "failed the samesite tests");
       return newCookie;
     }
   }
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -237,16 +237,18 @@ class nsCookieService final : public nsI
                             , public nsICookieManager
                             , public nsIObserver
                             , public nsSupportsWeakReference
                             , public nsIMemoryReporter
 {
   private:
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
+    static bool sSameSiteEnabled; // cached pref
+
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSICOOKIESERVICE
     NS_DECL_NSICOOKIEMANAGER
     NS_DECL_NSIMEMORYREPORTER
 
     nsCookieService();
@@ -259,16 +261,17 @@ class nsCookieService final : public nsI
    * (thus instantiating it, if necessary) and clear all the cookies for that
    * app.
    */
   static void AppClearDataObserverInit();
   static nsCString GetPathFromURI(nsIURI *aHostURI);
   static nsresult GetBaseDomain(nsIEffectiveTLDService *aTLDService, nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch);
   static nsresult GetBaseDomainFromHost(nsIEffectiveTLDService *aTLDService, const nsACString &aHost, nsCString &aBaseDomain);
   static bool DomainMatches(nsCookie* aCookie, const nsACString& aHost);
+  static bool IsSameSiteEnabled();
   static bool PathMatches(nsCookie* aCookie, const nsACString& aPath);
   static bool CanSetCookie(nsIURI *aHostURI, const nsCookieKey& aKey, nsCookieAttributes &aCookieAttributes, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel, bool aLeaveSercureAlone, bool &aSetCookie, mozIThirdPartyUtil* aThirdPartyUtil);
   static CookieStatus CheckPrefs(nsICookiePermission *aPermissionServices, uint8_t aCookieBehavior, bool aThirdPartySession, bool aThirdPartyNonsecureSession, nsIURI *aHostURI, bool aIsForeign, const char *aCookieHeader, const int aNumOfCookies, const OriginAttributes& aOriginAttrs);
   static int64_t ParseServerTime(const nsCString &aServerTime);
   void GetCookiesForURI(nsIURI *aHostURI, bool aIsForeign, bool aIsSafeTopLevelNav, bool aIsTopLevelForeign, bool aHttpBound, const OriginAttributes& aOriginAttrs, nsTArray<nsCookie*>& aCookieList);
 
   protected:
     virtual ~nsCookieService();
--- a/netwerk/dns/TRRService.cpp
+++ b/netwerk/dns/TRRService.cpp
@@ -568,26 +568,33 @@ TRRService::CompleteLookup(nsHostRecord 
       NS_NewTimerWithCallback(getter_AddRefs(mRetryConfirmTimer),
                               this, mRetryConfirmInterval,
                               nsITimer::TYPE_ONE_SHOT);
       if (mRetryConfirmInterval < 64000) {
         // double the interval up to this point
         mRetryConfirmInterval *= 2;
       }
     } else {
+      if (mMode != MODE_TRRONLY) {
+        // don't accumulate trronly data here since trronly failures are
+        // handled above by trying again, so counting the successes here would
+        // skew the numbers
+        Telemetry::Accumulate(Telemetry::DNS_TRR_NS_VERFIFIED,
+                              (mConfirmationState == CONFIRM_OK));
+      }
       mRetryConfirmInterval = 1000;
     }
     return LOOKUP_OK;
   }
 
   // when called without a host record, this is a domain name check response.
   if (NS_SUCCEEDED(status)) {
     LOG(("TRR verified %s to be fine!\n", newRRSet->mHostName));
   } else {
-    LOG(("TRR says %s doesn't resove as NS!\n", newRRSet->mHostName));
+    LOG(("TRR says %s doesn't resolve as NS!\n", newRRSet->mHostName));
     TRRBlacklist(nsCString(newRRSet->mHostName), pb, false);
   }
   return LOOKUP_OK;
 }
 
 #undef LOG
 
 } // namespace net
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -295,33 +295,31 @@ nsHostRecord::ResolveComplete()
                                   Telemetry::LABELS_DNS_TRR_RACE::NativeFasterBy50 :
                                   Telemetry::LABELS_DNS_TRR_RACE::NativeFaster);
             LOG(("nsHostRecord::Complete %s Dns Race: NATIVE\n", host.get()));
         }
     }
 
     switch(mResolverMode) {
     case MODE_NATIVEONLY:
+    case MODE_TRROFF:
         AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::nativeOnly);
         break;
     case MODE_PARALLEL:
         AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrRace);
         break;
     case MODE_TRRFIRST:
         AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrFirst);
         break;
     case MODE_TRRONLY:
         AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOnly);
         break;
     case MODE_SHADOW:
         AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrShadow);
         break;
-    case MODE_TRROFF:
-        AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOff);
-        break;
     }
 
     if (mTRRUsed && !mTRRSuccess && mNativeSuccess && gTRRService) {
         gTRRService->TRRBlacklist(nsCString(host), pb, true);
     }
 }
 
 nsHostRecord::~nsHostRecord()
--- a/security/manager/ssl/nsIX509CertDB.idl
+++ b/security/manager/ssl/nsIX509CertDB.idl
@@ -73,27 +73,16 @@ interface nsIX509CertDB : nsISupports {
    *
    *  @param aDBkey Database internal key, as obtained using
    *                attribute dbkey in nsIX509Cert.
    */
   [must_use]
   nsIX509Cert findCertByDBKey(in ACString aDBkey);
 
   /**
-   *  Find a certificate by email address.
-   *
-   *  @param aEmailAddress The email address to be used as the key
-   *                       to find the certificate.
-   *
-   *  @return The matching certificate if found.
-   */
-  [must_use]
-  nsIX509Cert findCertByEmailAddress(in ACString aEmailAddress);
-
-  /**
    *  Use this to import a stream sent down as a mime type into
    *  the certificate database on the default token.
    *  The stream may consist of one or more certificates.
    *
    *  @param data The raw data to be imported
    *  @param length The length of the data to be imported
    *  @param type The type of the certificate, see constants in nsIX509Cert
    *  @param ctx A UI context.
@@ -295,64 +284,38 @@ interface nsIX509CertDB : nsISupports {
    *              effectively ignored by gecko, but they still must be specified
    *              (at least by a final trailing comma) because this argument is
    *              passed to CERT_DecodeTrustString.
    * @return nsIX509Cert the resulting certificate
    */
   [must_use]
   nsIX509Cert addCert(in ACString certDER, in ACString trust);
 
-  // Flags for verifyCertNow (these must match the values in CertVerifier.cpp):
-  // Prevent network traffic. Doesn't work with classic verification.
+  // Flags for asyncVerifyCertAtTime (these must match the values in
+  // CertVerifier.cpp):
+  // Prevent network traffic.
   const uint32_t FLAG_LOCAL_ONLY = 1 << 0;
   // Do not fall back to DV verification after attempting EV validation.
-  // Actually does prevent network traffic, but can cause a valid EV
-  // certificate to not be considered valid.
   const uint32_t FLAG_MUST_BE_EV = 1 << 1;
 
-  /** Warning: This interface is inteded to use only for testing only as:
-   *    1. It can create IO on the main thread.
-   *    2. It is in constant change, so in/out can change at any release.
-   *
-   *  Obtain the verification result for a cert given a particular usage.
-   *  On success, the call returns 0, the chain built during verification,
-   *  and whether the cert is good for EV usage.
-   *  On failure, the call returns the PRErrorCode for the verification failure
+  /*
+   * Asynchronously verify a certificate given a set of parameters. Calls the
+   * `verifyCertFinished` function on the provided `nsICertVerificationCallback`
+   * with the results of the verification operation.
+   * See the documentation for  nsICertVerificationCallback.
    *
-   *  @param aCert Obtain the stored trust of this certificate
-   *  @param aUsage a integer representing the usage from NSS
-   *  @param aFlags flags as described above
-   *  @param aHostname the (optional) hostname to verify for
-   *  @param aTime the time at which to verify, in seconds since the epoch
-   *  @param aVerifiedChain chain of verification up to the root if success
-   *  @param aHasEVPolicy bool that signified that the cert was an EV cert
-   *  @return 0 if success or the value or the error code for the verification
-   *          failure
-   */
-  [must_use]
-  int32_t /*PRErrorCode*/
-    verifyCertAtTime(in nsIX509Cert aCert,
-                     in int64_t /*SECCertificateUsage*/ aUsage,
-                     in uint32_t aFlags,
-                     in ACString aHostname,
-                     in uint64_t aTime,
-                     out nsIX509CertList aVerifiedChain,
-                     out bool aHasEVPolicy);
-  [must_use]
-  int32_t /*PRErrorCode*/
-    verifyCertNow(in nsIX509Cert aCert,
-                  in int64_t /*SECCertificateUsage*/ aUsage,
-                  in uint32_t aFlags,
-                  in ACString aHostname,
-                  out nsIX509CertList aVerifiedChain,
-                  out bool aHasEVPolicy);
-
-  /**
-   * Similar to the above, but asynchronous. As a result, use of this API is not
-   * limited to tests.
+   * @param aCert the certificate to verify
+   * @param aUsage an integer representing the usage to verify for (see
+   *               SECCertificateUsage in certt.h from NSS)
+   * @param aFlags flags as described above
+   * @param aHostname the (optional) hostname to verify for
+   * @param aTime the time at which to verify, in seconds since the epoch
+   * @param aCallback the nsICertVerificationCallback that will receive the
+                      results of this verification
+   * @return a succeeding nsresult if the job was dispatched successfully
    */
   [must_use]
   void asyncVerifyCertAtTime(in nsIX509Cert aCert,
                              in int64_t /*SECCertificateUsage*/ aUsage,
                              in uint32_t aFlags,
                              in ACString aHostname,
                              in uint64_t aTime,
                              in nsICertVerificationCallback aCallback);
--- a/security/manager/ssl/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/nsNSSCertificateDB.cpp
@@ -884,72 +884,16 @@ nsNSSCertificateDB::ExportPKCS12File(nsI
   if (count == 0) {
     return NS_OK;
   }
   nsPKCS12Blob blob;
   return blob.ExportToFile(aFile, certs, count);
 }
 
 NS_IMETHODIMP
-nsNSSCertificateDB::FindCertByEmailAddress(const nsACString& aEmailAddress,
-                                           nsIX509Cert** _retval)
-{
-  nsresult rv = BlockUntilLoadableRootsLoaded();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
-  NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
-
-  const nsCString& flatEmailAddress = PromiseFlatCString(aEmailAddress);
-  UniqueCERTCertList certlist(
-    PK11_FindCertsFromEmailAddress(flatEmailAddress.get(), nullptr));
-  if (!certlist)
-    return NS_ERROR_FAILURE;
-
-  // certlist now contains certificates with the right email address,
-  // but they might not have the correct usage or might even be invalid
-
-  if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
-    return NS_ERROR_FAILURE; // no certs found
-
-  CERTCertListNode *node;
-  // search for a valid certificate
-  for (node = CERT_LIST_HEAD(certlist);
-       !CERT_LIST_END(node, certlist);
-       node = CERT_LIST_NEXT(node)) {
-
-    UniqueCERTCertList unusedCertChain;
-    mozilla::pkix::Result result =
-      certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
-                               mozilla::pkix::Now(),
-                               nullptr /*XXX pinarg*/,
-                               nullptr /*hostname*/,
-                               unusedCertChain);
-    if (result == mozilla::pkix::Success) {
-      break;
-    }
-  }
-
-  if (CERT_LIST_END(node, certlist)) {
-    // no valid cert found
-    return NS_ERROR_FAILURE;
-  }
-
-  // node now contains the first valid certificate with correct usage
-  RefPtr<nsNSSCertificate> nssCert = nsNSSCertificate::Create(node->cert);
-  if (!nssCert)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  nssCert.forget(_retval);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64,
                                     /*out*/ nsIX509Cert** _retval)
 {
   if (!_retval) {
     return NS_ERROR_INVALID_POINTER;
   }
 
   // Base64Decode() doesn't consider a zero length input as an error, and just
@@ -1301,45 +1245,16 @@ VerifyCertAtTime(nsIX509Cert* aCert,
   if (result == mozilla::pkix::Success && evOidPolicy != SEC_OID_UNKNOWN) {
     *aHasEVPolicy = true;
   }
   nssCertList.forget(aVerifiedChain);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
-                                  int64_t /*SECCertificateUsage*/ aUsage,
-                                  uint32_t aFlags,
-                                  const nsACString& aHostname,
-                                  nsIX509CertList** aVerifiedChain,
-                                  bool* aHasEVPolicy,
-                                  int32_t* /*PRErrorCode*/ _retval)
-{
-  return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname,
-                            mozilla::pkix::Now(),
-                            aVerifiedChain, aHasEVPolicy, _retval);
-}
-
-NS_IMETHODIMP
-nsNSSCertificateDB::VerifyCertAtTime(nsIX509Cert* aCert,
-                                     int64_t /*SECCertificateUsage*/ aUsage,
-                                     uint32_t aFlags,
-                                     const nsACString& aHostname,
-                                     uint64_t aTime,
-                                     nsIX509CertList** aVerifiedChain,
-                                     bool* aHasEVPolicy,
-                                     int32_t* /*PRErrorCode*/ _retval)
-{
-  return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname,
-                            mozilla::pkix::TimeFromEpochInSeconds(aTime),
-                            aVerifiedChain, aHasEVPolicy, _retval);
-}
-
 class VerifyCertAtTimeTask final : public CryptoTask
 {
 public:
   VerifyCertAtTimeTask(nsIX509Cert* aCert, int64_t aUsage, uint32_t aFlags,
                        const nsACString& aHostname, uint64_t aTime,
                        nsICertVerificationCallback* aCallback)
     : mCert(aCert)
     , mUsage(aUsage)
@@ -1356,19 +1271,20 @@ public:
 
 private:
   virtual nsresult CalculateResult() override
   {
     nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID);
     if (!certDB) {
       return NS_ERROR_FAILURE;
     }
-    return certDB->VerifyCertAtTime(mCert, mUsage, mFlags, mHostname, mTime,
-                                    getter_AddRefs(mVerifiedCertList),
-                                    &mHasEVPolicy, &mPRErrorCode);
+    return VerifyCertAtTime(mCert, mUsage, mFlags, mHostname,
+                            mozilla::pkix::TimeFromEpochInSeconds(mTime),
+                            getter_AddRefs(mVerifiedCertList),
+                            &mHasEVPolicy, &mPRErrorCode);
   }
 
   virtual void CallCallback(nsresult rv) override
   {
     if (NS_FAILED(rv)) {
       Unused << mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE,
                                               nullptr, false);
     } else {
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -171,49 +171,63 @@ function setCertTrust(cert, trustString)
 }
 
 function getXPCOMStatusFromNSS(statusNSS) {
   let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"]
                            .getService(Ci.nsINSSErrorsService);
   return nssErrorsService.getXPCOMFromNSSError(statusNSS);
 }
 
+// Helper for checkCertErrorGenericAtTime
+class CertVerificationExpectedErrorResult {
+  constructor(certName, expectedError, expectedEVStatus, resolve) {
+    this.certName = certName;
+    this.expectedError = expectedError;
+    this.expectedEVStatus = expectedEVStatus;
+    this.resolve = resolve;
+  }
+
+  verifyCertFinished(aPRErrorCode, aVerifiedChain, aHasEVPolicy) {
+    equal(aPRErrorCode, this.expectedError,
+          `verifying ${this.certName}: should get error ${this.expectedError}`);
+    if (this.expectedEVStatus != undefined) {
+      equal(aHasEVPolicy, this.expectedEVStatus,
+            `verifying ${this.certName}: ` +
+            `should ${this.expectedEVStatus ? "be" : "not be"} EV`);
+    }
+    this.resolve();
+  }
+}
+
 // certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation.
 // In particular, hostname is optional.
 function checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, time,
-                                     /* optional */ hasEVPolicy,
+                                     /* optional */ isEVExpected,
                                      /* optional */ hostname) {
-  info(`cert cn=${cert.commonName}`);
-  info(`cert issuer cn=${cert.issuerCommonName}`);
-  let verifiedChain = {};
-  let error = certdb.verifyCertAtTime(cert, usage, NO_FLAGS, hostname, time,
-                                      verifiedChain, hasEVPolicy || {});
-  Assert.equal(error, expectedError,
-               "Actual and expected error should match");
+  return new Promise((resolve, reject) => {
+      let result = new CertVerificationExpectedErrorResult(
+        cert.commonName, expectedError, isEVExpected, resolve);
+      certdb.asyncVerifyCertAtTime(cert, usage, NO_FLAGS, hostname, time,
+                                   result);
+  });
 }
 
 // certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation.
 // In particular, hostname is optional.
 function checkCertErrorGeneric(certdb, cert, expectedError, usage,
-                               /* optional */ hasEVPolicy,
-                               /* optional */ hostname) {
-  info(`cert cn=${cert.commonName}`);
-  info(`cert issuer cn=${cert.issuerCommonName}`);
-  let verifiedChain = {};
-  let error = certdb.verifyCertNow(cert, usage, NO_FLAGS, hostname,
-                                   verifiedChain, hasEVPolicy || {});
-  Assert.equal(error, expectedError,
-               "Actual and expected error should match");
+                                     /* optional */ isEVExpected,
+                                     /* optional */ hostname) {
+  let now = (new Date()).getTime() / 1000;
+  return checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, now,
+                                     isEVExpected, hostname);
 }
 
 function checkEVStatus(certDB, cert, usage, isEVExpected) {
-  let hasEVPolicy = {};
-  checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage, hasEVPolicy);
-  Assert.equal(hasEVPolicy.value, isEVExpected,
-               "Actual and expected EV status should match");
+  return checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage,
+                               isEVExpected);
 }
 
 function _getLibraryFunctionWithNoArguments(functionName, libraryName,
                                             returnType) {
   // Open the NSS library. copied from services/crypto/modules/WeaveCrypto.js
   let path = ctypes.libraryName(libraryName);
 
   // XXX really want to be able to pass specific dlopen flags here.
@@ -668,16 +682,25 @@ function startOCSPResponder(serverPort, 
         Assert.equal(expectedResponseTypes.length, 0,
                      "Should have 0 remaining expected response types");
       }
       httpServer.stop(callback);
     }
   };
 }
 
+// Given an OCSP responder (see startOCSPResponder), returns a promise that
+// resolves when the responder has successfully stopped.
+function stopOCSPResponder(responder) {
+  return new Promise((resolve, reject) => {
+    responder.stop(resolve);
+  });
+}
+
+
 // A prototype for a fake, error-free sslstatus
 var FakeSSLStatus = function(certificate) {
   this.serverCert = certificate;
 };
 
 FakeSSLStatus.prototype = {
   serverCert: null,
   cipherName: null,
--- a/security/manager/ssl/tests/unit/test_add_preexisting_cert.js
+++ b/security/manager/ssl/tests/unit/test_add_preexisting_cert.js
@@ -20,25 +20,25 @@ function load_cert(cert, trust) {
 function getDERString(cert) {
   let derString = "";
   for (let rawByte of cert.getRawDER({})) {
     derString += String.fromCharCode(rawByte);
   }
   return derString;
 }
 
-function run_test() {
+add_task(async function() {
   load_cert("ca", "CTu,CTu,CTu");
   let int_cert = load_cert("int-limited-depth", "CTu,CTu,CTu");
   let file = "test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem";
   let cert_pem = readFile(do_get_file(file));
   let ee = certDB.constructX509FromBase64(pemToBase64(cert_pem));
-  checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
+  await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
   // Change the already existing intermediate certificate's trust using
   // addCertFromBase64().
   notEqual(int_cert, null, "Intermediate cert should be in the cert DB");
   let base64_cert = btoa(getDERString(int_cert));
   let returnedEE = certDB.addCertFromBase64(base64_cert, "p,p,p");
   notEqual(returnedEE, null, "addCertFromBase64 should return a certificate");
-  checkCertErrorGeneric(certDB, ee, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageSSLServer);
-}
+  await checkCertErrorGeneric(certDB, ee, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageSSLServer);
+});
--- a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
@@ -26,22 +26,22 @@ function certFromFile(certName) {
 function loadCertWithTrust(certName, trustString) {
   addCertFromFile(gCertDB, `test_baseline_requirements/${certName}.pem`,
                   trustString);
 }
 
 function checkCertOn25August2016(cert, expectedResult) {
   // (new Date("2016-08-25T00:00:00Z")).getTime() / 1000
   const VALIDATION_TIME = 1472083200;
-  checkCertErrorGenericAtTime(gCertDB, cert, expectedResult,
-                              certificateUsageSSLServer, VALIDATION_TIME, {},
-                              "example.com");
+  return checkCertErrorGenericAtTime(gCertDB, cert, expectedResult,
+                                     certificateUsageSSLServer, VALIDATION_TIME,
+                                     false, "example.com");
 }
 
-function run_test() {
+add_task(async function() {
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("security.pki.name_matching_mode");
     Services.prefs.clearUserPref("security.test.built_in_root_hash");
     Services.prefs.clearUserPref("privacy.reduceTimerPrecision");
   });
 
   Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false);
 
@@ -50,142 +50,142 @@ function run_test() {
   // When verifying a certificate, if the trust anchor is not a built-in root,
   // name matching will fall back to using the subject common name if necessary
   // (i.e. if there is no subject alternative name extension or it does not
   // contain any dNSName or iPAddress entries). Thus, since imported roots are
   // not in general treated as built-ins, these should all successfully verify
   // regardless of the value of the pref.
   Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
   info("current mode: always fall back, root not built-in");
-  checkCertOn25August2016(certFromFile("no-san-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-older"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                          PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-older"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                PRErrorCodeSuccess);
 
   Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
   info("current mode: fall back for notBefore < August 23, 2016, root " +
        "not built-in");
-  checkCertOn25August2016(certFromFile("no-san-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-older"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                          PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-older"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                PRErrorCodeSuccess);
 
   Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
   info("current mode: fall back for notBefore < August 23, 2015, root " +
        "not built-in");
-  checkCertOn25August2016(certFromFile("no-san-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-older"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                          PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-older"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                PRErrorCodeSuccess);
 
   Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
   info("current mode: never fall back, root not built-in");
-  checkCertOn25August2016(certFromFile("no-san-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("no-san-older"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                          PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                          PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("no-san-older"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                PRErrorCodeSuccess);
+  await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                PRErrorCodeSuccess);
 
   // In debug builds, we can treat an imported root as a built-in, and thus we
   // can actually test the different values of the pref.
   if (isDebugBuild) {
     let root = certFromFile("ca");
     Services.prefs.setCharPref("security.test.built_in_root_hash",
                                root.sha256Fingerprint);
 
     // Always fall back if necessary.
     Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
     info("current mode: always fall back, root built-in");
-    checkCertOn25August2016(certFromFile("no-san-recent"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("no-san-old"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("no-san-older"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                            PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("no-san-old"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("no-san-older"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                  PRErrorCodeSuccess);
 
     // Only fall back if notBefore < 23 August 2016
     Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
     info("current mode: fall back for notBefore < August 23, 2016, root " +
          "built-in");
-    checkCertOn25August2016(certFromFile("no-san-recent"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("no-san-old"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("no-san-older"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                            PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("no-san-old"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("no-san-older"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                  PRErrorCodeSuccess);
 
     // Only fall back if notBefore < 23 August 2015
     Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
     info("current mode: fall back for notBefore < August 23, 2015, root " +
          "built-in");
-    checkCertOn25August2016(certFromFile("no-san-recent"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("no-san-old"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("no-san-older"),
-                            PRErrorCodeSuccess);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                            PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("no-san-old"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("no-san-older"),
+                                  PRErrorCodeSuccess);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                  PRErrorCodeSuccess);
 
     // Never fall back.
     Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
     info("current mode: never fall back, root built-in");
-    checkCertOn25August2016(certFromFile("no-san-recent"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("no-san-old"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("no-san-older"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
-    checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
-                            SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("no-san-recent"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("no-san-old"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("no-san-older"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
+    await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+                                  SSL_ERROR_BAD_CERT_DOMAIN);
   }
-}
+});
--- a/security/manager/ssl/tests/unit/test_certDB_import.js
+++ b/security/manager/ssl/tests/unit/test_certDB_import.js
@@ -63,27 +63,35 @@ function getCertAsByteArray(certPath) {
   let byteArray = [];
   for (let i = 0; i < certBytes.length; i++) {
     byteArray.push(certBytes.charCodeAt(i));
   }
 
   return byteArray;
 }
 
-function findCertByCommonName(commonName) {
+function commonFindCertBy(propertyName, value) {
   let certEnumerator = gCertDB.getCerts().getEnumerator();
   while (certEnumerator.hasMoreElements()) {
     let cert = certEnumerator.getNext().QueryInterface(Ci.nsIX509Cert);
-    if (cert.commonName == commonName) {
+    if (cert[propertyName] == value) {
       return cert;
     }
   }
   return null;
 }
 
+function findCertByCommonName(commonName) {
+  return commonFindCertBy("commonName", commonName);
+}
+
+function findCertByEmailAddress(emailAddress) {
+  return commonFindCertBy("emailAddress", emailAddress);
+}
+
 function testImportCACert() {
   // Sanity check the CA cert is missing.
   equal(findCertByCommonName(CA_CERT_COMMON_NAME), null,
         "CA cert should not be in the database before import");
 
   // Import and check for success.
   let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem");
   gCertDB.importCertificates(caArray, caArray.length, Ci.nsIX509Cert.CA_CERT,
@@ -102,22 +110,21 @@ function run_test() {
   let certificateDialogsCID =
     MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
                            gCertificateDialogs);
   registerCleanupFunction(() => {
     MockRegistrar.unregister(certificateDialogsCID);
   });
 
   // Sanity check the e-mail cert is missing.
-  throws(() => gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS),
-         /NS_ERROR_FAILURE/,
+  equal(findCertByEmailAddress(TEST_EMAIL_ADDRESS), null,
          "E-mail cert should not be in the database before import");
 
   // Import the CA cert so that the e-mail import succeeds.
   testImportCACert();
 
   // Import the e-mail cert and check for success.
   let emailArray = getCertAsByteArray("test_certDB_import/emailEE.pem");
   gCertDB.importEmailCertificate(emailArray, emailArray.length,
                                  gInterfaceRequestor);
-  notEqual(gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS), null,
+  notEqual(findCertByEmailAddress(TEST_EMAIL_ADDRESS), null,
            "E-mail cert should now be found in the database");
 }
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -161,28 +161,29 @@ var addonManager = Cc["@mozilla.org/addo
 addonManager.observe(null, "addons-startup", null);
 
 var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
                   .createInstance(Ci.nsIScriptableUnicodeConverter);
 converter.charset = "UTF-8";
 
 function verify_cert(file, expectedError) {
   let ee = constructCertFromFile(file);
-  checkCertErrorGeneric(certDB, ee, expectedError, certificateUsageSSLServer);
+  return checkCertErrorGeneric(certDB, ee, expectedError,
+                               certificateUsageSSLServer);
 }
 
 // The certificate blocklist currently only applies to TLS server certificates.
-function verify_non_tls_usage_succeeds(file) {
+async function verify_non_tls_usage_succeeds(file) {
   let ee = constructCertFromFile(file);
-  checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
 }
 
 function load_cert(cert, trust) {
   let file = "bad_certs/" + cert + ".pem";
   addCertFromFile(certDB, file, trust);
 }
 
 function test_is_revoked(certList, issuerString, serialString, subjectString,
@@ -304,17 +305,17 @@ function run_test() {
                      { " Rym6o+VN9xgZXT/QLrvN/nv1ZN4=": true},
                    "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=":
                      { " a0X7/7DlTaedpgrIJg25iBPOkIM=": true},
                    "YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy":
                      { " YW5vdGhlciBzZXJpYWwu": true,
                        " c2VyaWFsMi4=": true }
                  };
 
-  add_test(function () {
+  add_task(async function() {
     // check some existing items in revocations.txt are blocked. Since the
     // CertBlocklistItems don't know about the data they contain, we can use
     // arbitrary data (not necessarily DER) to test if items are revoked or not.
     // This test corresponds to:
     // issuer: c29tZSBpbWFnaW5hcnkgaXNzdWVy
     // serial: c2VyaWFsLg==
     ok(test_is_revoked(certList, "some imaginary issuer", "serial."),
       "issuer / serial pair should be blocked");
@@ -331,35 +332,33 @@ function run_test() {
     // (we test this issuer twice to ensure we can read multiple serials)
     ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
       "issuer / serial pair should be blocked");
 
     // Soon we'll load a blocklist which revokes test-int.pem, which issued
     // test-int-ee.pem.
     // Check the cert validates before we load the blocklist
     let file = "test_onecrl/test-int-ee.pem";
-    verify_cert(file, PRErrorCodeSuccess);
+    await verify_cert(file, PRErrorCodeSuccess);
 
     // The blocklist also revokes other-test-ca.pem, which issued
     // other-ca-ee.pem. Check the cert validates before we load the blocklist
     file = "bad_certs/other-issuer-ee.pem";
-    verify_cert(file, PRErrorCodeSuccess);
+    await verify_cert(file, PRErrorCodeSuccess);
 
     // The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash.
     // Check the cert validates before we load the blocklist
     file = "test_onecrl/same-issuer-ee.pem";
-    verify_cert(file, PRErrorCodeSuccess);
-
-    run_next_test();
+    await verify_cert(file, PRErrorCodeSuccess);
   });
 
   // blocklist load is async so we must use add_test from here
   add_task(fetch_blocklist);
 
-  add_test(function() {
+  add_task(async function() {
     // The blocklist will be loaded now. Let's check the data is sane.
     // In particular, we should still have the revoked issuer / serial pair
     // that was in both revocations.txt and the blocklist.
     ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
       "issuer / serial pair should be blocked");
 
     // Check that both serials in the certItem with multiple serials were read
     // properly
@@ -374,48 +373,46 @@ function run_test() {
        "issuer / serial pair should be blocked");
 
     // Check the blocklist entry has been persisted properly to the backing
     // file
     check_revocations_txt_contents(expected);
 
     // Check the blocklisted intermediate now causes a failure
     let file = "test_onecrl/test-int-ee.pem";
-    verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
-    verify_non_tls_usage_succeeds(file);
+    await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
+    await verify_non_tls_usage_succeeds(file);
 
     // Check the ee with the blocklisted root also causes a failure
     file = "bad_certs/other-issuer-ee.pem";
-    verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
-    verify_non_tls_usage_succeeds(file);
+    await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
+    await verify_non_tls_usage_succeeds(file);
 
     // Check the ee blocked by subject / pubKey causes a failure
     file = "test_onecrl/same-issuer-ee.pem";
-    verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
-    verify_non_tls_usage_succeeds(file);
+    await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
+    await verify_non_tls_usage_succeeds(file);
 
     // Check a non-blocklisted chain still validates OK
     file = "bad_certs/default-ee.pem";
-    verify_cert(file, PRErrorCodeSuccess);
+    await verify_cert(file, PRErrorCodeSuccess);
 
     // Check a bad cert is still bad (unknown issuer)
     file = "bad_certs/unknownissuer.pem";
-    verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER);
+    await verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER);
 
     // check that save with no further update is a no-op
     let lastModified = gRevocations.lastModifiedTime;
     // add an already existing entry
     certList.revokeCertByIssuerAndSerial("YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy",
                                          "c2VyaWFsMi4=");
     certList.saveEntries();
     let newModified = gRevocations.lastModifiedTime;
     equal(lastModified, newModified,
           "saveEntries with no modifications should not update the backing file");
-
-    run_next_test();
   });
 
   add_test(function() {
     // Check the blocklist entry has not changed
     check_revocations_txt_contents(expected);
     run_next_test();
   });
 
--- a/security/manager/ssl/tests/unit/test_cert_eku.js
+++ b/security/manager/ssl/tests/unit/test_cert_eku.js
@@ -18,120 +18,122 @@ function certFromFile(certName) {
   return constructCertFromFile(`test_cert_eku/${certName}.pem`);
 }
 
 function loadCertWithTrust(certName, trustString) {
   addCertFromFile(certdb, `test_cert_eku/${certName}.pem`, trustString);
 }
 
 function checkEndEntity(cert, expectedResult) {
-  checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, expectedResult,
+                               certificateUsageSSLServer);
 }
 
 function checkCertOn25August2016(cert, expectedResult) {
   // (new Date("2016-08-25T00:00:00Z")).getTime() / 1000
   const VALIDATION_TIME = 1472083200;
-  checkCertErrorGenericAtTime(certdb, cert, expectedResult,
-                              certificateUsageSSLServer, VALIDATION_TIME);
+  return checkCertErrorGenericAtTime(certdb, cert, expectedResult,
+                                     certificateUsageSSLServer,
+                                     VALIDATION_TIME);
 }
 
 
-function run_test() {
+add_task(async function() {
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("privacy.reduceTimerPrecision");
   });
   Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false);
 
   loadCertWithTrust("ca", "CTu,,");
   // end-entity has id-kp-serverAuth => success
-  checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess);
   // end-entity has id-kp-serverAuth => success
-  checkEndEntity(certFromFile("ee-SA-CA"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-SA-CA"), PRErrorCodeSuccess);
   // end-entity has extended key usage, but id-kp-serverAuth is not present =>
   // failure
-  checkEndEntity(certFromFile("ee-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
   // end-entity has id-kp-serverAuth => success
-  checkEndEntity(certFromFile("ee-SA-nsSGC"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-SA-nsSGC"), PRErrorCodeSuccess);
 
   // end-entity has extended key usage, but id-kp-serverAuth is not present =>
   // failure (in particular, Netscape Server Gated Crypto (also known as
   // Netscape Step Up) is not an acceptable substitute for end-entity
   // certificates).
   // Verify this for all Netscape Step Up policy configurations.
   // 0 = "always accept nsSGC in place of serverAuth for CA certificates"
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0);
-  checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
   // 1 = "accept nsSGC before 23 August 2016"
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1);
-  checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
   // 2 = "accept nsSGC before 23 August 2015"
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2);
-  checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
   // 3 = "never accept nsSGC"
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3);
-  checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
 
   // end-entity has id-kp-OCSPSigning, which is not acceptable for end-entity
   // certificates being verified as TLS server certificates => failure
-  checkEndEntity(certFromFile("ee-SA-OCSP"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-SA-OCSP"), SEC_ERROR_INADEQUATE_CERT_TYPE);
 
   // intermediate has id-kp-serverAuth => success
   loadCertWithTrust("int-SA", ",,");
-  checkEndEntity(certFromFile("ee-int-SA"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-int-SA"), PRErrorCodeSuccess);
   // intermediate has id-kp-serverAuth => success
   loadCertWithTrust("int-SA-CA", ",,");
-  checkEndEntity(certFromFile("ee-int-SA-CA"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-int-SA-CA"), PRErrorCodeSuccess);
   // intermediate has extended key usage, but id-kp-serverAuth is not present
   // => failure
   loadCertWithTrust("int-CA", ",,");
-  checkEndEntity(certFromFile("ee-int-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+  await checkEndEntity(certFromFile("ee-int-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
   // intermediate has id-kp-serverAuth => success
   loadCertWithTrust("int-SA-nsSGC", ",,");
-  checkEndEntity(certFromFile("ee-int-SA-nsSGC"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-int-SA-nsSGC"), PRErrorCodeSuccess);
 
   // Intermediate has Netscape Server Gated Crypto. Success will depend on the
   // Netscape Step Up policy configuration and the notBefore property of the
   // intermediate.
   loadCertWithTrust("int-nsSGC-recent", ",,");
   loadCertWithTrust("int-nsSGC-old", ",,");
   loadCertWithTrust("int-nsSGC-older", ",,");
   // 0 = "always accept nsSGC in place of serverAuth for CA certificates"
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0);
   info("Netscape Step Up policy: always accept");
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
                           PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
                           PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
                           PRErrorCodeSuccess);
   // 1 = "accept nsSGC before 23 August 2016"
   info("Netscape Step Up policy: accept before 23 August 2016");
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
                           SEC_ERROR_INADEQUATE_CERT_TYPE);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
                           PRErrorCodeSuccess);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
                           PRErrorCodeSuccess);
   // 2 = "accept nsSGC before 23 August 2015"
   info("Netscape Step Up policy: accept before 23 August 2015");
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
                           SEC_ERROR_INADEQUATE_CERT_TYPE);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
                           SEC_ERROR_INADEQUATE_CERT_TYPE);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
                           PRErrorCodeSuccess);
   // 3 = "never accept nsSGC"
   info("Netscape Step Up policy: never accept");
   Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
                           SEC_ERROR_INADEQUATE_CERT_TYPE);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
                           SEC_ERROR_INADEQUATE_CERT_TYPE);
-  checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+  await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
                           SEC_ERROR_INADEQUATE_CERT_TYPE);
 
   // intermediate has id-kp-OCSPSigning, which is acceptable for CA
   // certificates => success
   loadCertWithTrust("int-SA-OCSP", ",,");
-  checkEndEntity(certFromFile("ee-int-SA-OCSP"), PRErrorCodeSuccess);
-}
+  await checkEndEntity(certFromFile("ee-int-SA-OCSP"), PRErrorCodeSuccess);
+});
--- a/security/manager/ssl/tests/unit/test_cert_embedded_null.js
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null.js
@@ -9,30 +9,32 @@
 // Includes a similar test case but for the subject alternative name extension.
 
 "use strict";
 
 do_get_profile(); // must be called before getting nsIX509CertDB
 const certdb = Cc["@mozilla.org/security/x509certdb;1"]
                  .getService(Ci.nsIX509CertDB);
 
-function do_testcase(certname, checkCommonName) {
+async function do_testcase(certname, checkCommonName) {
   let cert = constructCertFromFile(`test_cert_embedded_null/${certname}.pem`);
   // Where applicable, check that the testcase is meaningful (i.e. that the
   // certificate's subject common name has an embedded NUL in it).
   if (checkCommonName) {
     equal(cert.commonName, "www.bank1.com\\00www.bad-guy.com",
           "certificate subject common name should have an embedded NUL byte");
   }
-  checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
-                        certificateUsageSSLServer, {}, "www.bank1.com");
-  checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
-                        certificateUsageSSLServer, {}, "www.bad-guy.com");
+  await checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
+                              certificateUsageSSLServer, undefined,
+                              "www.bank1.com");
+  await checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
+                              certificateUsageSSLServer, undefined,
+                              "www.bad-guy.com");
 }
 
-function run_test() {
+add_task(async function() {
   addCertFromFile(certdb, "test_cert_embedded_null/ca.pem", "CTu,,");
 
-  do_testcase("embeddedNull", true);
-  do_testcase("embeddedNullSAN", false);
-  do_testcase("embeddedNullCNAndSAN", true);
-  do_testcase("embeddedNullSAN2", false);
-}
+  await do_testcase("embeddedNull", true);
+  await do_testcase("embeddedNullSAN", false);
+  await do_testcase("embeddedNullCNAndSAN", true);
+  await do_testcase("embeddedNullSAN2", false);
+});
--- a/security/manager/ssl/tests/unit/test_cert_sha1.js
+++ b/security/manager/ssl/tests/unit/test_cert_sha1.js
@@ -22,21 +22,22 @@ function certFromFile(certName) {
   return constructCertFromFile("test_cert_sha1/" + certName + ".pem");
 }
 
 function loadCertWithTrust(certName, trustString) {
   addCertFromFile(certdb, "test_cert_sha1/" + certName + ".pem", trustString);
 }
 
 function checkEndEntity(cert, expectedResult) {
-  checkCertErrorGenericAtTime(certdb, cert, expectedResult,
-                              certificateUsageSSLServer, VALIDATION_TIME);
+  return checkCertErrorGenericAtTime(certdb, cert, expectedResult,
+                                     certificateUsageSSLServer,
+                                     VALIDATION_TIME);
 }
 
-function run_test() {
+add_task(async function() {
   loadCertWithTrust("ca", "CTu,,");
   loadCertWithTrust("int-pre", ",,");
   loadCertWithTrust("int-post", ",,");
 
   // Test cases per pref setting
   //
   // root  intermed.  end entity
   // ===========================
@@ -82,61 +83,61 @@ function run_test() {
   // verifier does not take into account the currently configured SHA-1 policy.
   // This is in part due to implementation complexity and because this isn't
   // actually how TLS web server certificates are verified in the TLS handshake
   // (which makes a full implementation that supports heeding the SHA-1 policy
   // unnecessary).
 
   // SHA-1 allowed
   Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 0);
-  checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
 
   // SHA-1 forbidden
   Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 1);
-  checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-  checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-  checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+  await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+  await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+  await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
 
   // SHA-1 forbidden (test the case where the pref has been set to 2)
   Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 2);
-  checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-  checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-  checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+  await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+  await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+  await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
 
   // SHA-1 allowed only when issued by an imported root. First test with the
   // test root considered a built-in (on debug only - this functionality is
   // disabled on non-debug builds).
   Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 3);
   if (isDebugBuild) {
     let root = certFromFile("ca");
     Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
-    checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-    checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-    checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+    await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+    await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+    await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
     Services.prefs.clearUserPref("security.test.built_in_root_hash");
   }
 
   // SHA-1 still allowed only when issued by an imported root.
   // Now test with the test root considered a non-built-in.
-  checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
 
   // SHA-1 allowed before 2016 or when issued by an imported root. First test
   // with the test root considered a built-in.
   Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
   if (isDebugBuild) {
     let root = certFromFile("ca");
     Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
-    checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
-    checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
-    checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+    await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+    await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+    await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
     Services.prefs.clearUserPref("security.test.built_in_root_hash");
   }
 
   // SHA-1 still only allowed before 2016 or when issued by an imported root.
   // Now test with the test root considered a non-built-in.
-  checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
-}
+  await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
+});
--- a/security/manager/ssl/tests/unit/test_cert_signatures.js
+++ b/security/manager/ssl/tests/unit/test_cert_signatures.js
@@ -39,25 +39,25 @@ function readAndTamperWithNthByte(certif
 const BYTE_IN_SIGNATURE = -8;
 function addSignatureTamperedCertificate(certificatePath) {
   let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
   certdb.addCertFromBase64(base64, ",,");
 }
 
 function ensureSignatureVerificationFailure(certificatePath) {
   let cert = constructCertFromFile(certificatePath);
-  checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
-                        certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
+                               certificateUsageSSLServer);
 }
 
 function tamperWithSignatureAndEnsureVerificationFailure(certificatePath) {
   let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
   let cert = certdb.constructX509FromBase64(base64);
-  checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
-                        certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
+                               certificateUsageSSLServer);
 }
 
 // The beginning of a certificate looks like this (in hex, using DER):
 // 30 XX XX XX [the XX encode length - there are probably 3 bytes here]
 //    30 XX XX XX [length again]
 //       A0 03
 //          02 01
 //             02
@@ -76,46 +76,46 @@ function addSerialNumberTamperedCertific
                                         BYTE_IN_SERIAL_NUMBER);
   certdb.addCertFromBase64(base64, ",,");
 }
 
 function tamperWithSerialNumberAndEnsureVerificationFailure(certificatePath) {
   let base64 = readAndTamperWithNthByte(certificatePath,
                                         BYTE_IN_SERIAL_NUMBER);
   let cert = certdb.constructX509FromBase64(base64);
-  checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
-                        certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
+                               certificateUsageSSLServer);
 }
 
-function run_test() {
+add_task(async function() {
   addCertFromFile(certdb, "test_cert_signatures/ca-rsa.pem", "CTu,,");
   addCertFromFile(certdb, "test_cert_signatures/ca-secp384r1.pem", "CTu,,");
 
   // Tamper with the signatures on intermediate certificates and ensure that
   // end-entity certificates issued by those intermediates do not validate
   // successfully.
   addSignatureTamperedCertificate("test_cert_signatures/int-rsa.pem");
   addSignatureTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
-  ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
-  ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
+  await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
+  await ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
 
   // Tamper with the signatures on end-entity certificates and ensure that they
   // do not validate successfully.
-  tamperWithSignatureAndEnsureVerificationFailure(
+  await tamperWithSignatureAndEnsureVerificationFailure(
     "test_cert_signatures/ee-rsa-direct.pem");
-  tamperWithSignatureAndEnsureVerificationFailure(
+  await tamperWithSignatureAndEnsureVerificationFailure(
     "test_cert_signatures/ee-secp384r1-direct.pem");
 
   // Tamper with the serial numbers of intermediate certificates and ensure
   // that end-entity certificates issued by those intermediates do not validate
   // successfully.
   addSerialNumberTamperedCertificate("test_cert_signatures/int-rsa.pem");
   addSerialNumberTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
-  ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
-  ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
+  await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
+  await ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
 
   // Tamper with the serial numbers of end-entity certificates and ensure that
   // they do not validate successfully.
-  tamperWithSerialNumberAndEnsureVerificationFailure(
+  await tamperWithSerialNumberAndEnsureVerificationFailure(
     "test_cert_signatures/ee-rsa-direct.pem");
-  tamperWithSerialNumberAndEnsureVerificationFailure(
+  await tamperWithSerialNumberAndEnsureVerificationFailure(
     "test_cert_signatures/ee-secp384r1-direct.pem");
-}
+});
--- a/security/manager/ssl/tests/unit/test_cert_trust.js
+++ b/security/manager/ssl/tests/unit/test_cert_trust.js
@@ -18,129 +18,129 @@ function load_cert(cert_name, trust_stri
 function setup_basic_trusts(ca_cert, int_cert) {
   certdb.setCertTrust(ca_cert, Ci.nsIX509Cert.CA_CERT,
                       Ci.nsIX509CertDB.TRUSTED_SSL |
                       Ci.nsIX509CertDB.TRUSTED_EMAIL);
 
   certdb.setCertTrust(int_cert, Ci.nsIX509Cert.CA_CERT, 0);
 }
 
-function test_ca_distrust(ee_cert, cert_to_modify_trust, isRootCA) {
+async function test_ca_distrust(ee_cert, cert_to_modify_trust, isRootCA) {
   // On reset most usages are successful
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
 
 
   // Test of active distrust. No usage should pass.
   setCertTrust(cert_to_modify_trust, "p,p,p");
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageSSLServer);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageEmailRecipient);
 
   // Trust set to T  -  trusted CA to issue client certs, where client cert is
   // usageSSLClient.
   setCertTrust(cert_to_modify_trust, "T,T,T");
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
 
   // XXX(Bug 982340)
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
 
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
 
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
 
 
   // Now tests on the SSL trust bit
   setCertTrust(cert_to_modify_trust, "p,C,C");
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageSSLServer);
 
   // XXX(Bug 982340)
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
 
   // Inherited trust SSL
   setCertTrust(cert_to_modify_trust, ",C,C");
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
   // XXX(Bug 982340)
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
 
   // Now tests on the EMAIL trust bit
   setCertTrust(cert_to_modify_trust, "C,p,C");
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+                              certificateUsageEmailRecipient);
 
 
   // inherited EMAIL Trust
   setCertTrust(cert_to_modify_trust, "C,,C");
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
-                        certificateUsageSSLCA);
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
-                                                  : PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+                              certificateUsageSSLCA);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+                                                        : PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
 }
 
 
-function run_test() {
+add_task(async function() {
   let certList = [
     "ca",
     "int",
     "ee",
   ];
   let loadedCerts = [];
   for (let certName of certList) {
     loadedCerts.push(load_cert(certName, ",,"));
@@ -149,41 +149,41 @@ function run_test() {
   let ca_cert = loadedCerts[0];
   notEqual(ca_cert, null, "CA cert should have successfully loaded");
   let int_cert = loadedCerts[1];
   notEqual(int_cert, null, "Intermediate cert should have successfully loaded");
   let ee_cert = loadedCerts[2];
   notEqual(ee_cert, null, "EE cert should have successfully loaded");
 
   setup_basic_trusts(ca_cert, int_cert);
-  test_ca_distrust(ee_cert, ca_cert, true);
+  await test_ca_distrust(ee_cert, ca_cert, true);
 
   setup_basic_trusts(ca_cert, int_cert);
-  test_ca_distrust(ee_cert, int_cert, false);
+  await test_ca_distrust(ee_cert, int_cert, false);
 
   // Reset trust to default ("inherit trust")
   setCertTrust(ca_cert, ",,");
   setCertTrust(int_cert, ",,");
 
   // If an end-entity certificate is manually trusted, it may not be the root of
   // its own verified chain. In general this will cause "unknown issuer" errors
   // unless a CA trust anchor can be found.
   setCertTrust(ee_cert, "CTu,CTu,CTu");
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
-                        certificateUsageSSLServer);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
-                        certificateUsageEmailRecipient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
+                              certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER,
+                              certificateUsageEmailRecipient);
 
   // Now make a CA trust anchor available.
   setCertTrust(ca_cert, "CTu,CTu,CTu");
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageSSLClient);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailSigner);
-  checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
-                        certificateUsageEmailRecipient);
-}
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLServer);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageSSLClient);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailSigner);
+  await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+                              certificateUsageEmailRecipient);
+});
--- a/security/manager/ssl/tests/unit/test_cert_version.js
+++ b/security/manager/ssl/tests/unit/test_cert_version.js
@@ -37,154 +37,156 @@ function certFromFile(certName) {
   return constructCertFromFile("test_cert_version/" + certName + ".pem");
 }
 
 function loadCertWithTrust(certName, trustString) {
   addCertFromFile(certdb, "test_cert_version/" + certName + ".pem", trustString);
 }
 
 function checkEndEntity(cert, expectedResult) {
-  checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, expectedResult,
+                               certificateUsageSSLServer);
 }
 
 function checkIntermediate(cert, expectedResult) {
-  checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLCA);
+  return checkCertErrorGeneric(certdb, cert, expectedResult,
+                               certificateUsageSSLCA);
 }
 
 // Test that the code that decodes certificates to display them in the
 // certificate manager correctly handles the version field.
 function checkCertVersion(cert, expectedVersionString) {
   let asn1 = cert.ASN1Structure.QueryInterface(Ci.nsIASN1Sequence);
   let tbsCertificate = asn1.ASN1Objects.queryElementAt(0, Ci.nsIASN1Sequence);
   let version = tbsCertificate.ASN1Objects.queryElementAt(0, Ci.nsIASN1Object);
   equal(version.displayValue, expectedVersionString,
         "Actual and expected version strings should match");
 }
 
-function run_test() {
+add_task(async function() {
   loadCertWithTrust("ca", "CTu,,");
 
   // Section for CAs lacking the basicConstraints extension entirely:
   loadCertWithTrust("int-v1-noBC_ca", ",,");
-  checkIntermediate(certFromFile("int-v1-noBC_ca"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
-  checkEndEntity(certFromFile("ee_int-v1-noBC"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
+  await checkIntermediate(certFromFile("int-v1-noBC_ca"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
+  await checkEndEntity(certFromFile("ee_int-v1-noBC"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
   // A v1 certificate with no basicConstraints extension may issue certificates
   // if it is a trust anchor.
   loadCertWithTrust("int-v1-noBC_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v1-noBC_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v1-noBC"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v1-noBC_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v1-noBC"), PRErrorCodeSuccess);
 
   loadCertWithTrust("int-v2-noBC_ca", ",,");
-  checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v2-noBC_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
 
   loadCertWithTrust("int-v3-noBC_ca", ",,");
-  checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v3-noBC_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
 
   loadCertWithTrust("int-v4-noBC_ca", ",,");
-  checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v4-noBC_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
 
   // Section for CAs with basicConstraints not specifying cA:
   loadCertWithTrust("int-v1-BC-not-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v1-BC-not-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
 
   loadCertWithTrust("int-v2-BC-not-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v2-BC-not-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
 
   loadCertWithTrust("int-v3-BC-not-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v3-BC-not-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
 
   loadCertWithTrust("int-v4-BC-not-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
   loadCertWithTrust("int-v4-BC-not-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
-  checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+  await checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+  await checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
 
   // Section for CAs with basicConstraints specifying cA:
   loadCertWithTrust("int-v1-BC-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess);
   loadCertWithTrust("int-v1-BC-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess);
 
   loadCertWithTrust("int-v2-BC-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess);
   loadCertWithTrust("int-v2-BC-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess);
 
   loadCertWithTrust("int-v3-BC-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess);
   loadCertWithTrust("int-v3-BC-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess);
 
   loadCertWithTrust("int-v4-BC-cA_ca", ",,");
-  checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess);
   loadCertWithTrust("int-v4-BC-cA_ca", "CTu,,");
-  checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess);
+  await checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess);
 
   // Section for end-entity certificates with various basicConstraints:
-  checkEndEntity(certFromFile("ee-v1-noBC_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-v2-noBC_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-v3-noBC_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-v4-noBC_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v1-noBC_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v2-noBC_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v3-noBC_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v4-noBC_ca"), PRErrorCodeSuccess);
 
-  checkEndEntity(certFromFile("ee-v1-BC-not-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-v2-BC-not-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-v3-BC-not-cA_ca"), PRErrorCodeSuccess);
-  checkEndEntity(certFromFile("ee-v4-BC-not-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v1-BC-not-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v2-BC-not-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v3-BC-not-cA_ca"), PRErrorCodeSuccess);
+  await checkEndEntity(certFromFile("ee-v4-BC-not-cA_ca"), PRErrorCodeSuccess);
 
-  checkEndEntity(certFromFile("ee-v1-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
-  checkEndEntity(certFromFile("ee-v2-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
-  checkEndEntity(certFromFile("ee-v3-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
-  checkEndEntity(certFromFile("ee-v4-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+  await checkEndEntity(certFromFile("ee-v1-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+  await checkEndEntity(certFromFile("ee-v2-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+  await checkEndEntity(certFromFile("ee-v3-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+  await checkEndEntity(certFromFile("ee-v4-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
 
   // Section for self-signed certificates:
-  checkEndEntity(certFromFile("ss-v1-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v2-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v3-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v4-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v1-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v2-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v3-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v4-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
 
-  checkEndEntity(certFromFile("ss-v1-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v2-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v3-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v4-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v1-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v2-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v3-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v4-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
 
-  checkEndEntity(certFromFile("ss-v1-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v2-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v3-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
-  checkEndEntity(certFromFile("ss-v4-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v1-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v2-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v3-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+  await checkEndEntity(certFromFile("ss-v4-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
 
   checkCertVersion(certFromFile("ss-v1-noBC"), "Version 1");
   checkCertVersion(certFromFile("int-v2-BC-cA_ca"), "Version 2");
   checkCertVersion(certFromFile("ee-v3-BC-not-cA_ca"), "Version 3");
   checkCertVersion(certFromFile("int-v4-BC-not-cA_ca"), "Version 4");
-}
+});
--- a/security/manager/ssl/tests/unit/test_keysize.js
+++ b/security/manager/ssl/tests/unit/test_keysize.js
@@ -19,109 +19,109 @@ const certdb = Cc["@mozilla.org/security
  *        The key type of the root certificate, or the name of an elliptic
  *        curve, as output by the 'openssl ecparam -list_curves' command.
  * @param {Number} rootKeySize
  * @param {String} intKeyType
  * @param {Number} intKeySize
  * @param {String} eeKeyType
  * @param {Number} eeKeySize
  * @param {PRErrorCode} eeExpectedError
+ * @return {Promise} a promise that will resolve when the verification has
+ *                   completed
  */
 function checkChain(rootKeyType, rootKeySize, intKeyType, intKeySize,
                     eeKeyType, eeKeySize, eeExpectedError) {
   let rootName = "root_" + rootKeyType + "_" + rootKeySize;
   let intName = "int_" + intKeyType + "_" + intKeySize;
   let eeName = "ee_" + eeKeyType + "_" + eeKeySize;
 
   let intFullName = intName + "-" + rootName;
   let eeFullName = eeName + "-" + intName + "-" + rootName;
 
   addCertFromFile(certdb, `test_keysize/${rootName}.pem`, "CTu,CTu,CTu");
   addCertFromFile(certdb, `test_keysize/${intFullName}.pem`, ",,");
   let eeCert = constructCertFromFile(`test_keysize/${eeFullName}.pem`);
 
   info("cert o=" + eeCert.organization);
   info("cert issuer o=" + eeCert.issuerOrganization);
-  checkCertErrorGeneric(certdb, eeCert, eeExpectedError,
-                        certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, eeCert, eeExpectedError,
+                               certificateUsageSSLServer);
 }
 
 /**
  * Tests various RSA chains.
  *
  * @param {Number} inadequateKeySize
  * @param {Number} adequateKeySize
  */
-function checkRSAChains(inadequateKeySize, adequateKeySize) {
+async function checkRSAChains(inadequateKeySize, adequateKeySize) {
   // Chain with certs that have adequate sizes for DV
-  checkChain("rsa", adequateKeySize,
-             "rsa", adequateKeySize,
-             "rsa", adequateKeySize,
-             PRErrorCodeSuccess);
+  await checkChain("rsa", adequateKeySize,
+                   "rsa", adequateKeySize,
+                   "rsa", adequateKeySize,
+                   PRErrorCodeSuccess);
 
   // Chain with a root cert that has an inadequate size for DV
-  checkChain("rsa", inadequateKeySize,
-             "rsa", adequateKeySize,
-             "rsa", adequateKeySize,
-             MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+  await checkChain("rsa", inadequateKeySize,
+                   "rsa", adequateKeySize,
+                   "rsa", adequateKeySize,
+                   MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
 
   // Chain with an intermediate cert that has an inadequate size for DV
-  checkChain("rsa", adequateKeySize,
-             "rsa", inadequateKeySize,
-             "rsa", adequateKeySize,
-             MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+  await checkChain("rsa", adequateKeySize,
+                   "rsa", inadequateKeySize,
+                   "rsa", adequateKeySize,
+                   MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
 
   // Chain with an end entity cert that has an inadequate size for DV
-  checkChain("rsa", adequateKeySize,
-             "rsa", adequateKeySize,
-             "rsa", inadequateKeySize,
-             MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+  await checkChain("rsa", adequateKeySize,
+                   "rsa", adequateKeySize,
+                   "rsa", inadequateKeySize,
+                   MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
 }
 
-function checkECCChains() {
-  checkChain("secp256r1", 256,
-             "secp384r1", 384,
-             "secp521r1", 521,
-             PRErrorCodeSuccess);
-  checkChain("secp256r1", 256,
-             "secp224r1", 224,
-             "secp256r1", 256,
-             SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
-  checkChain("secp256r1", 256,
-             "secp256r1", 256,
-             "secp224r1", 224,
-             SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
-  checkChain("secp224r1", 224,
-             "secp256r1", 256,
-             "secp256r1", 256,
-             SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
-  checkChain("secp256r1", 256,
-             "secp256r1", 256,
-             "secp256k1", 256,
-             SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
-  checkChain("secp256k1", 256,
-             "secp256r1", 256,
-             "secp256r1", 256,
-             SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+async function checkECCChains() {
+  await checkChain("secp256r1", 256,
+                   "secp384r1", 384,
+                   "secp521r1", 521,
+                   PRErrorCodeSuccess);
+  await checkChain("secp256r1", 256,
+                   "secp224r1", 224,
+                   "secp256r1", 256,
+                   SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+  await checkChain("secp256r1", 256,
+                   "secp256r1", 256,
+                   "secp224r1", 224,
+                   SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+  await checkChain("secp224r1", 224,
+                   "secp256r1", 256,
+                   "secp256r1", 256,
+                   SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+  await checkChain("secp256r1", 256,
+                   "secp256r1", 256,
+                   "secp256k1", 256,
+                   SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+  await checkChain("secp256k1", 256,
+                   "secp256r1", 256,
+                   "secp256r1", 256,
+                   SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
 }
 
-function checkCombinationChains() {
-  checkChain("rsa", 2048,
-             "secp256r1", 256,
-             "secp384r1", 384,
-             PRErrorCodeSuccess);
-  checkChain("rsa", 2048,
-             "secp256r1", 256,
-             "secp224r1", 224,
-             SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
-  checkChain("secp256r1", 256,
-             "rsa", 1016,
-             "secp256r1", 256,
-             MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+async function checkCombinationChains() {
+  await checkChain("rsa", 2048,
+                   "secp256r1", 256,
+                   "secp384r1", 384,
+                   PRErrorCodeSuccess);
+  await checkChain("rsa", 2048,
+                   "secp256r1", 256,
+                   "secp224r1", 224,
+                   SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+  await checkChain("secp256r1", 256,
+                   "rsa", 1016,
+                   "secp256r1", 256,
+                   MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
 }
 
-function run_test() {
-  checkRSAChains(1016, 1024);
-  checkECCChains();
-  checkCombinationChains();
-
-  run_next_test();
-}
+add_task(async function() {
+  await checkRSAChains(1016, 1024);
+  await checkECCChains();
+  await checkCombinationChains();
+});
--- a/security/manager/ssl/tests/unit/test_keysize_ev.js
+++ b/security/manager/ssl/tests/unit/test_keysize_ev.js
@@ -20,49 +20,47 @@ function getOCSPResponder(expectedCertNa
 
 function loadCert(certName, trustString) {
   let certFilename = "test_keysize_ev/" + certName + ".pem";
   addCertFromFile(certDB, certFilename, trustString);
   return constructCertFromFile(certFilename);
 }
 
 /**
- * Adds a single EV key size test.
+ * Asynchronously runs a single EV key size test.
  *
  * @param {Array} expectedNamesForOCSP
  *        An array of nicknames of the certs to be responded to.
  * @param {String} rootCertFileName
  *        The file name of the root cert. Can begin with ".." to reference
  *        certs in folders other than "test_keysize_ev/".
  * @param {Array} intCertFileNames
  *        An array of file names of any intermediate certificates.
  * @param {String} endEntityCertFileName
  *        The file name of the end entity cert.
  * @param {Boolean} expectedResult
  *        Whether the chain is expected to validate as EV.
  */
-function addKeySizeTestForEV(expectedNamesForOCSP,
-                             rootCertFileName, intCertFileNames,
-                             endEntityCertFileName, expectedResult) {
-  add_test(function() {
-    clearOCSPCache();
-    let ocspResponder = getOCSPResponder(expectedNamesForOCSP);
+async function keySizeTestForEV(expectedNamesForOCSP,
+                                rootCertFileName, intCertFileNames,
+                                endEntityCertFileName, expectedResult) {
+  clearOCSPCache();
+  let ocspResponder = getOCSPResponder(expectedNamesForOCSP);
 
-    loadCert(rootCertFileName, "CTu,CTu,CTu");
-    for (let intCertFileName of intCertFileNames) {
-      loadCert(intCertFileName, ",,");
-    }
-    checkEVStatus(
-      certDB,
-      constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`),
-      certificateUsageSSLServer,
-      expectedResult);
+  loadCert(rootCertFileName, "CTu,CTu,CTu");
+  for (let intCertFileName of intCertFileNames) {
+    loadCert(intCertFileName, ",,");
+  }
+  await checkEVStatus(
+    certDB,
+    constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`),
+    certificateUsageSSLServer,
+    expectedResult);
 
-    ocspResponder.stop(run_next_test);
-  });
+  await stopOCSPResponder(ocspResponder);
 }
 
 /**
  * For debug builds which have the test EV roots compiled in, checks RSA chains
  * which contain certs with key sizes adequate for EV are validated as such,
  * while chains that contain any cert with an inadequate key size fail EV and
  * validate as DV.
  * For opt builds which don't have the test EV roots compiled in, checks that
@@ -71,17 +69,17 @@ function addKeySizeTestForEV(expectedNam
  * Note: This function assumes that the key size requirements for EV are greater
  * than the requirements for DV.
  *
  * @param {Number} inadequateKeySize
  *        The inadequate key size of the generated certs.
  * @param {Number} adequateKeySize
  *        The adequate key size of the generated certs.
  */
-function checkRSAChains(inadequateKeySize, adequateKeySize) {
+async function checkRSAChains(inadequateKeySize, adequateKeySize) {
   // Reuse the existing test RSA EV root
   let rootOKCertFileName = "../test_ev_certs/evroot";
   let rootOKName = "evroot";
   let rootNotOKName = "ev_root_rsa_" + inadequateKeySize;
   let intOKName = "ev_int_rsa_" + adequateKeySize;
   let intNotOKName = "ev_int_rsa_" + inadequateKeySize;
   let eeOKName = "ev_ee_rsa_" + adequateKeySize;
   let eeNotOKName = "ev_ee_rsa_" + inadequateKeySize;
@@ -91,55 +89,53 @@ function checkRSAChains(inadequateKeySiz
   // will for example not be done for the "ev_int_rsa_2048-evroot" intermediate
   // in such a build.
   let intFullName = intOKName + "-" + rootOKName;
   let eeFullName = eeOKName + "-" + intOKName + "-" + rootOKName;
   let expectedNamesForOCSP = gEVExpected
                            ? [ intFullName,
                                eeFullName ]
                            : [ eeFullName ];
-  addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
-                      [ intFullName ], eeFullName, gEVExpected);
+  await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
+                         [ intFullName ], eeFullName, gEVExpected);
 
   // Chain with a root cert that has an inadequate size for EV, but
   // adequate size for DV
   intFullName = intOKName + "-" + rootNotOKName;
   eeFullName = eeOKName + "-" + intOKName + "-" + rootNotOKName;
   expectedNamesForOCSP = [ eeFullName ];
-  addKeySizeTestForEV(expectedNamesForOCSP, rootNotOKName,
-                      [ intFullName ], eeFullName, false);
+  await keySizeTestForEV(expectedNamesForOCSP, rootNotOKName,
+                         [ intFullName ], eeFullName, false);
 
   // Chain with an intermediate cert that has an inadequate size for EV, but
   // adequate size for DV
   intFullName = intNotOKName + "-" + rootOKName;
   eeFullName = eeOKName + "-" + intNotOKName + "-" + rootOKName;
   expectedNamesForOCSP = [ eeFullName ];
-  addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
-                      [ intFullName ], eeFullName, false);
+  await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
+                         [ intFullName ], eeFullName, false);
 
   // Chain with an end entity cert that has an inadequate size for EV, but
   // adequate size for DV
   intFullName = intOKName + "-" + rootOKName;
   eeFullName = eeNotOKName + "-" + intOKName + "-" + rootOKName;
   expectedNamesForOCSP = gEVExpected
                        ? [ intFullName,
                            eeFullName ]
                        : [ eeFullName ];
-  addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
-                      [ intFullName ], eeFullName, false);
+  await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
+                         [ intFullName ], eeFullName, false);
 }
 
-function run_test() {
+add_task(async function() {
   Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
   Services.prefs.setIntPref("security.OCSP.enabled", 1);
 
   let smallKeyEVRoot =
     constructCertFromFile("test_keysize_ev/ev_root_rsa_2040.pem");
   equal(smallKeyEVRoot.sha256Fingerprint,
         "40:AB:5D:A5:89:15:A9:4B:82:87:B8:A6:9A:84:B1:DB:" +
         "7A:9D:DB:B8:4E:E1:23:E3:C6:64:E7:50:DC:35:8C:68",
         "test sanity check: the small-key EV root must have the same " +
         "fingerprint as the corresponding entry in ExtendedValidation.cpp");
 
-  checkRSAChains(2040, 2048);
-
-  run_next_test();
-}
+  await checkRSAChains(2040, 2048);
+});
--- a/security/manager/ssl/tests/unit/test_name_constraints.js
+++ b/security/manager/ssl/tests/unit/test_name_constraints.js
@@ -33,31 +33,31 @@ function certFromFile(name) {
 }
 
 function loadCertWithTrust(certName, trustString) {
   addCertFromFile(certdb, `test_name_constraints/${certName}.pem`,
                   trustString);
 }
 
 function checkCertNotInNameSpace(cert) {
-  checkCertErrorGeneric(certdb, cert, SEC_ERROR_CERT_NOT_IN_NAME_SPACE,
-                        certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, SEC_ERROR_CERT_NOT_IN_NAME_SPACE,
+                               certificateUsageSSLServer);
 }
 
 function checkCertInNameSpace(cert) {
-  checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
-                        certificateUsageSSLServer);
+  return checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
+                               certificateUsageSSLServer);
 }
 
-function run_test() {
+add_task(async function() {
   // Test that name constraints from the entire certificate chain are enforced.
   loadCertWithTrust("ca-example-com-permitted", "CTu,,");
   loadCertWithTrust("int-example-org-permitted", ",,");
-  checkCertNotInNameSpace(certFromFile("ee-example-com-and-org"));
-  checkCertNotInNameSpace(certFromFile("ee-example-com"));
-  checkCertNotInNameSpace(certFromFile("ee-example-org"));
-  checkCertNotInNameSpace(certFromFile("ee-example-test"));
+  await checkCertNotInNameSpace(certFromFile("ee-example-com-and-org"));
+  await checkCertNotInNameSpace(certFromFile("ee-example-com"));
+  await checkCertNotInNameSpace(certFromFile("ee-example-org"));
+  await checkCertNotInNameSpace(certFromFile("ee-example-test"));
 
   // Test that externally-imposed name constraints are enforced (DCISS tests).
   loadCertWithTrust("dciss", "CTu,,");
-  checkCertInNameSpace(certFromFile("NameConstraints.dcissallowed"));
-  checkCertNotInNameSpace(certFromFile("NameConstraints.dcissblocked"));
-}
+  await checkCertInNameSpace(certFromFile("NameConstraints.dcissallowed"));
+  await checkCertNotInNameSpace(certFromFile("NameConstraints.dcissblocked"));
+});
--- a/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js
@@ -25,117 +25,94 @@ function getFailingOCSPResponder() {
 }
 
 function getOCSPResponder(expectedCertNames) {
   return startOCSPResponder(SERVER_PORT, "www.example.com", "test_ev_certs",
                             expectedCertNames, []);
 }
 
 // Tests that in ocspOff mode, OCSP fetches are never done.
-function testOff() {
-  add_test(() => {
-    Services.prefs.setIntPref("security.OCSP.enabled", 0);
-    info("Setting security.OCSP.enabled to 0");
-    run_next_test();
-  });
+async function testOff() {
+  Services.prefs.setIntPref("security.OCSP.enabled", 0);
+  info("Setting security.OCSP.enabled to 0");
 
   // EV chains should verify successfully but never get EV status.
-  add_test(() => {
-    clearOCSPCache();
-    let ocspResponder = getFailingOCSPResponder();
-    checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer,
-                  false);
-    ocspResponder.stop(run_next_test);
-  });
+  clearOCSPCache();
+  let ocspResponder = getFailingOCSPResponder();
+  await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"),
+                      certificateUsageSSLServer, false);
+  await stopOCSPResponder(ocspResponder);
 
   // A DV chain should verify successfully.
-  add_test(() => {
-    clearOCSPCache();
-    let ocspResponder = getFailingOCSPResponder();
-    checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
-                          PRErrorCodeSuccess, certificateUsageSSLServer);
-    ocspResponder.stop(run_next_test);
-  });
+  clearOCSPCache();
+  ocspResponder = getFailingOCSPResponder();
+  await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
+                              PRErrorCodeSuccess, certificateUsageSSLServer);
+  await stopOCSPResponder(ocspResponder);
 }
 
 // Tests that in ocspOn mode, OCSP fetches are done for both EV and DV certs.
-function testOn() {
-  add_test(() => {
-    Services.prefs.setIntPref("security.OCSP.enabled", 1);
-    info("Setting security.OCSP.enabled to 1");
-    run_next_test();
-  });
+async function testOn() {
+  Services.prefs.setIntPref("security.OCSP.enabled", 1);
+  info("Setting security.OCSP.enabled to 1");
 
   // If a successful OCSP response is fetched, then an EV chain should verify
   // successfully and get EV status as well.
-  add_test(() => {
-    clearOCSPCache();
-    let ocspResponder =
+  clearOCSPCache();
+  let ocspResponder =
       getOCSPResponder(gEVExpected ? ["test-oid-path-int", "test-oid-path-ee"]
                                    : ["test-oid-path-ee"]);
-    checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer,
-                  gEVExpected);
-    ocspResponder.stop(run_next_test);
-  });
+  await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"),
+                      certificateUsageSSLServer, gEVExpected);
+  await stopOCSPResponder(ocspResponder);
 
   // If a successful OCSP response is fetched, then a DV chain should verify
   // successfully.
-  add_test(() => {
-    clearOCSPCache();
-    let ocspResponder = getOCSPResponder(["non-ev-root-path-ee"]);
-    checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
-                          PRErrorCodeSuccess, certificateUsageSSLServer);
-    ocspResponder.stop(run_next_test);
-  });
+  clearOCSPCache();
+  ocspResponder = getOCSPResponder(["non-ev-root-path-ee"]);
+  await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),