Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Wed, 29 Aug 2018 00:58:21 +0300
changeset 433636 3205543f957cd2a6905486d73aa897535fdd9825
parent 433541 9494c03553b9b968194c78602fb75273d39d9ede (current diff)
parent 433635 211b070bac735ff9301f80af489a045a7f644b60 (diff)
child 433637 a33ef251cb467a34aad71b0d94a4289addc9590f
child 433654 644e800d1d8aa4bf2a4cc560132fc290539c5bea
child 433698 3c3eda8b2ee5d4349d36fdb698b0367a5c6e1741
push id34518
push useraciure@mozilla.com
push dateTue, 28 Aug 2018 21:58:56 +0000
treeherdermozilla-central@3205543f957c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
3205543f957c / 63.0a1 / 20180828220157 / files
nightly linux64
3205543f957c / 63.0a1 / 20180828220157 / files
nightly mac
3205543f957c / 63.0a1 / 20180828220157 / files
nightly win32
3205543f957c / 63.0a1 / 20180828220157 / files
nightly win64
3205543f957c / 63.0a1 / 20180828220157 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
browser/app/profile/firefox.js
devtools/client/inspector/flexbox/components/FlexContainerItem.js
devtools/client/inspector/flexbox/components/FlexContainerList.js
devtools/client/preferences/devtools-client.js
dom/base/CustomElementRegistry.cpp
dom/base/CustomElementRegistry.h
dom/base/FragmentOrElement.cpp
dom/base/FragmentOrElement.h
dom/base/nsDocument.cpp
dom/base/nsIContent.h
gfx/src/nsIScriptableRegion.idl
gfx/src/nsScriptableRegion.cpp
gfx/src/nsScriptableRegion.h
gfx/tests/unit/.eslintrc.js
gfx/tests/unit/test_nsIScriptableRegion.js
gfx/tests/unit/xpcshell.ini
js/src/jit/arm64/AtomicOperations-arm64.h
modules/libpref/init/StaticPrefList.h
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/webdriver/tests/element_send_keys/user_prompts.py.ini
toolkit/components/antitracking/test/browser/browser_imageCache.js
new file mode 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1482,17 +1482,16 @@ pref("toolkit.telemetry.hybridContent.en
 pref("browser.ping-centre.telemetry", true);
 pref("browser.ping-centre.log", false);
 pref("browser.ping-centre.staging.endpoint", "https://onyx_tiles.stage.mozaws.net/v3/links/ping-centre");
 pref("browser.ping-centre.production.endpoint", "https://tiles.services.mozilla.com/v3/links/ping-centre");
 
 // Enable GMP support in the addon manager.
 pref("media.gmp-provider.enabled", true);
 
-pref("browser.contentblocking.enabled", true);
 pref("browser.contentblocking.cookies-site-data.ui.reject-trackers.recommended", true);
 pref("browser.contentblocking.fastblock.control-center.ui.enabled", true);
 pref("browser.contentblocking.trackingprotection.control-center.ui.enabled", true);
 #ifdef NIGHTLY_BUILD
 pref("browser.contentblocking.ui.enabled", true);
 pref("browser.contentblocking.cookies-site-data.ui.reject-trackers.enabled", true);
 pref("browser.contentblocking.rejecttrackers.control-center.ui.enabled", true);
 #else
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -390,17 +390,17 @@ var gPluginHandler = {
   infobarBlockedForURI(uri) {
     return new Promise((resolve, reject) => {
       let tableName = Services.prefs.getStringPref("urlclassifier.flashInfobarTable", "");
       if (!tableName) {
         resolve(false);
       }
       let classifier = Cc["@mozilla.org/url-classifier/dbservice;1"]
         .getService(Ci.nsIURIClassifier);
-      classifier.asyncClassifyLocalWithTables(uri, tableName, (c, list) => {
+      classifier.asyncClassifyLocalWithTables(uri, tableName, [], [], (c, list) => {
         resolve(list.length > 0);
       });
     });
   },
 
   async updateHiddenPluginUI(browser, haveInsecure, actions,
                                  principal, location) {
     let origin = principal.originNoSuffix;
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -43,17 +43,17 @@ support-files =
 [browser_new_file_whitelisted_http_tab.js]
 skip-if = !e10s # Test only relevant for e10s.
 [browser_new_tab_insert_position.js]
 skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing
 support-files = file_new_tab_page.html
 [browser_new_tab_in_privileged_process_pref.js]
 skip-if = !e10s # Pref and test only relevant for e10s.
 [browser_new_web_tab_in_file_process_pref.js]
-skip-if = !e10s # Pref and test only relevant for e10s.
+skip-if = !e10s || (os == 'mac' && debug) # Pref and test only relevant for e10s. #Bug 1366137
 [browser_newwindow_tabstrip_overflow.js]
 [browser_open_newtab_start_observer_notification.js]
 [browser_opened_file_tab_navigated_to_web.js]
 skip-if = (os == 'mac' && debug) || (os == 'linux' && debug) # Bug 1356347
 [browser_overflowScroll.js]
 [browser_pinnedTabs_clickOpen.js]
 [browser_pinnedTabs_closeByKeyboard.js]
 [browser_pinnedTabs.js]
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -23,27 +23,27 @@ file, You can obtain one at http://mozil
 
   <binding id="urlbar" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
 
     <content sizetopopup="pref">
       <xul:hbox flex="1" class="urlbar-textbox-container">
         <children includes="image|deck|stack|box"/>
         <xul:moz-input-box anonid="moz-input-box"
                   class="urlbar-input-box"
-                  flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
+                  flex="1">
           <children/>
           <html:input anonid="scheme"
                       class="urlbar-scheme textbox-input"
                       required="required"
                       xbl:inherits="textoverflow,focused"/>
           <html:input anonid="input"
                       class="autocomplete-textbox urlbar-input textbox-input"
                       allowevents="true"
                       inputmode="mozAwesomebar"
-                      xbl:inherits="tooltiptext=inputtooltiptext,value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
+                      xbl:inherits="value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
         </xul:moz-input-box>
         <xul:image anonid="urlbar-go-button"
                    class="urlbar-go-button urlbar-icon"
                    onclick="gURLBar.handleCommand(event);"
                    tooltiptext="&goEndCap.tooltip;"
                    xbl:inherits="pageproxystate,parentfocused=focused,usertyping"/>
         <xul:dropmarker anonid="historydropmarker"
                         class="urlbar-history-dropmarker urlbar-icon chromeclass-toolbar-additional"
@@ -1053,23 +1053,27 @@ file, You can obtain one at http://mozil
           this.popup.overrideValue = "http://www." + url;
         ]]></body>
       </method>
 
       <method name="_initURLTooltip">
         <body><![CDATA[
           if (this.focused || !this.hasAttribute("textoverflow"))
             return;
-          this.inputField.setAttribute("tooltiptext", this.value);
+          // We set the tooltip text on the parent node instead of the input
+          // field because XUL tooltips only work on XUL elements.
+          //
+          // FIXME(bug 1486716): title should work on chrome documents instead.
+          this.inputField.parentNode.setAttribute("tooltiptext", this.value);
         ]]></body>
       </method>
 
       <method name="_hideURLTooltip">
         <body><![CDATA[
-          this.inputField.removeAttribute("tooltiptext");
+          this.inputField.parentNode.removeAttribute("tooltiptext");
         ]]></body>
       </method>
 
       <!-- Returns:
            null if there's a security issue and we should do nothing.
            a URL object if there is one that we're OK with loading,
            a text value otherwise.
            -->
--- a/browser/components/payments/test/browser/head.js
+++ b/browser/components/payments/test/browser/head.js
@@ -338,16 +338,20 @@ add_task(async function setup_head() {
     if (msg.category == "CSP_CSPViolationWithURI" && msg.errorMessage.includes("at inline")) {
       // Ignore unknown CSP error.
       return;
     }
     if (msg.message && msg.message.match(/docShell is null.*BrowserUtils.jsm/)) {
       // Bug 1478142 - Console spam from the Find Toolbar.
       return;
     }
+    if (msg.errorMessage == "AbortError: The operation was aborted. " &&
+        msg.sourceName == "" && msg.lineNumber == 0) {
+      return;
+    }
     ok(false, msg.message || msg.errorMessage);
   });
   await setupFormAutofillStorage();
   registerCleanupFunction(function cleanup() {
     paymentSrv.cleanup();
     cleanupFormAutofillStorage();
     Services.prefs.clearUserPref(RESPONSE_TIMEOUT_PREF);
     Services.prefs.clearUserPref(SAVE_CREDITCARD_DEFAULT_PREF);
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -190,18 +190,18 @@
           <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
           <hbox>
             <menulist id="blockCookiesMenu" preference="network.cookie.cookieBehavior"
                       onsyncfrompreference="return gPrivacyPane.readBlockCookiesFrom();"
                       onsynctopreference="return gPrivacyPane.writeBlockCookiesFrom();">
               <menupopup>
                 <menuitem id="blockCookiesFromTrackers" data-l10n-id="sitedata-block-trackers-option" value="trackers"/>
                 <menuitem data-l10n-id="sitedata-block-unvisited-option" value="unvisited"/>
-                <menuitem data-l10n-id="sitedata-block-all-third-parties-option" value="all-third-parties"/>
-                <menuitem data-l10n-id="sitedata-block-always-option" value="always"/>
+                <menuitem data-l10n-id="sitedata-block-all-third-party-option" value="all-third-parties"/>
+                <menuitem data-l10n-id="sitedata-block-all-option" value="always"/>
               </menupopup>
             </menulist>
           </hbox>
         </hbox>
         <hbox id="keepRow"
               align="center">
           <label id="keepUntil"
                  control="keepCookiesUntil"
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -750,25 +750,25 @@ sitedata-disallow-cookies-option =
     .accesskey = B
 
 # This label means 'type of content that is blocked', and is followed by a drop-down list with content types below.
 # The list items are the strings named sitedata-block-*-option*.
 sitedata-block-desc = Type blocked
     .accesskey = T
 
 sitedata-block-trackers-option-recommended =
-    .label = Third party trackers (recommended)
+    .label = Third-party trackers (recommended)
 sitedata-block-trackers-option =
-    .label = Third party trackers
+    .label = Third-party trackers
 sitedata-block-unvisited-option =
     .label = Cookies from unvisited websites
-sitedata-block-all-third-parties-option =
-    .label = All third-party cookies
-sitedata-block-always-option =
-    .label = All cookies (may cause websites to break)
+sitedata-block-all-third-party-option =
+    .label = All third-party cookies (may cause websites to break)
+sitedata-block-all-option =
+    .label = All cookies (will cause websites to break)
 
 sitedata-clear =
     .label = Clear Data…
     .accesskey = l
 
 sitedata-settings =
     .label = Manage Data…
     .accesskey = M
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -677,18 +677,20 @@ var SitePermissions = {
         return gStringBundle.GetStringFromName("state.current.prompt");
       case this.ALLOW:
         if (scope && scope != this.SCOPE_PERSISTENT && scope != this.SCOPE_POLICY)
           return gStringBundle.GetStringFromName("state.current.allowedTemporarily");
         return gStringBundle.GetStringFromName("state.current.allowed");
       case this.ALLOW_COOKIES_FOR_SESSION:
         return gStringBundle.GetStringFromName("state.current.allowedForSession");
       case this.BLOCK:
-        if (scope && scope != this.SCOPE_PERSISTENT && scope != this.SCOPE_POLICY)
+        if (scope && scope != this.SCOPE_PERSISTENT && scope != this.SCOPE_POLICY &&
+            scope != this.SCOPE_GLOBAL) {
           return gStringBundle.GetStringFromName("state.current.blockedTemporarily");
+        }
         return gStringBundle.GetStringFromName("state.current.blocked");
       default:
         return null;
     }
   },
 };
 
 var gPermissionObject = {
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -56,16 +56,17 @@
   skin/classic/browser/identity-icon.svg                       (../shared/identity-block/identity-icon.svg)
   skin/classic/browser/identity-icon-notice.svg                (../shared/identity-block/identity-icon-notice.svg)
   skin/classic/browser/info.svg                                (../shared/info.svg)
   skin/classic/browser/searchReset.css                         (../shared/searchReset.css)
 
   skin/classic/browser/illustrations/error-session-restore.svg (../shared/illustrations/error-session-restore.svg)
 
   skin/classic/browser/notification-icons/autoplay-media.svg                (../shared/notification-icons/autoplay-media.svg)
+  skin/classic/browser/notification-icons/autoplay-media-detailed.svg       (../shared/notification-icons/autoplay-media-detailed.svg)
   skin/classic/browser/notification-icons/autoplay-media-blocked.svg        (../shared/notification-icons/autoplay-media-blocked.svg)
   skin/classic/browser/notification-icons/camera-blocked.svg                (../shared/notification-icons/camera-blocked.svg)
   skin/classic/browser/notification-icons/camera.svg                        (../shared/notification-icons/camera.svg)
   skin/classic/browser/notification-icons/canvas-blocked.svg                (../shared/notification-icons/canvas-blocked.svg)
   skin/classic/browser/notification-icons/canvas.svg                        (../shared/notification-icons/canvas.svg)
   skin/classic/browser/notification-icons/default-info.svg                  (../shared/notification-icons/default-info.svg)
   skin/classic/browser/notification-icons/desktop-notification-blocked.svg  (../shared/notification-icons/desktop-notification-blocked.svg)
   skin/classic/browser/notification-icons/desktop-notification.svg          (../shared/notification-icons/desktop-notification.svg)
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -52,29 +52,32 @@
 .geo-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/geo.svg);
 }
 
 .geo-icon.blocked-permission-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/geo-blocked.svg);
 }
 
-.popup-notification-icon[popupid="autoplay-media"],
+.popup-notification-icon[popupid="geolocation"] {
+  list-style-image: url(chrome://browser/skin/notification-icons/geo-detailed.svg);
+}
+
 .autoplay-media-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media.svg);
 }
 
+.popup-notification-icon[popupid="autoplay-media"] {
+  list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media-detailed.svg);
+}
+
 .autoplay-media-icon.blocked-permission-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/autoplay-media-blocked.svg);
 }
 
-.popup-notification-icon[popupid="geolocation"] {
-  list-style-image: url(chrome://browser/skin/notification-icons/geo-detailed.svg);
-}
-
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .indexedDB-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/indexedDB.svg);
 }
 
 .login-icon {
   list-style-image: url(chrome://browser/skin/notification-icons/login.svg);
 }
--- a/browser/themes/shared/notification-icons/autoplay-media-blocked.svg
+++ b/browser/themes/shared/notification-icons/autoplay-media-blocked.svg
@@ -1,7 +1,8 @@
 <!-- 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" fill="context-fill" fill-opacity="context-fill-opacity">
-  <path d="M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm0 1c.62 0 1.23.2 1.73.56l-4.17 4.17A3 3 0 0 1 12 9zm0 6c-.62 0-1.23-.2-1.73-.56l4.17-4.17A3 3 0 0 1 12 15zm-1.77-7.68a5.02 5.02 0 0 0-2.88 2.83l-1.53.79a.6.6 0 0 1-.55 0 .48.48 0 0 1-.27-.42V5.48c0-.17.1-.33.27-.42a.6.6 0 0 1 .55 0l4.4 2.26z"/>
-  <path d="M13.61 5.7a1 1 0 0 1-1.89.65 5 5 0 1 0-5.54 6.58 1 1 0 1 1-.33 1.98 7 7 0 1 1 7.76-9.22z"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
+  <path d="M14.944 4.056l-1.478 1.478a5.989 5.989 0 0 1-7.93 7.93l-1.485 1.485A7.981 7.981 0 0 0 14.944 4.056z"/>
+  <path d="M11.974 7.026l-4.608 4.608 4.8-2.771a1 1 0 0 0 0-1.726z"/>
+  <path d="M14.707 1.293a1 1 0 0 0-1.414 0l-.4.4A7.8 7.8 0 0 0 10.98.574a1 1 0 0 0-.746 1.856 5.767 5.767 0 0 1 1.234.688L9.175 5.411 6.494 3.863A1 1 0 0 0 5 4.726v4.86l-1.885 1.885A5.919 5.919 0 0 1 3 4.721V6a.5.5 0 0 0 1 0V2.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0 0 1h1.262a7.963 7.963 0 0 0-.074 9.9l-.395.395a1 1 0 1 0 1.414 1.414l12-12a1 1 0 0 0 0-1.416z"/>
 </svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/notification-icons/autoplay-media-detailed.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="32" height="32" viewBox="0 0 32 32" fill="context-fill" fill-opacity="context-fill-opacity">
+  <path d="M21.954 1.185a1.5 1.5 0 0 0-1.117 2.784A12.961 12.961 0 1 1 5 9.207V10.5a1.5 1.5 0 0 0 3 0v-6A1.5 1.5 0 0 0 6.5 3h-5a1.5 1.5 0 0 0 0 3h2.1a15.934 15.934 0 1 0 18.354-4.815z"/>
+  <path d="M13 24.245l11.325-6.538a1.99 1.99 0 0 0 0-3.446L13 7.723a1.989 1.989 0 0 0-2.984 1.723v13.076A1.989 1.989 0 0 0 13 24.245z"/>
+</svg>
--- a/browser/themes/shared/notification-icons/autoplay-media.svg
+++ b/browser/themes/shared/notification-icons/autoplay-media.svg
@@ -1,7 +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" fill="context-fill" fill-opacity="context-fill-opacity">
-  <path d="M8 2a6 6 0 1 0 6 6 6.007 6.007 0 0 0-6-6zm0 11a5 5 0 1 1 5-5 5.006 5.006 0 0 1-5 5z"></path>
-  <path d="M6.75 4.969A.5.5 0 0 0 6 5.4v5.2a.5.5 0 0 0 .75.433l4.5-2.6a.5.5 0 0 0 0-.866z"></path>
+  <path d="M10.98.574a1 1 0 0 0-.746 1.856A6.034 6.034 0 1 1 3 4.721V6a.5.5 0 0 0 1 0V2.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0 0 1h1.262A8 8 0 1 0 10.98.574z"/>
+  <path d="M6.494 12.137l5.672-3.274a1 1 0 0 0 0-1.726L6.494 3.863A1 1 0 0 0 5 4.726v6.548a1 1 0 0 0 1.494.863z"/>
 </svg>
--- a/config/external/icu/defs.mozbuild
+++ b/config/external/icu/defs.mozbuild
@@ -25,17 +25,20 @@ if not CONFIG['HAVE_LANGINFO_CODESET']:
 
 if CONFIG['MOZ_DEBUG']:
     DEFINES['U_DEBUG'] = 1
 
 # ICU requires RTTI
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-frtti']
 elif CONFIG['OS_TARGET'] == 'WINNT':
-    CXXFLAGS += ['-GR']
+    # Remove the -GR- flag so we don't get a bunch of warning spam.
+    COMPILE_FLAGS['OS_CXXFLAGS'] = [
+        f for f in COMPILE_FLAGS['OS_CXXFLAGS'] if f != '-GR-'
+    ] + ['-GR']
 
 DisableStlWrapping()
 AllowCompilerWarnings()
 
 # We allow compiler warnings, but we can at least cut down on spammy
 # warnings that get triggered for every file.
 if CONFIG['CC_TYPE'] == 'clang-cl':
     CFLAGS += [
--- a/db/sqlite3/src/moz.build
+++ b/db/sqlite3/src/moz.build
@@ -93,14 +93,19 @@ elif CONFIG['HAVE_64BIT_BUILD']:
     # On 64bit platforms default to a MEMORY temp store for performance.
     DEFINES['SQLITE_TEMP_STORE'] = 2
 
 # Change the default temp files prefix, to easily distinguish files we created
 # vs files created by other Sqlite instances in the system.
 # This has obviously no effect in case of System Sqlite.
 DEFINES['SQLITE_TEMP_FILE_PREFIX'] = '"mz_etilqs_"'
 
+# Our copy of sqlite3 doesn't know about AArch64 + Windows's endianness yet,
+# help it out.  (This does non-Windows too, but that's OK.)
+if CONFIG['CPU_ARCH'] == 'aarch64':
+    DEFINES['SQLITE_BYTEORDER'] = 1234
+
 # Suppress warnings in third-party code.
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CFLAGS += [
         '-Wno-sign-compare',
         '-Wno-type-limits',
     ]
rename from devtools/client/inspector/flexbox/components/FlexContainerItem.js
rename to devtools/client/inspector/flexbox/components/FlexContainer.js
--- a/devtools/client/inspector/flexbox/components/FlexContainerItem.js
+++ b/devtools/client/inspector/flexbox/components/FlexContainer.js
@@ -12,17 +12,17 @@ const { translateNodeFrontToGrip } = req
 
 // Reps
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 const ElementNode = REPS.ElementNode;
 
 const Types = require("../types");
 
-class FlexContainerItem extends PureComponent {
+class FlexContainer extends PureComponent {
   static get propTypes() {
     return {
       flexbox: PropTypes.shape(Types.flexbox).isRequired,
       getSwatchColorPickerTooltip: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       onToggleFlexboxHighlighter: PropTypes.func.isRequired,
@@ -98,31 +98,30 @@ class FlexContainerItem extends PureComp
 
   render() {
     const {
       flexbox,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
     } = this.props;
     const {
-      actorID,
       color,
       highlighted,
       nodeFront,
     } = flexbox;
 
     return (
-      dom.li({},
+      dom.div({ className: "flex-container devtools-monospace" },
         dom.label({},
           dom.input(
             {
-              type: "checkbox",
-              value: actorID,
+              className: "devtools-checkbox-toggle",
               checked: highlighted,
               onChange: this.onFlexboxCheckboxClick,
+              type: "checkbox",
             }
           ),
           Rep(
             {
               defaultRep: ElementNode,
               mode: MODE.TINY,
               object: translateNodeFrontToGrip(nodeFront),
               onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
@@ -145,9 +144,9 @@ class FlexContainerItem extends PureComp
         // Ideally we should modify the SwatchColorPickerTooltip to bypass this
         // requirement. See https://bugzilla.mozilla.org/show_bug.cgi?id=1341578
         dom.span({ className: "flexbox-color-value" }, color)
       )
     );
   }
 }
 
-module.exports = FlexContainerItem;
+module.exports = FlexContainer;
deleted file mode 100644
--- a/devtools/client/inspector/flexbox/components/FlexContainerList.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { createFactory, PureComponent } = 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 { getStr } = require("devtools/client/inspector/layout/utils/l10n");
-
-const FlexContainerItem = createFactory(require("./FlexContainerItem"));
-
-const Types = require("../types");
-
-class FlexContainerList extends PureComponent {
-  static get propTypes() {
-    return {
-      flexbox: PropTypes.shape(Types.flexbox).isRequired,
-      getSwatchColorPickerTooltip: PropTypes.func.isRequired,
-      onHideBoxModelHighlighter: PropTypes.func.isRequired,
-      onSetFlexboxOverlayColor: PropTypes.func.isRequired,
-      onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
-      onToggleFlexboxHighlighter: PropTypes.func.isRequired,
-      setSelectedNode: PropTypes.func.isRequired,
-    };
-  }
-
-  render() {
-    const {
-      flexbox,
-      getSwatchColorPickerTooltip,
-      onHideBoxModelHighlighter,
-      onSetFlexboxOverlayColor,
-      onShowBoxModelHighlighterForNode,
-      onToggleFlexboxHighlighter,
-      setSelectedNode,
-    } = this.props;
-
-    return (
-      dom.div({ className: "flexbox-container" },
-        dom.span({}, getStr("flexbox.overlayFlexbox")),
-        dom.ul(
-          {
-            id: "flexbox-list",
-            className: "devtools-monospace",
-          },
-          FlexContainerItem({
-            key: flexbox.id,
-            flexbox,
-            getSwatchColorPickerTooltip,
-            onHideBoxModelHighlighter,
-            onSetFlexboxOverlayColor,
-            onShowBoxModelHighlighterForNode,
-            onToggleFlexboxHighlighter,
-            setSelectedNode,
-          })
-        )
-      )
-    );
-  }
-}
-
-module.exports = FlexContainerList;
--- a/devtools/client/inspector/flexbox/components/FlexContainerProperties.js
+++ b/devtools/client/inspector/flexbox/components/FlexContainerProperties.js
@@ -13,64 +13,31 @@ const ComputedProperty = createFactory(r
 
 class FlexContainerProperties extends PureComponent {
   static get propTypes() {
     return {
       properties: PropTypes.object.isRequired,
     };
   }
 
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      // Whether or not the properties are shown.
-      isShown: true,
-    };
-
-    this.onToggleExpander = this.onToggleExpander.bind(this);
-  }
-
-  onToggleExpander(event) {
-    event.stopPropagation();
-
-    this.setState((prevState) => {
-      return {
-        isShown: !prevState.isShown,
-      };
-    });
-  }
-
   render() {
     const { properties } =  this.props;
 
     return (
       dom.div(
         {
           id: "flex-container-properties",
           className: "flexbox-container",
         },
-        dom.div(
-          {
-            className: "layout-properties-header",
-            onDoubleClick: this.onToggleExpander,
-          },
-          dom.span(
-            {
-              className: "layout-properties-expander theme-twisty",
-              open: this.state.isShown,
-              onClick: this.onToggleExpander,
-            }
-          ),
+        dom.div({ className: "layout-properties-header" },
           getStr("flexbox.flexContainerProperties")
         ),
         dom.div(
           {
             className: "layout-properties-wrapper devtools-monospace",
-            hidden: !this.state.isShown,
             tabIndex: 0,
           },
           Object.entries(properties).map(([name, value]) => ComputedProperty({
             key: name,
             name,
             value,
           }))
         )
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/flexbox/components/FlexItem.js
@@ -0,0 +1,42 @@
+/* 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";
+
+const { PureComponent } = 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 { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
+
+// Reps
+const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
+const { Rep } = REPS;
+const ElementNode = REPS.ElementNode;
+
+const Types = require("../types");
+
+class FlexItem extends PureComponent {
+  static get propTypes() {
+    return {
+      flexItem: PropTypes.shape(Types.flexItem).isRequired,
+    };
+  }
+
+  render() {
+    const { flexItem } = this.props;
+    const { nodeFront } = flexItem;
+
+    return (
+      dom.li({},
+        Rep({
+          defaultRep: ElementNode,
+          mode: MODE.TINY,
+          object: translateNodeFrontToGrip(nodeFront)
+        })
+      )
+    );
+  }
+}
+
+module.exports = FlexItem;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/flexbox/components/FlexItemList.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = 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 FlexItem = createFactory(require(("./FlexItem")));
+
+const Types = require("../types");
+
+class FlexItemList extends PureComponent {
+  static get propTypes() {
+    return {
+      flexItems: PropTypes.arrayOf(PropTypes.shape(Types.flexItem)).isRequired,
+    };
+  }
+
+  render() {
+    const { flexItems } = this.props;
+
+    return (
+      dom.ol(
+        { id: "flex-item-list" },
+        flexItems.map(flexItem => FlexItem({
+          key: flexItem.actorID,
+          flexItem,
+        }))
+      )
+    );
+  }
+}
+
+module.exports = FlexItemList;
--- a/devtools/client/inspector/flexbox/components/Flexbox.js
+++ b/devtools/client/inspector/flexbox/components/Flexbox.js
@@ -4,38 +4,57 @@
 
 "use strict";
 
 const { createFactory, PureComponent } = 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 { getStr } = require("devtools/client/inspector/layout/utils/l10n");
 
-loader.lazyGetter(this, "FlexContainerList", function() {
-  return createFactory(require("./FlexContainerList"));
+loader.lazyGetter(this, "FlexContainer", function() {
+  return createFactory(require("./FlexContainer"));
 });
 loader.lazyGetter(this, "FlexContainerProperties", function() {
   return createFactory(require("./FlexContainerProperties"));
 });
+loader.lazyGetter(this, "FlexItemList", function() {
+  return createFactory(require("./FlexItemList"));
+});
 
 const Types = require("../types");
 
 class Flexbox extends PureComponent {
   static get propTypes() {
     return {
       flexbox: PropTypes.shape(Types.flexbox).isRequired,
       getSwatchColorPickerTooltip: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       onToggleFlexboxHighlighter: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
+  renderFlexItemList() {
+    const { flexbox } = this.props;
+    const {
+      flexItems,
+      highlighted,
+    } = flexbox;
+
+    if (!highlighted || !flexItems.length) {
+      return null;
+    }
+
+    return FlexItemList({
+      flexItems,
+    });
+  }
+
   render() {
     const {
       flexbox,
       getSwatchColorPickerTooltip,
       onHideBoxModelHighlighter,
       onSetFlexboxOverlayColor,
       onShowBoxModelHighlighterForNode,
       onToggleFlexboxHighlighter,
@@ -47,27 +66,26 @@ class Flexbox extends PureComponent {
         dom.div({ className: "devtools-sidepanel-no-result" },
           getStr("flexbox.noFlexboxeOnThisPage")
         )
       );
     }
 
     return (
       dom.div({ id: "layout-flexbox-container" },
-        dom.div({ className: "flexbox-content" },
-          FlexContainerList({
-            flexbox,
-            getSwatchColorPickerTooltip,
-            onHideBoxModelHighlighter,
-            onSetFlexboxOverlayColor,
-            onShowBoxModelHighlighterForNode,
-            onToggleFlexboxHighlighter,
-            setSelectedNode,
-          })
-        ),
+        FlexContainer({
+          flexbox,
+          getSwatchColorPickerTooltip,
+          onHideBoxModelHighlighter,
+          onSetFlexboxOverlayColor,
+          onShowBoxModelHighlighterForNode,
+          onToggleFlexboxHighlighter,
+          setSelectedNode,
+        }),
+        this.renderFlexItemList(),
         FlexContainerProperties({
           properties: flexbox.properties,
         })
       )
     );
   }
 }
 
--- a/devtools/client/inspector/flexbox/components/moz.build
+++ b/devtools/client/inspector/flexbox/components/moz.build
@@ -1,12 +1,13 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'Flexbox.js',
-    'FlexContainerItem.js',
-    'FlexContainerList.js',
+    'FlexContainer.js',
     'FlexContainerProperties.js',
+    'FlexItem.js',
+    'FlexItemList.js',
 )
--- a/devtools/client/inspector/flexbox/flexbox.js
+++ b/devtools/client/inspector/flexbox/flexbox.js
@@ -310,45 +310,72 @@ class FlexboxInspector {
 
     // Clear the flexbox panel if there is no flex container for the current node
     // selection.
     if (!flexboxFront) {
       this.store.dispatch(clearFlexbox());
       return;
     }
 
-    let nodeFront = flexboxFront.containerNodeFront;
+    let containerNodeFront = flexboxFront.containerNodeFront;
 
     // If the FlexboxFront doesn't yet have access to the NodeFront for its container,
     // then get it from the walker. This happens when the walker hasn't seen this
     // particular DOM Node in the tree yet or when we are connected to an older server.
-    if (!nodeFront) {
+    if (!containerNodeFront) {
       try {
-        nodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
+        containerNodeFront = await this.walker.getNodeFromActor(flexboxFront.actorID,
           ["containerEl"]);
       } catch (e) {
         // This call might fail if called asynchrously after the toolbox is finished
         // closing.
         return;
       }
     }
 
     const highlighted = this._highlighters &&
-      nodeFront == this.highlighters.flexboxHighlighterShown;
+      containerNodeFront == this.highlighters.flexboxHighlighterShown;
+
+    // Fetch the flex items for the given flex container and the flex item NodeFronts.
+    const flexItems = [];
+    const flexItemFronts = await flexboxFront.getFlexItems();
+
+    for (const flexItemFront of flexItemFronts) {
+      let itemNodeFront = flexItemFront.nodeFront;
+
+      if (!itemNodeFront) {
+        try {
+          itemNodeFront = await this.walker.getNodeFromActor(flexItemFront.actorID,
+            ["element"]);
+        } catch (e) {
+          // This call might fail if called asynchrously after the toolbox is finished
+          // closing.
+          return;
+        }
+      }
+
+      flexItems.push({
+        actorID: flexItemFront.actorID,
+        flexItemSizing: flexItemFront.flexItemSizing,
+        nodeFront: itemNodeFront,
+        properties: flexItemFront.properties,
+      });
+    }
 
     const currentUrl = this.inspector.target.url;
     // Get the hostname, if there is no hostname, fall back on protocol
     // ex: `data:` uri, and `about:` pages
     const hostname = parseURL(currentUrl).hostname || parseURL(currentUrl).protocol;
     const customColors = await this.getCustomFlexboxColors();
     const color = customColors[hostname] ? customColors[hostname] : FLEXBOX_COLOR;
 
     this.store.dispatch(updateFlexbox({
       actorID: flexboxFront.actorID,
       color,
+      flexItems,
       highlighted,
-      nodeFront,
+      nodeFront: containerNodeFront,
       properties: flexboxFront.properties,
     }));
   }
 }
 
 module.exports = FlexboxInspector;
--- a/devtools/client/inspector/flexbox/reducers/flexbox.js
+++ b/devtools/client/inspector/flexbox/reducers/flexbox.js
@@ -11,16 +11,18 @@ const {
   UPDATE_FLEXBOX_HIGHLIGHTED,
 } = require("../actions/index");
 
 const INITIAL_FLEXBOX = {
   // The actor ID of the flex container.
   actorID: null,
   // The color of the flexbox highlighter overlay.
   color: "",
+  // An array of flex items belonging to the current flex container.
+  flexItems: [],
   // Whether or not the flexbox highlighter is highlighting the flex container.
   highlighted: false,
   // The NodeFront of the flex container.
   nodeFront: null,
   // The computed style properties of the flex container.
   properties: {},
 };
 
--- a/devtools/client/inspector/flexbox/types.js
+++ b/devtools/client/inspector/flexbox/types.js
@@ -1,24 +1,49 @@
 /* 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";
 
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
+/**
+ * A flex item data.
+ */
+const flexItem = exports.flexItem = {
+
+  // The actor ID of the flex item.
+  actorID: PropTypes.string,
+
+  // The flex item sizing data.
+  flexItemSizing: PropTypes.object,
+
+  // The NodeFront of the flex item.
+  nodeFront: PropTypes.object,
+
+  // The computed style properties of the flex item.
+  properties: PropTypes.object,
+
+};
+
+/**
+ * A flex container data.
+ */
 exports.flexbox = {
 
   // The actor ID of the flex container.
   actorID: PropTypes.string,
 
   // The color of the flexbox highlighter overlay.
   color: PropTypes.string,
 
+  // Array of flex container's flex items.
+  flexItems: PropTypes.arrayOf(PropTypes.shape(flexItem)),
+
   // Whether or not the flexbox highlighter is highlighting the flex container.
   highlighted: PropTypes.bool,
 
   // The NodeFront of the flex container.
   nodeFront: PropTypes.object,
 
   // The computed style properties of the flex container.
   properties: PropTypes.object,
--- a/devtools/client/inspector/fonts/components/FontStyle.js
+++ b/devtools/client/inspector/fonts/components/FontStyle.js
@@ -41,17 +41,17 @@ class FontStyle extends PureComponent {
       ),
       dom.div(
         {
           className: "font-control-input"
         },
         dom.input(
           {
             checked: this.props.value === "italic" || this.props.value === "oblique",
-            className: "font-value-toggle",
+            className: "devtools-checkbox-toggle",
             name: this.name,
             onChange: this.onToggle,
             type: "checkbox",
           }
         )
       )
     );
   }
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -36,16 +36,18 @@ class HighlightersOverlay {
     this.editors = {};
     this.inspector = inspector;
     this.highlighterUtils = this.inspector.toolbox.highlighterUtils;
     this.store = this.inspector.store;
     this.telemetry = inspector.telemetry;
 
     // NodeFront of the flexbox container that is highlighted.
     this.flexboxHighlighterShown = null;
+    // NodeFront of the flex item that is highlighted.
+    this.flexItemHighlighterShown = null;
     // NodeFront of element that is highlighted by the geometry editor.
     this.geometryEditorHighlighterShown = null;
     // NodeFront of the grid container that is highlighted.
     this.gridHighlighterShown = null;
     // Name of the highlighter shown on mouse hover.
     this.hoveredHighlighterShown = null;
     // Name of the selector highlighter shown.
     this.selectorHighlighterShown = null;
@@ -59,19 +61,21 @@ class HighlightersOverlay {
     };
 
     this.onClick = this.onClick.bind(this);
     this.onMarkupMutation = this.onMarkupMutation.bind(this);
     this.onMouseMove = this.onMouseMove.bind(this);
     this.onMouseOut = this.onMouseOut.bind(this);
     this.onWillNavigate = this.onWillNavigate.bind(this);
     this.hideFlexboxHighlighter = this.hideFlexboxHighlighter.bind(this);
+    this.hideFlexItemHighlighter = this.hideFlexItemHighlighter.bind(this);
     this.hideGridHighlighter = this.hideGridHighlighter.bind(this);
     this.hideShapesHighlighter = this.hideShapesHighlighter.bind(this);
     this.showFlexboxHighlighter = this.showFlexboxHighlighter.bind(this);
+    this.showFlexItemHighlighter = this.showFlexItemHighlighter.bind(this);
     this.showGridHighlighter = this.showGridHighlighter.bind(this);
     this.showShapesHighlighter = this.showShapesHighlighter.bind(this);
     this._handleRejection = this._handleRejection.bind(this);
     this.onShapesHighlighterShown = this.onShapesHighlighterShown.bind(this);
     this.onShapesHighlighterHidden = this.onShapesHighlighterHidden.bind(this);
 
     // Add inspector events, not specific to a given view.
     this.inspector.on("markupmutation", this.onMarkupMutation);
@@ -211,22 +215,20 @@ class HighlightersOverlay {
     if (node == this.shapesHighlighterShown) {
       const options = Object.assign({}, this.state.shapes.options);
       options.hoverPoint = point;
       await this.showShapesHighlighter(node, options);
     }
   }
 
   /**
-   * Create a flexbox highlighter settings object for the provided nodeFront.
-   *
-   * @param  {NodeFront} nodeFront
-   *         The NodeFront for which we need highlighter settings.
+   * Create a flexbox highlighter settings object from the Redux store containing any
+   * highlighter options that should be passed into the highlighter.
    */
-  getFlexboxHighlighterSettings(nodeFront) {
+  getFlexboxHighlighterSettings() {
     const { flexbox } = this.store.getState();
     const color = flexbox.color;
     return { color };
   }
 
   /**
    * Toggle the flexbox highlighter for the given flexbox container element.
    *
@@ -303,16 +305,72 @@ class HighlightersOverlay {
     this.flexboxHighlighterShown = null;
     this.emit("flexbox-highlighter-hidden", nodeFront);
 
     // Erase flexbox highlighter state.
     this.state.flexbox = null;
   }
 
   /**
+   * Toggle the flex item highlighter for the given flex item element.
+   *
+   * @param  {NodeFront} node
+   *         The NodeFront of the flex item element to highlight.
+   * @param  {Object} options
+   *         Object used for passing options to the flex item highlighter.
+   */
+  async toggleFlexItemHighlighter(node, options = {}) {
+    if (node == this.flexItemHighlighterShown) {
+      await this.hideFlexItemHighlighter(node);
+      return;
+    }
+
+    await this.showFlexItemHighlighter(node, options);
+  }
+
+  /**
+   * Show the flex item highlighter for the given flex item element.
+   *
+   * @param  {NodeFront} node
+   *         The NodeFront of the flex item element to highlight.
+   * @param  {Object} options
+   *         Object used for passing options to the flex item highlighter.
+   */
+  async showFlexItemHighlighter(node, options) {
+    const highlighter = await this._getHighlighter("FlexItemHighlighter");
+    if (!highlighter) {
+      return;
+    }
+
+    options = Object.assign({}, options, this.getFlexboxHighlighterSettings());
+
+    const isShown = await highlighter.show(node, options);
+    if (!isShown) {
+      return;
+    }
+
+    this.flexItemHighlighterShown = node;
+  }
+
+  /**
+   * Hide the flex item highlighter for the given flex item element.
+   *
+   * @param  {NodeFront} node
+   *         The NodeFront of the flex item element to unhighlight.
+   */
+  async hideFlexItemHighlighter(node) {
+    if (!this.flexItemHighlighterShown || !this.highlighters.FlexItemHighlighter) {
+      return;
+    }
+
+    await this.highlighters.FlexItemHighlighter.hide();
+    this.flexItemHighlighterShown = null;
+  }
+
+  /**
    * Create a grid highlighter settings object for the provided nodeFront.
    *
    * @param  {NodeFront} nodeFront
    *         The NodeFront for which we need highlighter settings.
    */
   getGridHighlighterSettings(nodeFront) {
     const { grids, highlighterSettings } = this.store.getState();
     const grid = grids.find(g => g.nodeFront === nodeFront);
@@ -907,34 +965,38 @@ class HighlightersOverlay {
     if (!hasInterestingMutation) {
       // Bail out if the mutations did not remove nodes, or if no grid highlighter is
       // displayed.
       return;
     }
 
     this._hideHighlighterIfDeadNode(this.flexboxHighlighterShown,
       this.hideFlexboxHighlighter);
+    this._hideHighlighterIfDeadNode(this.flexItemHighlighterShown,
+      this.hideFlexItemHighlighter);
     this._hideHighlighterIfDeadNode(this.gridHighlighterShown,
       this.hideGridHighlighter);
     this._hideHighlighterIfDeadNode(this.shapesHighlighterShown,
       this.hideShapesHighlighter);
   }
 
   /**
    * Clear saved highlighter shown properties on will-navigate.
    */
   onWillNavigate() {
+    this.destroyEditors();
+
     this.boxModelHighlighterShown = null;
     this.flexboxHighlighterShown = null;
+    this.flexItemHighlighterShown = null;
     this.geometryEditorHighlighterShown = null;
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
     this.shapesHighlighterShown = null;
-    this.destroyEditors();
   }
 
   /**
   * Destroy and clean-up all instances of in-context editors.
   */
   destroyEditors() {
     for (const type in this.editors) {
       this.editors[type].off("show");
@@ -975,16 +1037,17 @@ class HighlightersOverlay {
 
     this.inspector = null;
     this.highlighterUtils = null;
     this.state = null;
     this.store = null;
 
     this.boxModelHighlighterShown = null;
     this.flexboxHighlighterShown = null;
+    this.flexItemHighlighterShown = null;
     this.geometryEditorHighlighterShown = null;
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
     this.shapesHighlighterShown = null;
 
     this.destroyed = true;
   }
--- a/devtools/client/locales/en-US/layout.properties
+++ b/devtools/client/locales/en-US/layout.properties
@@ -7,20 +7,16 @@
 
 # LOCALIZATION NOTE (flexbox.header): The accordion header for the Flexbox pane.
 flexbox.header=Flexbox
 
 # LOCALIZATION NOTE (flexbox.noFlexboxeOnThisPage): In the case where there are no CSS
 # flex containers to display.
 flexbox.noFlexboxeOnThisPage=Select a Flex container or item to continue.
 
-# LOCALIZATION NOTE (flexbox.overlayFlexbox): Header for the list of flex container
-# elements if only one item can be selected.
-flexbox.overlayFlexbox=Overlay Flexbox
-
 # LOCALIZATION NOTE (flexbox.flexContainerProperties): Header for the flex container
 # properties in the Flexbox panel.
 flexbox.flexContainerProperties=Flex Container Properties
 
 # LOCALIZATION NOTE (layout.cannotShowGridOutline, layout.cannotSHowGridOutline.title):
 # In the case where the grid outline cannot be effectively displayed.
 layout.cannotShowGridOutline=Cannot show outline for this grid
 layout.cannotShowGridOutline.title=The selected grid’s outline cannot effectively fit inside the layout panel for it to be usable.
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -52,29 +52,35 @@ pref("devtools.inspector.three-pane-firs
 // Collapse pseudo-elements by default in the rule-view
 pref("devtools.inspector.show_pseudo_elements", false);
 // The default size for image preview tooltips in the rule-view/computed-view/markup-view
 pref("devtools.inspector.imagePreviewTooltipSize", 300);
 // Enable user agent style inspection in rule-view
 pref("devtools.inspector.showUserAgentStyles", false);
 // Show all native anonymous content (like controls in <video> tags)
 pref("devtools.inspector.showAllAnonymousContent", false);
-// Enable the Flexbox highlighter
-pref("devtools.inspector.flexboxHighlighter.enabled", false);
 // Enable the CSS shapes highlighter
 pref("devtools.inspector.shapesHighlighter.enabled", true);
-// Enable the Flexbox Inspector panel
-pref("devtools.flexboxinspector.enabled", false);
 // Enable the new Animation Inspector
 pref("devtools.new-animationinspector.enabled", true);
 // Enable the Font Editor
 pref("devtools.inspector.fonteditor.enabled", true);
 // Enable the font highlight-on-hover feature
 pref("devtools.inspector.fonthighlighter.enabled", true);
 
+// Flexbox preferences
+// Enable the Flexbox highlighter in Nightly
+#if defined(NIGHTLY_BUILD)
+pref("devtools.inspector.flexboxHighlighter.enabled", true);
+#else
+pref("devtools.inspector.flexboxHighlighter.enabled", false);
+#endif
+// Enable the Flexbox Inspector panel
+pref("devtools.flexboxinspector.enabled", false);
+
 // Grid highlighter preferences
 pref("devtools.gridinspector.gridOutlineMaxColumns", 50);
 pref("devtools.gridinspector.gridOutlineMaxRows", 50);
 pref("devtools.gridinspector.showGridAreas", false);
 pref("devtools.gridinspector.showGridLineNumbers", false);
 pref("devtools.gridinspector.showInfiniteLines", false);
 
 // Whether or not the box model panel is opened in the layout view
--- a/devtools/client/themes/common.css
+++ b/devtools/client/themes/common.css
@@ -3,25 +3,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 @import url("resource://devtools/client/themes/splitters.css");
 @namespace html url("http://www.w3.org/1999/xhtml");
 
 :root {
   font: message-box;
 
+  --clear-icon-url: url("chrome://devtools/skin/images/clear.svg");
+  --tab-line-hover-color: rgba(0,0,0,.2);
   --tab-line-selected-color: var(--blue-50);
-}
-
-:root.theme-light {
-  --tab-line-hover-color: rgba(0,0,0,.2);
+  --toggle-thumb-color: white;
+  --toggle-track-color: var(--grey-30);
 }
 
 :root.theme-dark {
   --tab-line-hover-color: rgba(255,255,255,.2);
+  --toggle-thumb-color: var(--grey-40);
+  --toggle-track-color: var(--grey-50);
 }
 
 :root[platform="mac"] {
   --monospace-font-family: Menlo, monospace;
 }
 
 :root[platform="win"] {
   --monospace-font-family: Consolas, monospace;
@@ -379,19 +381,16 @@ checkbox:-moz-focusring {
 
 .devtools-toolbarbutton:not([disabled])[label][checked=true]:focus,
 .devtools-toolbarbutton:not([disabled])[label][open]:focus,
 .devtools-button:not(:empty).checked:focus {
   background-color: var(--toolbarbutton-checked-focus-background);
 }
 
 /* Icons */
-:root {
-  --clear-icon-url: url("chrome://devtools/skin/images/clear.svg");
-}
 
 .devtools-button.devtools-clear-icon::before {
   background-image: var(--clear-icon-url);
 }
 
 .devtools-button.devtools-filter-icon::before {
   background-image: var(--filter-image);
 }
@@ -795,8 +794,55 @@ checkbox:-moz-focusring {
 /* No result message styles */
 
 .devtools-sidepanel-no-result {
   font-style: italic;
   padding: 0.5em 21px;
   -moz-user-select: none;
   font-size: 12px;
 }
+
+/* Checkbox Toggle */
+
+.devtools-checkbox-toggle {
+  --x-pos: .15em;
+  /* Reset native checkbox styling. */
+  -moz-appearance: none;
+  background-color: var(--toggle-track-color);
+  cursor: pointer;
+  /* Change font-size to scale. */
+  font-size: 16px;
+  width: 2em;
+  height: 1em;
+  border-radius: 1em;
+  /* Animate the thumb position between states of the checkbox. */
+  transition: background-color .1s ease-out;
+}
+
+.devtools-checkbox-toggle:focus {
+  box-shadow: 0 0 0 1px var(--blue-55);
+}
+
+.devtools-checkbox-toggle:checked:focus {
+  background-color: var(--blue-40);
+  box-shadow: none;
+}
+
+.devtools-checkbox-toggle:checked {
+  --x-pos: 1.15em;
+  background-color: var(--blue-55);
+}
+
+.devtools-checkbox-toggle::before {
+  position: relative;
+  width: calc(1em - .3em);
+  height: calc(1em - .3em);
+  transform: translateY(.15em) translateX(var(--x-pos));
+  border-radius: 100%;
+  display: block;
+  content: "";
+  background-color: var(--toggle-thumb-color);
+  transition: transform .1s ease-out;
+}
+
+.devtools-checkbox-toggle:checked::before {
+  background-color: white;
+}
--- a/devtools/client/themes/fonts.css
+++ b/devtools/client/themes/fonts.css
@@ -1,28 +1,24 @@
 /* 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/. */
 
 /* CSS Variables specific to the font editor that aren't defined by the themes */
 :root {
   --slider-thumb-color: var(--grey-50);
   --slider-track-color: var(--grey-30);
-  --toggle-thumb-color: white;
-  --toggle-track-color: var(--grey-30);
   --input-background-color: white;
   --input-border-color: var(--grey-30);
   --input-text-color: var(--grey-90);
 }
 
 :root.theme-dark {
   --slider-thumb-color: var(--grey-40);
   --slider-track-color: var(--grey-50);
-  --toggle-thumb-color: var(--grey-40);
-  --toggle-track-color: var(--grey-50);
   --input-background-color: var(--grey-70);
   --input-border-color: var(--grey-70);
   --input-text-color: var(--grey-40);
 }
 
 #sidebar-panel-fontinspector {
   margin: 0;
   display: flex;
@@ -351,68 +347,16 @@
   background-color: var(--blue-55);
 }
 
 .font-value-slider::-moz-range-track {
   background-color: var(--slider-track-color);
   height: 3px;
 }
 
-/*
-  Restyle a native checkbox input to look like a toggle with a "thumb".
-  Build the decoration using solid shapes created with radial- and linear-gradient
-  background images. Animate the position of the "thumb" using background-position.
- */
-.font-value-toggle {
-  --x-pos: .15em;
-  /* Reset native checkbox styling. */
-  -moz-appearance: none;
-  background-color: var(--toggle-track-color);
-  cursor: pointer;
-  /* Change font-size to scale. */
-  font-size: 16px;
-  width: 2em;
-  height: 1em;
-  border-radius: 1em;
-  /* Animate the thumb position between states of the checkbox. */
-  transition: background-color .1s ease-out;
-  /* border: 1px solid transparent; */
-  /* box-sizing: content-box; */
-}
-
-.font-value-toggle:focus {
-  box-shadow: 0 0 0 1px var(--blue-55);
-}
-
-.font-value-toggle:checked:focus {
-  background-color: var(--blue-40);
-  box-shadow: none;
-}
-
-.font-value-toggle:checked {
-  --x-pos: 1.15em;
-  background-color: var(--blue-55);
-}
-
-.font-value-toggle::before {
-  position: relative;
-  width: calc(1em - .3em);
-  height: calc(1em - .3em);
-  transform: translateY(.15em) translateX(var(--x-pos));
-  border-radius: 100%;
-  display: block;
-  content: "";
-  background-color: var(--toggle-thumb-color);
-  transition: transform .1s ease-out;
-}
-
-.font-value-toggle:checked::before {
-  background-color: white;
-}
-
 .font-origin {
   margin-top: -.25em;
   color: var(--theme-comment);
   justify-self: start;
 }
 
 .font-origin.system {
   text-transform: capitalize;
--- a/devtools/client/themes/layout.css
+++ b/devtools/client/themes/layout.css
@@ -4,66 +4,68 @@
 
 #layout-container {
   height: 100%;
   width: 100%;
   overflow: auto;
   min-width: 200px;
 }
 
+#layout-container .accordion ._content {
+  padding: 0;
+}
+
 /**
  * Common styles for shared components
  */
 
-.flexbox-container,
 .grid-container {
   display: flex;
   flex-direction: column;
   flex: 1 auto;
   min-width: 140px;
   margin-inline-start: 16px;
 }
 
 .grid-container:first-child {
   margin-bottom: 10px;
 }
 
-.flexbox-container > span,
 .grid-container > span {
   font-weight: 600;
   margin-bottom: 5px;
   pointer-events: none;
 }
 
-.flexbox-container > ul,
 .grid-container > ul {
   list-style: none;
   margin: 0;
   padding: 0;
 }
 
-.flexbox-container li,
-.grid-container li {
+#layout-container li {
   padding: 3px 0;
+  -moz-user-select: none;
 }
 
-.flexbox-container input,
+.flex-container input,
 .grid-container input {
   margin-inline-end: 7px;
   vertical-align: middle;
 }
 
-.flexbox-container label,
+.flex-container label,
 .grid-container label {
   margin-inline-start: -3px;
 }
 
 /* Layout Properties: Common styles used for the Box Model and Flexbox Properties */
 
 .layout-properties-header {
+  font-size: 12px;
   padding: 2px 3px;
   -moz-user-select: none;
 }
 
 .layout-properties-expander {
   vertical-align: middle;
   display: inline-block;
   margin-inline-start: 2px;
@@ -84,45 +86,75 @@
   flex: 1;
 }
 
 .layout-properties-wrapper .computed-property-value-container {
   flex: 1;
   display: block;
 }
 
+#layout-flexbox-container {
+  display: flex;
+  flex-direction: column;
+}
+
+/**
+ * Flex Container
+ */
+
+.flex-container {
+  border-bottom: 1px solid var(--theme-splitter-color);
+  padding: 5px 0;
+  padding-inline-start: 20px;
+}
+
+/**
+ * Flex Item List
+ */
+
+#flex-item-list {
+  border-bottom: 1px solid var(--theme-splitter-color);
+  font-size: 12px;
+  margin: 0;
+  padding-top: 5px;
+  padding-bottom: 5px;
+}
+
 /**
  * Flex Container Properties
  */
 
 #flex-container-properties {
-  margin: 0 0 5px 0;
+  margin-bottom: 5px;
+}
+
+#flex-container-properties .layout-properties-header {
+  padding: 5px 0;
+  padding-inline-start: 20px;
 }
 
 /**
  * Grid Container
  */
 
-#layout-flexbox-container,
 #layout-grid-container {
   display: flex;
   flex-direction: column;
-  margin: 5px;
+  padding: 5px;
 }
 
 /**
  * Grid Content
  */
 
-.flexbox-content,
 .grid-content {
   display: flex;
   flex-wrap: wrap;
   flex: 1;
-  margin: 5px 0;
+  padding: 5px 0;
 }
 
 /**
  * Grid Outline
  */
 
 .grid-outline-container {
   margin: 5px;
--- a/devtools/client/themes/markup.css
+++ b/devtools/client/themes/markup.css
@@ -442,13 +442,14 @@ ul.children + .tag-line::before {
 .markup-badge[data-display="inline-flex"]:not(.active).interactive:hover,
 .markup-badge[data-display="inline-grid"]:not(.active):focus,
 .markup-badge[data-display="inline-grid"]:not(.active):hover,
 .markup-badge[data-event]:focus,
 .markup-badge[data-event]:hover {
   background-color: var(--markup-badge-hover-background-color);
 }
 
-.markup-badge.active {
+.markup-badge.active,
+.markup-badge.interactive.active {
   background-color: var(--markup-badge-active-background-color);
   border-color: var(--markup-badge-active-border-color);
   color: var(--theme-selection-color);
 }
--- a/devtools/server/actors/layout.js
+++ b/devtools/server/actors/layout.js
@@ -1,32 +1,38 @@
 /* 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";
 
 const { Cu } = require("chrome");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
-const { flexboxSpec, gridSpec, layoutSpec } = require("devtools/shared/specs/layout");
-const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
+const {
+  flexboxSpec,
+  flexItemSpec,
+  gridSpec,
+  layoutSpec,
+} = require("devtools/shared/specs/layout");
+const { SHOW_ELEMENT } = require("devtools/shared/dom-node-filter-constants");
 const { getStringifiableFragments } =
   require("devtools/server/actors/utils/css-grid-utils");
 
+loader.lazyRequireGetter(this, "CssLogic", "devtools/server/actors/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants");
-loader.lazyRequireGetter(this, "CssLogic", "devtools/server/actors/inspector/css-logic", true);
 
 /**
  * Set of actors the expose the CSS layout information to the devtools protocol clients.
  *
  * The |Layout| actor is the main entry point. It is used to get various CSS
  * layout-related information from the document.
  *
  * The |Flexbox| actor provides the container node information to inspect the flexbox
- * container.
+ * container. It is also used to return an array of |FlexItem| actors which provide the
+ * flex item information.
  *
  * The |Grid| actor provides the grid fragment information to inspect the grid container.
  */
 
 const FlexboxActor = ActorClassWithSpec(flexboxSpec, {
   /**
    * @param  {LayoutActor} layoutActor
    *         The LayoutActor instance.
@@ -70,16 +76,119 @@ const FlexboxActor = ActorClassWithSpec(
     // ActorID so we avoid the client from doing another round trip to get it in many
     // cases.
     if (this.walker.hasNode(this.containerEl)) {
       form.containerNodeActorID = this.walker.getNode(this.containerEl).actorID;
     }
 
     return form;
   },
+
+  /**
+   * Returns an array of FlexItemActor objects for all the flex item elements contained
+   * in the flex container element.
+   *
+   * @return {Array} An array of FlexItemActor objects.
+   */
+  getFlexItems() {
+    if (isNodeDead(this.containerEl)) {
+      return [];
+    }
+
+    const flex = this.containerEl.getAsFlexContainer();
+    if (!flex) {
+      return [];
+    }
+
+    const flexItemActors = [];
+
+    for (const line of flex.getLines()) {
+      for (const item of line.getItems()) {
+        flexItemActors.push(new FlexItemActor(this, item.node, {
+          crossMaxSize: item.crossMaxSize,
+          crossMinSize: item.crossMinSize,
+          mainBaseSize: item.mainBaseSize,
+          mainDeltaSize: item.mainDeltaSize,
+          mainMaxSize: item.mainMaxSize,
+          mainMinSize: item.mainMinSize,
+        }));
+      }
+    }
+
+    return flexItemActors;
+  },
+});
+
+/**
+ * The FlexItemActor provides information about a flex items' data.
+ */
+const FlexItemActor = ActorClassWithSpec(flexItemSpec, {
+  /**
+   * @param  {FlexboxActor} flexboxActor
+   *         The FlexboxActor instance.
+   * @param  {DOMNode} element
+   *         The flex item element.
+   * @param  {Object} flexItemSizing
+   *         The flex item sizing data.
+   */
+  initialize(flexboxActor, element, flexItemSizing) {
+    Actor.prototype.initialize.call(this, flexboxActor.conn);
+
+    this.containerEl = flexboxActor.containerEl;
+    this.element = element;
+    this.flexItemSizing = flexItemSizing;
+    this.walker = flexboxActor.walker;
+  },
+
+  destroy() {
+    Actor.prototype.destroy.call(this);
+
+    this.containerEl = null;
+    this.element = null;
+    this.flexItemSizing = null;
+    this.walker = null;
+  },
+
+  form(detail) {
+    if (detail === "actorid") {
+      return this.actorID;
+    }
+
+    const { flexDirection } = CssLogic.getComputedStyle(this.containerEl);
+    const styles = CssLogic.getComputedStyle(this.element);
+    const clientRect = this.element.getBoundingClientRect();
+    const dimension = flexDirection.startsWith("row") ? "width" : "height";
+
+    const form = {
+      actor: this.actorID,
+      // The flex item sizing data.
+      flexItemSizing: this.flexItemSizing,
+      // The computed style properties of the flex item.
+      properties: {
+        "flex-basis": styles.flexBasis,
+        "flex-grow": styles.flexGrow,
+        "flex-shrink": styles.flexShrink,
+        // min-width/height computed style.
+        [`min-${dimension}`]: styles[`min-${dimension}`],
+        // max-width/height computed style.
+        [`max-${dimension}`]: styles[`max-${dimension}`],
+        // Computed width/height of the flex item element.
+        [dimension]: parseFloat(clientRect[dimension.toLowerCase()].toPrecision(6)),
+      },
+    };
+
+    // If the WalkerActor already knows the flex item element, then also return its
+    // ActorID so we avoid the client from doing another round trip to get it in many
+    // cases.
+    if (this.walker.hasNode(this.element)) {
+      form.nodeActorID = this.walker.getNode(this.element).actorID;
+    }
+
+    return form;
+  },
 });
 
 /**
  * The GridActor provides information about a given grid's fragment data.
  */
 const GridActor = ActorClassWithSpec(gridSpec, {
   /**
    * @param  {LayoutActor} layoutActor
@@ -170,18 +279,17 @@ const LayoutActor = ActorClassWithSpec(l
       return null;
     }
 
     // Given node can either be a Node or a NodeActor.
     if (node.rawNode) {
       node = node.rawNode;
     }
 
-    const treeWalker = this.walker.getDocumentWalker(node,
-      nodeFilterConstants.SHOW_ELEMENT);
+    const treeWalker = this.walker.getDocumentWalker(node, SHOW_ELEMENT);
     let currentNode = treeWalker.currentNode;
     let displayType = this.walker.getNode(currentNode).displayType;
 
     if (!displayType) {
       return null;
     }
 
     if (type == "flex" &&
@@ -282,10 +390,11 @@ const LayoutActor = ActorClassWithSpec(l
   },
 });
 
 function isNodeDead(node) {
   return !node || (node.rawNode && Cu.isDeadWrapper(node.rawNode));
 }
 
 exports.FlexboxActor = FlexboxActor;
+exports.FlexItemActor = FlexItemActor;
 exports.GridActor = GridActor;
 exports.LayoutActor = LayoutActor;
--- a/devtools/server/actors/network-event.js
+++ b/devtools/server/actors/network-event.js
@@ -285,16 +285,21 @@ const NetworkEventActor = protocol.Actor
    * Add network request headers.
    *
    * @param array headers
    *        The request headers array.
    * @param string rawHeaders
    *        The raw headers source.
    */
   addRequestHeaders(headers, rawHeaders) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._request.headers = headers;
     this._prepareHeaders(headers);
 
     if (rawHeaders) {
       rawHeaders = new LongStringActor(this.conn, rawHeaders);
       // bug 1462561 - Use "json" type and manually manage/marshall actors to woraround
       // protocol.js performance issue
       this.manage(rawHeaders);
@@ -310,31 +315,41 @@ const NetworkEventActor = protocol.Actor
 
   /**
    * Add network request cookies.
    *
    * @param array cookies
    *        The request cookies array.
    */
   addRequestCookies(cookies) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._request.cookies = cookies;
     this._prepareHeaders(cookies);
 
     this.emit("network-event-update:cookies", "requestCookies", {
       cookies: cookies.length,
     });
   },
 
   /**
    * Add network request POST data.
    *
    * @param object postData
    *        The request POST data.
    */
   addRequestPostData(postData) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._request.postData = postData;
     postData.text = new LongStringActor(this.conn, postData.text);
     // bug 1462561 - Use "json" type and manually manage/marshall actors to woraround
     // protocol.js performance issue
     this.manage(postData.text);
     const dataSize = postData.text.str.length;
     postData.text = postData.text.form();
 
@@ -348,16 +363,21 @@ const NetworkEventActor = protocol.Actor
    * Add the initial network response information.
    *
    * @param object info
    *        The response information.
    * @param string rawHeaders
    *        The raw headers source.
    */
   addResponseStart(info, rawHeaders) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     rawHeaders = new LongStringActor(this.conn, rawHeaders);
     // bug 1462561 - Use "json" type and manually manage/marshall actors to woraround
     // protocol.js performance issue
     this.manage(rawHeaders);
     this._response.rawHeaders = rawHeaders.form();
 
     this._response.httpVersion = info.httpVersion;
     this._response.status = info.status;
@@ -373,46 +393,61 @@ const NetworkEventActor = protocol.Actor
 
   /**
    * Add connection security information.
    *
    * @param object info
    *        The object containing security information.
    */
   addSecurityInfo(info) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._securityInfo = info;
 
     this.emit("network-event-update:security-info", "securityInfo", {
       state: info.state,
     });
   },
 
   /**
    * Add network response headers.
    *
    * @param array headers
    *        The response headers array.
    */
   addResponseHeaders(headers) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._response.headers = headers;
     this._prepareHeaders(headers);
 
     this.emit("network-event-update:headers", "responseHeaders", {
       headers: headers.length,
       headersSize: this._response.headersSize,
     });
   },
 
   /**
    * Add network response cookies.
    *
    * @param array cookies
    *        The response cookies array.
    */
   addResponseCookies(cookies) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._response.cookies = cookies;
     this._prepareHeaders(cookies);
 
     this.emit("network-event-update:cookies", "responseCookies", {
       cookies: cookies.length,
     });
   },
 
@@ -423,16 +458,21 @@ const NetworkEventActor = protocol.Actor
    *        The response content.
    * @param object
    *        - boolean discardedResponseBody
    *          Tells if the response content was recorded or not.
    *        - boolean truncated
    *          Tells if the some of the response content is missing.
    */
   addResponseContent(content, {discardResponseBody, truncated}) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._truncated = truncated;
     this._response.content = content;
     content.text = new LongStringActor(this.conn, content.text);
     // bug 1462561 - Use "json" type and manually manage/marshall actors to woraround
     // protocol.js performance issue
     this.manage(content.text);
     content.text = content.text.form();
 
@@ -441,29 +481,39 @@ const NetworkEventActor = protocol.Actor
       contentSize: content.size,
       encoding: content.encoding,
       transferredSize: content.transferredSize,
       discardResponseBody,
     });
   },
 
   addResponseCache: function(content) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._response.responseCache = content.responseCache;
     this.emit("network-event-update:response-cache", "responseCache");
   },
 
   /**
    * Add network event timing information.
    *
    * @param number total
    *        The total time of the network event.
    * @param object timings
    *        Timing details about the network event.
    */
   addEventTimings(total, timings, offsets) {
+    // Ignore calls when this actor is already destroyed
+    if (!this.actorID) {
+      return;
+    }
+
     this._totalTime = total;
     this._timings = timings;
     this._offsets = offsets;
 
     this.emit("network-event-update:event-timings", "eventTimings", {
       totalTime: total
     });
   },
--- a/devtools/server/actors/network-monitor/network-observer.js
+++ b/devtools/server/actors/network-monitor/network-observer.js
@@ -107,33 +107,36 @@ exports.matchRequest = matchRequest;
  *        Object with the filters to use for network requests:
  *        - window (nsIDOMWindow): filter network requests by the associated
  *          window object.
  *        - outerWindowID (number): filter requests by their top frame's outerWindowID.
  *        Filters are optional. If any of these filters match the request is
  *        logged (OR is applied). If no filter is provided then all requests are
  *        logged.
  * @param object owner
- *        The network monitor owner. This object needs to hold:
+ *        The network observer owner. This object needs to hold:
  *        - onNetworkEvent(requestInfo)
  *          This method is invoked once for every new network request and it is
  *          given the initial network request information as an argument.
  *          onNetworkEvent() must return an object which holds several add*()
  *          methods which are used to add further network request/response information.
  */
 function NetworkObserver(filters, owner) {
   this.filters = filters;
   this.owner = owner;
+
   this.openRequests = new Map();
   this.openResponses = new Map();
+
   this._httpResponseExaminer =
     DevToolsUtils.makeInfallible(this._httpResponseExaminer).bind(this);
   this._httpModifyExaminer =
     DevToolsUtils.makeInfallible(this._httpModifyExaminer).bind(this);
   this._serviceWorkerRequest = this._serviceWorkerRequest.bind(this);
+
   this._throttleData = null;
   this._throttler = null;
 }
 
 exports.NetworkObserver = NetworkObserver;
 
 NetworkObserver.prototype = {
   filters: null,
@@ -1060,18 +1063,18 @@ NetworkObserver.prototype = {
 
     return {
       total: totalTime,
       offsets: offsets
     };
   },
 
   /**
-   * Suspend Web Console activity. This is called when all Web Consoles are
-   * closed.
+   * Suspend observer activity. This is called when the Network monitor actor stops
+   * listening.
    */
   destroy: function() {
     if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) {
       gActivityDistributor.removeObserver(this);
       Services.obs.removeObserver(this._httpResponseExaminer,
                                   "http-on-examine-response");
       Services.obs.removeObserver(this._httpResponseExaminer,
                                   "http-on-examine-cached-response");
--- a/devtools/server/actors/webconsole/listeners/document-events.js
+++ b/devtools/server/actors/webconsole/listeners/document-events.js
@@ -27,16 +27,21 @@ exports.DocumentEventsListener = Documen
 
 DocumentEventsListener.prototype = {
   listen() {
     EventEmitter.on(this.console.parentActor, "window-ready", this.onWindowReady);
     this.onWindowReady({ window: this.console.window, isTopLevel: true });
   },
 
   onWindowReady({ window, isTopLevel }) {
+    // Avoid listening if the console actor is already destroyed
+    if (!this.console.conn) {
+      return;
+    }
+
     // Ignore iframes
     if (!isTopLevel) {
       return;
     }
 
     const { readyState } = window.document;
     if (readyState != "interactive" && readyState != "complete") {
       window.addEventListener("DOMContentLoaded", this.onContentLoaded, { once: true });
@@ -46,30 +51,40 @@ DocumentEventsListener.prototype = {
     if (readyState != "complete") {
       window.addEventListener("load", this.onLoad, { once: true });
     } else {
       this.onLoad({ target: window.document });
     }
   },
 
   onContentLoaded(event) {
+    // Avoid emitting an event when the console actor is already destroyed
+    if (!this.console.conn) {
+      return;
+    }
+
     const window = event.target.defaultView;
     const packet = {
       from: this.console.actorID,
       type: "documentEvent",
       name: "dom-interactive",
       // milliseconds since the UNIX epoch, when the parser finished its work
       // on the main document, that is when its Document.readyState changes to
       // 'interactive' and the corresponding readystatechange event is thrown
       time: window.performance.timing.domInteractive
     };
     this.console.conn.send(packet);
   },
 
   onLoad(event) {
+    // Avoid emitting an event when the console actor is already destroyed
+    if (!this.console.conn) {
+      return;
+    }
+
     const window = event.target.defaultView;
     const packet = {
       from: this.console.actorID,
       type: "documentEvent",
       name: "dom-complete",
       // milliseconds since the UNIX epoch, when the parser finished its work
       // on the main document, that is when its Document.readyState changes to
       // 'complete' and the corresponding readystatechange event is thrown
--- a/devtools/shared/fronts/layout.js
+++ b/devtools/shared/fronts/layout.js
@@ -1,16 +1,21 @@
 /* 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";
 
 const { FrontClassWithSpec } = require("devtools/shared/protocol");
-const { flexboxSpec, gridSpec, layoutSpec } = require("devtools/shared/specs/layout");
+const {
+  flexboxSpec,
+  flexItemSpec,
+  gridSpec,
+  layoutSpec,
+} = require("devtools/shared/specs/layout");
 
 const FlexboxFront = FrontClassWithSpec(flexboxSpec, {
   form: function(form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
     this._form = form;
@@ -31,16 +36,52 @@ const FlexboxFront = FrontClassWithSpec(
   /**
    * Get the computed style properties for the flex container.
    */
   get properties() {
     return this._form.properties;
   },
 });
 
+const FlexItemFront = FrontClassWithSpec(flexItemSpec, {
+  form: function(form, detail) {
+    if (detail === "actorid") {
+      this.actorID = form;
+      return;
+    }
+    this._form = form;
+  },
+
+  /**
+   * Get the flex item sizing data.
+   */
+  get flexItemSizing() {
+    return this._form.flexItemSizing;
+  },
+
+  /**
+   * In some cases, the FlexItemActor already knows the NodeActor ID of the node where the
+   * flex item is located. In such cases, this getter returns the NodeFront for it.
+   */
+  get nodeFront() {
+    if (!this._form.nodeActorID) {
+      return null;
+    }
+
+    return this.conn.getActor(this._form.nodeActorID);
+  },
+
+  /**
+   * Get the computed style properties for the flex item.
+   */
+  get properties() {
+    return this._form.properties;
+  },
+});
+
 const GridFront = FrontClassWithSpec(gridSpec, {
   form: function(form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
     this._form = form;
   },
@@ -87,10 +128,11 @@ const GridFront = FrontClassWithSpec(gri
 
     return this._form.writingMode;
   },
 });
 
 const LayoutFront = FrontClassWithSpec(layoutSpec, {});
 
 exports.FlexboxFront = FlexboxFront;
+exports.FlexItemFront = FlexItemFront;
 exports.GridFront = GridFront;
 exports.LayoutFront = LayoutFront;
--- a/devtools/shared/protocol.js
+++ b/devtools/shared/protocol.js
@@ -981,16 +981,21 @@ Actor.prototype = extend(Pool.prototype,
   // Existing Actors extending this class expect initialize to contain constructor logic.
   initialize: Actor,
 
   toString: function() {
     return "[Actor " + this.typeName + "/" + this.actorID + "]";
   },
 
   _sendEvent: function(name, request, ...args) {
+    if (!this.actorID) {
+      console.error(`Tried to send a '${name}' event on an already destroyed actor` +
+                    ` '${this.typeName}'`);
+      return;
+    }
     let packet;
     try {
       packet = request.write(args, this);
     } catch (ex) {
       console.error("Error sending event: " + name);
       throw ex;
     }
     packet.from = packet.from || this.actorID;
--- a/devtools/shared/specs/layout.js
+++ b/devtools/shared/specs/layout.js
@@ -4,16 +4,29 @@
 
 "use strict";
 
 const { Arg, generateActorSpec, RetVal } = require("devtools/shared/protocol");
 
 const flexboxSpec = generateActorSpec({
   typeName: "flexbox",
 
+  methods: {
+    getFlexItems: {
+      request: {},
+      response: {
+        flexitems: RetVal("array:flexitem")
+      }
+    },
+  },
+});
+
+const flexItemSpec = generateActorSpec({
+  typeName: "flexitem",
+
   methods: {},
 });
 
 const gridSpec = generateActorSpec({
   typeName: "grid",
 
   methods: {},
 });
@@ -47,10 +60,11 @@ const layoutSpec = generateActorSpec({
       response: {
         grids: RetVal("array:grid")
       }
     },
   },
 });
 
 exports.flexboxSpec = flexboxSpec;
+exports.flexItemSpec = flexItemSpec;
 exports.gridSpec = gridSpec;
 exports.layoutSpec = layoutSpec;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/EventStateManager.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/Logging.h"
 #include "mozilla/MediaFeatureChange.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ResultExtensions.h"
 #include "mozilla/Services.h"
+#include "mozilla/StaticPrefs.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Unused.h"
 
 #include "mozilla/dom/ClientChannelHelper.h"
 #include "mozilla/dom/ClientHandle.h"
 #include "mozilla/dom/ClientInfo.h"
 #include "mozilla/dom/ClientManager.h"
@@ -13110,33 +13111,31 @@ nsDocShell::GetNestedFrameId(uint64_t* a
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection)
 {
   *aUseTrackingProtection  = false;
 
-  static bool sCBEnabled = false;
+  bool cbEnabled = StaticPrefs::browser_contentblocking_enabled();
   static bool sTPEnabled = false;
   static bool sTPInPBEnabled = false;
   static bool sPrefsInit = false;
 
   if (!sPrefsInit) {
     sPrefsInit = true;
-    Preferences::AddBoolVarCache(&sCBEnabled,
-      "browser.contentblocking.enabled", true);
     Preferences::AddBoolVarCache(&sTPEnabled,
       "privacy.trackingprotection.enabled", false);
     Preferences::AddBoolVarCache(&sTPInPBEnabled,
       "privacy.trackingprotection.pbmode.enabled", false);
   }
 
-  if (mUseTrackingProtection || (sCBEnabled && sTPEnabled) ||
-      (sCBEnabled && UsePrivateBrowsing() && sTPInPBEnabled)) {
+  if (mUseTrackingProtection || (cbEnabled && sTPEnabled) ||
+      (cbEnabled && UsePrivateBrowsing() && sTPInPBEnabled)) {
     *aUseTrackingProtection = true;
     return NS_OK;
   }
 
   RefPtr<nsDocShell> parent = GetParentDocshell();
   if (parent) {
     return parent->GetUseTrackingProtection(aUseTrackingProtection);
   }
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -31,17 +31,16 @@
 #include "nsExternalSharingAppService.h"
 #include "nsExternalURLHandlerService.h"
 #endif
 
 // session history
 #include "nsSHEntry.h"
 #include "nsSHEntryShared.h"
 #include "nsSHistory.h"
-#include "nsSHTransaction.h"
 
 // LoadContexts (used for testing)
 #include "LoadContext.h"
 
 using mozilla::dom::ContentHandlerService;
 
 static bool gInitialized = false;
 
@@ -91,17 +90,16 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDBusHan
 #if defined(MOZ_WIDGET_ANDROID)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsExternalSharingAppService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsExternalURLHandlerService)
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ContentHandlerService, Init)
 
 // session history
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHEntry)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHTransaction)
 
 NS_DEFINE_NAMED_CID(NS_DOCSHELL_CID);
 NS_DEFINE_NAMED_CID(NS_DEFAULTURIFIXUP_CID);
 NS_DEFINE_NAMED_CID(NS_WEBNAVIGATION_INFO_CID);
 NS_DEFINE_NAMED_CID(NS_ABOUT_REDIRECTOR_MODULE_CID);
 NS_DEFINE_NAMED_CID(NS_URI_LOADER_CID);
 NS_DEFINE_NAMED_CID(NS_DOCUMENTLOADER_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_EXTERNALHELPERAPPSERVICE_CID);
@@ -113,17 +111,16 @@ NS_DEFINE_NAMED_CID(NS_LOCALHANDLERAPP_C
 #ifdef MOZ_ENABLE_DBUS
 NS_DEFINE_NAMED_CID(NS_DBUSHANDLERAPP_CID);
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
 NS_DEFINE_NAMED_CID(NS_EXTERNALSHARINGAPPSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_EXTERNALURLHANDLERSERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_SHENTRY_CID);
-NS_DEFINE_NAMED_CID(NS_SHTRANSACTION_CID);
 NS_DEFINE_NAMED_CID(NS_CONTENTHANDLERSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_LOADCONTEXT_CID);
 NS_DEFINE_NAMED_CID(NS_PRIVATELOADCONTEXT_CID);
 
 const mozilla::Module::CIDEntry kDocShellCIDs[] = {
   { &kNS_DOCSHELL_CID, false, nullptr, nsDocShellConstructor },
   { &kNS_DEFAULTURIFIXUP_CID, false, nullptr, nsDefaultURIFixupConstructor },
   { &kNS_WEBNAVIGATION_INFO_CID, false, nullptr, nsWebNavigationInfoConstructor },
@@ -141,17 +138,16 @@ const mozilla::Module::CIDEntry kDocShel
 #ifdef MOZ_ENABLE_DBUS
   { &kNS_DBUSHANDLERAPP_CID, false, nullptr, nsDBusHandlerAppConstructor },
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
   { &kNS_EXTERNALSHARINGAPPSERVICE_CID, false, nullptr, nsExternalSharingAppServiceConstructor },
   { &kNS_EXTERNALURLHANDLERSERVICE_CID, false, nullptr, nsExternalURLHandlerServiceConstructor },
 #endif
   { &kNS_SHENTRY_CID, false, nullptr, nsSHEntryConstructor },
-  { &kNS_SHTRANSACTION_CID, false, nullptr, nsSHTransactionConstructor },
   { &kNS_LOADCONTEXT_CID, false, nullptr, mozilla::CreateTestLoadContext },
   { &kNS_PRIVATELOADCONTEXT_CID, false, nullptr, mozilla::CreatePrivateTestLoadContext },
   { nullptr }
 };
 
 const mozilla::Module::ContractIDEntry kDocShellContracts[] = {
   { "@mozilla.org/docshell;1", &kNS_DOCSHELL_CID },
   { NS_URIFIXUP_CONTRACTID, &kNS_DEFAULTURIFIXUP_CID },
@@ -199,17 +195,16 @@ const mozilla::Module::ContractIDEntry k
 #ifdef MOZ_ENABLE_DBUS
   { NS_DBUSHANDLERAPP_CONTRACTID, &kNS_DBUSHANDLERAPP_CID },
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
   { NS_EXTERNALSHARINGAPPSERVICE_CONTRACTID, &kNS_EXTERNALSHARINGAPPSERVICE_CID },
   { NS_EXTERNALURLHANDLERSERVICE_CONTRACTID, &kNS_EXTERNALURLHANDLERSERVICE_CID },
 #endif
   { NS_SHENTRY_CONTRACTID, &kNS_SHENTRY_CID },
-  { NS_SHTRANSACTION_CONTRACTID, &kNS_SHTRANSACTION_CID },
   { NS_LOADCONTEXT_CONTRACTID, &kNS_LOADCONTEXT_CID },
   { NS_PRIVATELOADCONTEXT_CONTRACTID, &kNS_PRIVATELOADCONTEXT_CID },
   { nullptr }
 };
 
 static const mozilla::Module kDocShellModule = {
   mozilla::Module::kVersion,
   kDocShellCIDs,
--- a/docshell/shistory/nsISHTransaction.idl
+++ b/docshell/shistory/nsISHTransaction.idl
@@ -38,19 +38,8 @@ interface nsISHTransaction : nsISupports
 	attribute boolean persist;
 
 	/**
 	 * Create a transaction with parent and History Entry 
 	 */
 	 void create(in nsISHEntry aSHEntry, in nsISHTransaction aPrev);
 };
 
-%{ C++
-// {BFD1A792-AD9F-11d3-BDC7-0050040A9B44}
-
-
-#define NS_SHTRANSACTION_CID \
-{0xbfd1a792, 0xad9f, 0x11d3, {0xbd, 0xc7, 0x0, 0x50, 0x4, 0xa, 0x9b, 0x44}}
-
-#define NS_SHTRANSACTION_CONTRACTID \
-    "@mozilla.org/browser/session-history-transaction;1"
-
-%}
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -14,17 +14,17 @@
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIObserverService.h"
 #include "nsISHEntry.h"
 #include "nsISHistoryListener.h"
-#include "nsISHTransaction.h"
+#include "nsSHTransaction.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsTArray.h"
 #include "prsystem.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MathAlgorithms.h"
@@ -645,19 +645,17 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntr
 
   if (!currentPersist) {
     NOTIFY_LISTENERS(OnHistoryReplaceEntry, (currentIndex));
     NS_ENSURE_SUCCESS(currentTxn->SetSHEntry(aSHEntry), NS_ERROR_FAILURE);
     currentTxn->SetPersist(aPersist);
     return NS_OK;
   }
 
-  nsCOMPtr<nsISHTransaction> txn(
-    do_CreateInstance(NS_SHTRANSACTION_CONTRACTID));
-  NS_ENSURE_TRUE(txn, NS_ERROR_FAILURE);
+  nsCOMPtr<nsISHTransaction> txn(new nsSHTransaction());
 
   nsCOMPtr<nsIURI> uri;
   aSHEntry->GetURI(getter_AddRefs(uri));
   NOTIFY_LISTENERS(OnHistoryNewEntry, (uri, currentIndex));
 
   // If a listener has changed mIndex, we need to get currentTxn again,
   // otherwise we'll be left at an inconsistent state (see bug 320742)
   if (currentIndex != mIndex) {
--- a/dom/abort/AbortSignal.cpp
+++ b/dom/abort/AbortSignal.cpp
@@ -30,18 +30,19 @@ AbortSignalImpl::Abort()
 {
   if (mAborted) {
     return;
   }
 
   mAborted = true;
 
   // Let's inform the followers.
-  for (AbortFollower* follower : mFollowers) {
-    follower->Abort();
+  nsTObserverArray<AbortFollower*>::ForwardIterator iter(mFollowers);
+  while (iter.HasMore()) {
+    iter.GetNext()->Abort();
   }
 }
 
 void
 AbortSignalImpl::AddFollower(AbortFollower* aFollower)
 {
   MOZ_DIAGNOSTIC_ASSERT(aFollower);
   if (!mFollowers.Contains(aFollower)) {
--- a/dom/abort/AbortSignal.h
+++ b/dom/abort/AbortSignal.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_AbortSignal_h
 #define mozilla_dom_AbortSignal_h
 
 #include "mozilla/DOMEventTargetHelper.h"
+#include "nsTObserverArray.h"
 
 namespace mozilla {
 namespace dom {
 
 class AbortSignal;
 class AbortSignalImpl;
 
 // This class must be implemented by objects who want to follow a
@@ -57,17 +58,17 @@ public:
   void
   RemoveFollower(AbortFollower* aFollower);
 
 protected:
   virtual ~AbortSignalImpl() = default;
 
 private:
   // Raw pointers. AbortFollower unregisters itself in the DTOR.
-  nsTArray<AbortFollower*> mFollowers;
+  nsTObserverArray<AbortFollower*> mFollowers;
 
   bool mAborted;
 };
 
 class AbortSignal final : public DOMEventTargetHelper
                         , public AbortSignalImpl
 {
 public:
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -37,16 +37,23 @@ public:
   }
 
   virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
   {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mDefinition");
     aCb.NoteNativeChild(mDefinition,
       NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition));
   }
+
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+  {
+    // We don't really own mDefinition.
+    return aMallocSizeOf(this);
+  }
+
 private:
   virtual void Invoke(Element* aElement, ErrorResult& aRv) override
   {
     CustomElementRegistry::Upgrade(aElement, mDefinition, aRv);
   }
 
   RefPtr<CustomElementDefinition> mDefinition;
 };
@@ -62,28 +69,47 @@ class CustomElementCallbackReaction fina
     {
     }
 
     virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
     {
       mCustomElementCallback->Traverse(aCb);
     }
 
+    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+    {
+      size_t n = aMallocSizeOf(this);
+
+      n += mCustomElementCallback->SizeOfIncludingThis(aMallocSizeOf);
+
+      return n;
+    }
+
   private:
     virtual void Invoke(Element* aElement, ErrorResult& aRv) override
     {
       mCustomElementCallback->Call();
     }
 
     UniquePtr<CustomElementCallback> mCustomElementCallback;
 };
 
 //-----------------------------------------------------
 // CustomElementCallback
 
+size_t
+LifecycleCallbackArgs::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = name.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += oldValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += newValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += namespaceURI.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  return n;
+}
+
 void
 CustomElementCallback::Call()
 {
   switch (mType) {
     case nsIDocument::eConnected:
       static_cast<LifecycleConnectedCallback *>(mCallback.get())->Call(mThisObject);
       break;
     case nsIDocument::eDisconnected:
@@ -108,16 +134,34 @@ CustomElementCallback::Traverse(nsCycleC
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
   aCb.NoteXPCOMChild(mThisObject);
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback");
   aCb.NoteXPCOMChild(mCallback);
 }
 
+size_t
+CustomElementCallback::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  // We don't uniquely own mThisObject.
+
+  // We own mCallback but it doesn't have any special memory reporting we can do
+  // for it other than report its own size.
+  n += aMallocSizeOf(mCallback);
+
+  n += mArgs.SizeOfExcludingThis(aMallocSizeOf);
+
+  // mAdoptedCallbackArgs doesn't really uniquely own its members.
+
+  return n;
+}
+
 CustomElementCallback::CustomElementCallback(Element* aThisObject,
                                              nsIDocument::ElementCallbackType aCallbackType,
                                              mozilla::dom::CallbackFunction* aCallback)
   : mThisObject(aThisObject),
     mCallback(aCallback),
     mType(aCallbackType)
 {
 }
@@ -209,16 +253,30 @@ CustomElementData::Traverse(nsCycleColle
 
 void
 CustomElementData::Unlink()
 {
   mReactionQueue.Clear();
   mCustomElementDefinition = nullptr;
 }
 
+size_t
+CustomElementData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  n += mReactionQueue.ShallowSizeOfExcludingThis(aMallocSizeOf);
+
+  for (auto& reaction : mReactionQueue) {
+    n += reaction->SizeOfIncludingThis(aMallocSizeOf);
+  }
+
+  return n;
+}
+
 //-----------------------------------------------------
 // CustomElementRegistry
 
 namespace {
 
 class MOZ_RAII AutoConstructionStackEntry final
 {
 public:
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -36,31 +36,34 @@ class Function;
 class Promise;
 
 struct LifecycleCallbackArgs
 {
   nsString name;
   nsString oldValue;
   nsString newValue;
   nsString namespaceURI;
+
+  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
 };
 
 struct LifecycleAdoptedCallbackArgs
 {
   nsCOMPtr<nsIDocument> mOldDocument;
   nsCOMPtr<nsIDocument> mNewDocument;
 };
 
 class CustomElementCallback
 {
 public:
   CustomElementCallback(Element* aThisObject,
                         nsIDocument::ElementCallbackType aCallbackType,
                         CallbackFunction* aCallback);
   void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   void Call();
   void SetArgs(LifecycleCallbackArgs& aArgs)
   {
     MOZ_ASSERT(mType == nsIDocument::eAttributeChanged,
                "Arguments are only used by attribute changed callback.");
     mArgs = aArgs;
   }
 
@@ -125,16 +128,17 @@ struct CustomElementData
   AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
 
   void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
   CustomElementDefinition* GetCustomElementDefinition();
   nsAtom* GetCustomElementType();
 
   void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
   void Unlink();
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   nsAtom* GetIs(Element* aElement)
   {
     // If mType isn't the same as name atom, this is a customized built-in
     // element, which has 'is' value set.
     return aElement->NodeInfo()->NameAtom() == mType ? nullptr : mType.get();
   }
 private:
@@ -203,16 +207,17 @@ private:
 };
 
 class CustomElementReaction
 {
 public:
   virtual ~CustomElementReaction() = default;
   virtual void Invoke(Element* aElement, ErrorResult& aRv) = 0;
   virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const = 0;
+  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const = 0;
 
   bool IsUpgradeReaction()
   {
     return mIsUpgradeReaction;
   }
 
 protected:
   bool mIsUpgradeReaction = false;
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -669,16 +669,24 @@ nsIContent::nsExtendedContentSlots::Trav
 }
 
 nsIContent::nsExtendedContentSlots::nsExtendedContentSlots()
 {
 }
 
 nsIContent::nsExtendedContentSlots::~nsExtendedContentSlots() = default;
 
+size_t
+nsIContent::nsExtendedContentSlots::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  // For now, nothing to measure here.  We don't actually own any of our
+  // members.
+  return 0;
+}
+
 FragmentOrElement::nsDOMSlots::nsDOMSlots()
   : nsIContent::nsContentSlots(),
     mDataset(nullptr)
 {
   MOZ_COUNT_CTOR(nsDOMSlots);
 }
 
 FragmentOrElement::nsDOMSlots::~nsDOMSlots()
@@ -720,18 +728,24 @@ FragmentOrElement::nsDOMSlots::Unlink()
   mChildrenList = nullptr;
   mClassList = nullptr;
 }
 
 size_t
 FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
-  if (OwnsExtendedSlots()) {
-    n += aMallocSizeOf(GetExtendedContentSlots());
+
+  nsExtendedContentSlots* extendedSlots = GetExtendedContentSlots();
+  if (extendedSlots) {
+    if (OwnsExtendedSlots()) {
+      n += aMallocSizeOf(extendedSlots);
+    }
+
+    n += extendedSlots->SizeOfExcludingThis(aMallocSizeOf);
   }
 
   if (mAttributeMap) {
     n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf);
   }
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
@@ -795,16 +809,59 @@ FragmentOrElement::nsExtendedDOMSlots::T
   aCb.NoteNativeChild(mXBLBinding,
                      NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
 
   if (mCustomElementData) {
     mCustomElementData->Traverse(aCb);
   }
 }
 
+size_t
+FragmentOrElement::nsExtendedDOMSlots::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = nsIContent::nsExtendedContentSlots::SizeOfExcludingThis(aMallocSizeOf);
+
+  // We own mSMILOverrideStyle but there seems to be no memory reporting on CSS
+  // declarations?  At least report the memory the declaration takes up
+  // directly.
+  if (mSMILOverrideStyle) {
+    n += aMallocSizeOf(mSMILOverrideStyle);
+  }
+
+  // We don't really own mSMILOverrideStyleDeclaration.  mSMILOverrideStyle owns
+  // it.
+
+  // We don't seem to have memory reporting for nsXULControllers.  At least
+  // report the memory it's using directly.
+  if (mControllers) {
+    n += aMallocSizeOf(mControllers);
+  }
+
+  // We don't seem to have memory reporting for nsLabelsNodeList.  At least
+  // report the memory it's using directly.
+  if (mLabelsList) {
+    n += aMallocSizeOf(mLabelsList);
+  }
+
+  // mShadowRoot should be handled during normal DOM tree memory reporting, just
+  // like kids, siblings, etc.
+
+  // We don't seem to have memory reporting for nsXBLBinding.  At least
+  // report the memory it's using directly.
+  if (mXBLBinding) {
+    n += aMallocSizeOf(mXBLBinding);
+  }
+
+  if (mCustomElementData) {
+    n += mCustomElementData->SizeOfIncludingThis(aMallocSizeOf);
+  }
+
+  return n;
+}
+
 FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsIContent(aNodeInfo)
 {
 }
 
 FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
   : nsIContent(aNodeInfo)
 {
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -169,16 +169,18 @@ public:
   {
   public:
     nsExtendedDOMSlots();
     ~nsExtendedDOMSlots();
 
     void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&) final;
     void UnlinkExtendedSlots() final;
 
+    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const final;
+
     /**
      * SMIL Overridde style rules (for SMIL animation of CSS properties)
      * @see Element::GetSMILOverrideStyle
      */
     RefPtr<nsDOMCSSAttributeDeclaration> mSMILOverrideStyle;
 
     /**
      * Holds any SMIL override style declaration for this element.
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -334,16 +334,18 @@ uint32_t nsContentUtils::sCookiesLifetim
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
 bool nsContentUtils::sDoNotTrackEnabled = false;
 
+bool nsContentUtils::sAntiTrackingControlCenterUIEnabled = false;
+
 mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump");
 
 PopupControlState nsContentUtils::sPopupControlState = openAbused;
 
 int32_t nsContentUtils::sInnerOrOuterWindowCount = 0;
 uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0;
 
 // Subset of http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name
@@ -732,16 +734,19 @@ nsContentUtils::Init()
                                "browser.autofocus", true);
 
   Preferences::AddBoolVarCache(&sIsBytecodeCacheEnabled,
                                "dom.script_loader.bytecode_cache.enabled", false);
 
   Preferences::AddBoolVarCache(&sDisablePopups,
                                "dom.disable_open_during_load", false);
 
+  Preferences::AddBoolVarCache(&sAntiTrackingControlCenterUIEnabled,
+                               "browser.contentblocking.rejecttrackers.control-center.ui.enabled", 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();
 
@@ -8906,18 +8911,17 @@ StorageDisabledByAntiTrackingInternal(ns
 bool
 nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
                                               nsIChannel* aChannel,
                                               nsIPrincipal* aPrincipal,
                                               nsIURI* aURI)
 {
   bool disabled =
     StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI);
-  if (disabled &&
-      StaticPrefs::privacy_restrict3rdpartystorage_ui_enabled()) {
+  if (disabled && sAntiTrackingControlCenterUIEnabled) {
     nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
     if (!thirdPartyUtil) {
       return false;
     }
 
     nsCOMPtr<nsPIDOMWindowOuter> pwin;
     if (aWindow) {
       auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow());
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3474,17 +3474,17 @@ private:
   static bool sShowInputPlaceholderOnFocus;
   static bool sAutoFocusEnabled;
 #ifndef RELEASE_OR_BETA
   static bool sBypassCSSOMOriginCheck;
 #endif
   static bool sIsBytecodeCacheEnabled;
   static int32_t sBytecodeCacheStrategy;
   static uint32_t sCookiesLifetimePolicy;
-  static bool sShortcutsCustomized;
+  static bool sAntiTrackingControlCenterUIEnabled;
 
   static int32_t sPrivacyMaxInnerWidth;
   static int32_t sPrivacyMaxInnerHeight;
 
   class UserInteractionObserver;
   static UserInteractionObserver* sUserInteractionObserver;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -4429,8 +4429,27 @@ nsDOMWindowUtils::GetSystemFont(nsACStri
   }
 
   nsAutoCString fontName;
   widget->GetSystemFont(fontName);
   aFontName.Assign(fontName);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName,
+                                                    bool* aRecorded)
+{
+  *aRecorded = false;
+
+  nsIDocument* doc = GetDocument();
+  if (!doc || !doc->GetStyleUseCounters()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  bool knownProp = false;
+  *aRecorded =
+    Servo_IsCssPropertyRecordedInUseCounter(doc->GetStyleUseCounters(),
+                                            &aPropName,
+                                            &knownProp);
+  return knownProp ? NS_OK : NS_ERROR_FAILURE;
+}
+
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1515,16 +1515,20 @@ nsIDocument::nsIDocument()
     mServoRestyleRootDirtyBits(0),
     mThrowOnDynamicMarkupInsertionCounter(0),
     mIgnoreOpensDuringUnloadCounter(0),
     mNumTrackersFound(0),
     mNumTrackersBlocked(0)
 {
   SetIsInDocument();
   SetIsConnected(true);
+
+  if (StaticPrefs::layout_css_use_counters_enabled()) {
+    mStyleUseCounters.reset(Servo_UseCounters_Create());
+  }
 }
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
@@ -12650,17 +12654,18 @@ nsIDocument::SetDocTreeHadPlayRevoked()
     topLevelDoc->mDocTreeHadPlayRevoked = true;
   }
 }
 
 void
 nsIDocument::MaybeAllowStorageForOpener()
 {
   if (StaticPrefs::network_cookie_cookieBehavior() !=
-        nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+        nsICookieService::BEHAVIOR_REJECT_TRACKER ||
+      !StaticPrefs::browser_contentblocking_enabled()) {
     return;
   }
 
   // This will probably change for project fission, but currently this document
   // and the opener are on the same process. In the future, we should make this
   // part async.
 
   nsPIDOMWindowInner* inner = GetInnerWindow();
@@ -13161,18 +13166,21 @@ PrincipalFlashClassifier::AsyncClassifyI
     return FlashClassification::Denied;
   }
 
   nsresult rv = aPrincipal->GetURI(getter_AddRefs(mClassificationURI));
   if (NS_FAILED(rv) || !mClassificationURI) {
     return FlashClassification::Denied;
   }
 
+  // We don't support extra entries by pref for this classifier.
   rv = mUriClassifier->AsyncClassifyLocalWithTables(mClassificationURI,
                                                     tables,
+                                                    nsTArray<nsCString>(),
+                                                    nsTArray<nsCString>(),
                                                     this);
 
   if (NS_FAILED(rv)) {
     if (rv == NS_ERROR_MALFORMED_URI) {
       // This means that the URI had no hostname (ex: file://doc.html). In this
       // case, we allow the default (Unknown plugin) behavior.
       return FlashClassification::Unknown;
     } else {
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -792,16 +792,18 @@ protected:
   {
   public:
     nsExtendedContentSlots();
     virtual ~nsExtendedContentSlots();
 
     virtual void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&);
     virtual void UnlinkExtendedSlots();
 
+    virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
     /**
      * The nearest enclosing content node with a binding that created us.
      * TODO(emilio): This should be an Element*.
      *
      * @see nsIContent::GetBindingParent
      */
     nsCOMPtr<nsIContent> mBindingParent;
 
@@ -856,16 +858,18 @@ protected:
     void SetExtendedContentSlots(nsExtendedContentSlots* aSlots, bool aOwning)
     {
       mExtendedSlots = reinterpret_cast<uintptr_t>(aSlots);
       if (!aOwning) {
         mExtendedSlots |= sNonOwningExtendedSlotsFlag;
       }
     }
 
+    // OwnsExtendedSlots returns true if we have no extended slots or if we
+    // have extended slots and own them.
     bool OwnsExtendedSlots() const
     {
       return !(mExtendedSlots & sNonOwningExtendedSlotsFlag);
     }
 
     nsExtendedContentSlots* GetExtendedContentSlots() const
     {
       return reinterpret_cast<nsExtendedContentSlots*>(
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3397,16 +3397,21 @@ public:
 
   void SetDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
     if (!mUseCounters[aUseCounter]) {
       mUseCounters[aUseCounter] = true;
     }
   }
 
+  const StyleUseCounters* GetStyleUseCounters()
+  {
+    return mStyleUseCounters.get();
+  }
+
   void SetPageUseCounter(mozilla::UseCounter aUseCounter);
 
   void SetDocumentAndPageUseCounter(mozilla::UseCounter aUseCounter)
   {
     SetDocumentUseCounter(aUseCounter);
     SetPageUseCounter(aUseCounter);
   }
 
@@ -4314,16 +4319,19 @@ protected:
   // Flags for use counters used directly by this document.
   std::bitset<mozilla::eUseCounter_Count> mUseCounters;
   // Flags for use counters used by any child documents of this document.
   std::bitset<mozilla::eUseCounter_Count> mChildDocumentUseCounters;
   // Flags for whether we've notified our top-level "page" of a use counter
   // for this child document.
   std::bitset<mozilla::eUseCounter_Count> mNotifiedPageForUseCounter;
 
+  // The CSS property use counters.
+  mozilla::UniquePtr<StyleUseCounters> mStyleUseCounters;
+
   // Whether the user has interacted with the document or not:
   bool mUserHasInteracted;
 
   // Whether the user has interacted with the document via a restricted
   // set of gestures which are likely to be interaction with the document,
   // and not events that are fired as a byproduct of the user interacting
   // with the browser (events for like scrolling the page, keyboard short
   // cuts, etc).
--- a/dom/fetch/FetchObserver.cpp
+++ b/dom/fetch/FetchObserver.cpp
@@ -9,20 +9,22 @@
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(FetchObserver)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FetchObserver,
                                                   DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFollowingSignal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FetchObserver,
                                                 DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFollowingSignal)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchObserver)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(FetchObserver, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(FetchObserver, DOMEventTargetHelper)
 
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -25,23 +25,25 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Request)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Request)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFollowingSignal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Request)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFollowingSignal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Request)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamBody)
   MOZ_DIAGNOSTIC_ASSERT(!tmp->mReadableStreamReader);
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1923,16 +1923,24 @@ interface nsIDOMWindowUtils : nsISupport
 
   /**
    * Capture the contents of the current WebRender frame and
    * save them to a folder relative to the current working directory.
    */
   void wrCapture();
 
   /**
+   * Returns whether the document we're associated to has recorded a given CSS
+   * property via the use counter mechanism.
+   *
+   * Throws if there's no document or the property is invalid.
+   */
+  bool isCssPropertyRecordedInUseCounter(in ACString aProperty);
+
+  /**
    * NOTE: Currently works only on GTK+.
    */
   attribute ACString systemFont;
 
   // These consts are only for testing purposes.
   const long DEFAULT_MOUSE_POINTER_ID = 0;
   const long DEFAULT_PEN_POINTER_ID   = 1;
   const long DEFAULT_TOUCH_POINTER_ID = 2;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1639,21 +1639,18 @@ StartMacOSContentSandbox()
   int sandboxLevel = GetEffectiveContentSandboxLevel();
   if (sandboxLevel < 1) {
     return false;
   }
 
   // Close all current connections to the WindowServer. This ensures that the
   // Activity Monitor will not label the content process as "Not responding"
   // because it's not running a native event loop. See bug 1384336.
-  if (!recordreplay::IsRecordingOrReplaying()) {
-    // Because of the WebReplay system for proxying system API calls, for the
-    // time being we skip this when running under WebReplay (bug 1482668).
-    CGSShutdownServerConnections();
-  }
+  CGSShutdownServerConnections();
+
   // Actual security benefits are only acheived when we additionally deny
   // future connections, however this currently breaks WebGL so it's not done
   // by default.
   if (Preferences::GetBool(
         "security.sandbox.content.mac.disconnect-windowserver")) {
     CGError result = CGSSetDenyWindowServerConnections(true);
     MOZ_DIAGNOSTIC_ASSERT(result == kCGErrorSuccess);
 #if !MOZ_DIAGNOSTIC_ASSERT_ENABLED
--- a/dom/ipc/URLClassifierParent.cpp
+++ b/dom/ipc/URLClassifierParent.cpp
@@ -60,17 +60,20 @@ URLClassifierLocalParent::StartClassify(
 {
   nsresult rv = NS_OK;
   // Note that in safe mode, the URL classifier service isn't available, so we
   // should handle the service not being present gracefully.
   nsCOMPtr<nsIURIClassifier> uriClassifier =
     do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
   if (NS_SUCCEEDED(rv)) {
     MOZ_ASSERT(aURI);
-    rv = uriClassifier->AsyncClassifyLocalWithTables(aURI, aTables, this);
+    rv = uriClassifier->AsyncClassifyLocalWithTables(aURI, aTables,
+                                                     nsTArray<nsCString>(),
+                                                     nsTArray<nsCString>(),
+                                                     this);
   }
   if (NS_FAILED(rv)) {
     // Cannot do ClassificationFailed() because the child side
     // is expecting a callback. Only the second parameter will
     // be used, which is the "matched list". We treat "unable
     // to classify" as "not on any list".
     OnClassifyComplete(NS_OK, EmptyCString(), EmptyCString(), EmptyCString());
   }
--- a/dom/plugins/base/nsPluginsDirUnix.cpp
+++ b/dom/plugins/base/nsPluginsDirUnix.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsNPAPIPlugin.h"
 #include "nsNPAPIPluginInstance.h"
-#include "nsIMemory.h"
 #include "nsPluginsDir.h"
 #include "nsPluginsDirUtils.h"
 #include "prenv.h"
 #include "prerror.h"
 #include "prio.h"
 #include <sys/stat.h>
 #include "nsString.h"
 #include "nsIFile.h"
--- a/dom/promise/Promise-inl.h
+++ b/dom/promise/Promise-inl.h
@@ -76,16 +76,38 @@ struct StorageTypeHelper<SmartPtr<T>, tr
   : EnableIf<IsConvertible<SmartPtr<T>, T*>::value,
              RefPtr<T>>
 {
 };
 
 template <typename T>
 using StorageType = typename StorageTypeHelper<typename Decay<T>::Type>::Type;
 
+// Helpers to choose the correct argument type based on the storage type. Smart
+// pointers are converted to the corresponding raw pointer type. Everything else
+// is passed by move reference.
+//
+// Note: We can't just use std::forward for this because the input type may be a
+// raw pointer which does not match the argument type, and while the
+// spec-compliant behavior there should still give us the expected results, MSVC
+// considers it an illegal use of std::forward.
+template <template <typename> class SmartPtr, typename T>
+decltype(DeclVal<SmartPtr<T>>().get())
+ArgType(SmartPtr<T>& aVal)
+{
+  return aVal.get();
+}
+
+template <typename T>
+T&&
+ArgType(T& aVal)
+{
+  return std::move(aVal);
+}
+
 using ::ImplCycleCollectionUnlink;
 
 template <typename Callback, typename... Args>
 class NativeThenHandler final : public PromiseNativeThenHandlerBase
 {
 public:
   NativeThenHandler(Promise& aPromise, Callback&& aOnResolve,
                     Args&&... aArgs)
@@ -113,36 +135,34 @@ protected:
     return CallCallback(aCx, mOnResolve, aValue);
   }
 
   template <size_t... Indices>
   already_AddRefed<Promise>
   CallCallback(JSContext* aCx, const Callback& aHandler, JS::Handle<JS::Value> aValue,
                std::index_sequence<Indices...>)
   {
-    return mOnResolve(aCx, aValue, std::forward<Args>(Get<Indices>(mArgs))...);
+    return mOnResolve(aCx, aValue, ArgType(Get<Indices>(mArgs))...);
   }
 
   already_AddRefed<Promise>
   CallCallback(JSContext* aCx, const Callback& aHandler, JS::Handle<JS::Value> aValue)
   {
     return CallCallback(aCx, aHandler, aValue, std::index_sequence_for<Args...>{});
   }
 
   Callback mOnResolve;
 
   Tuple<StorageType<Args>...> mArgs;
 };
 
 } // anonymous namespace
 
 template <typename Callback, typename... Args>
-typename EnableIf<
-  Promise::IsHandlerCallback<Callback, Args...>::value,
-  Result<RefPtr<Promise>, nsresult>>::Type
+Promise::ThenResult<Callback, Args...>
 Promise::ThenWithCycleCollectedArgs(Callback&& aOnResolve, Args&&... aArgs)
 {
   using HandlerType = NativeThenHandler<Callback, Args...>;
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(GetParentObject(), rv);
   if (rv.Failed()) {
     return Err(rv.StealNSResult());
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -528,31 +528,40 @@ void
 Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise)
 {
   MOZ_ASSERT(!js::IsWrapper(aPromise));
 
   MOZ_ASSERT(JS::GetPromiseState(aPromise) == JS::PromiseState::Rejected);
 
   JS::Rooted<JS::Value> result(aCx, JS::GetPromiseResult(aPromise));
 
-  js::ErrorReport report(aCx);
-  if (!report.init(aCx, result, js::ErrorReport::NoSideEffects)) {
-    JS_ClearPendingException(aCx);
-    return;
-  }
-
   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
   bool isMainThread = MOZ_LIKELY(NS_IsMainThread());
   bool isChrome = isMainThread ? nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(aPromise))
                                : IsCurrentThreadRunningChromeWorker();
   nsGlobalWindowInner* win = isMainThread
     ? xpc::WindowGlobalOrNull(aPromise)
     : nullptr;
-  xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome,
-                  win ? win->AsInner()->WindowID() : 0);
+
+  js::ErrorReport report(aCx);
+  if (report.init(aCx, result, js::ErrorReport::NoSideEffects)) {
+    xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome,
+                    win ? win->AsInner()->WindowID() : 0);
+  } else {
+    JS_ClearPendingException(aCx);
+
+    RefPtr<Exception> exn;
+    if (result.isObject() &&
+        (NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, &result, exn)) ||
+         NS_SUCCEEDED(UNWRAP_OBJECT(Exception, &result, exn)))) {
+      xpcReport->Init(aCx, exn, isChrome, win ? win->AsInner()->WindowID() : 0);
+    } else {
+      return;
+    }
+  }
 
   // Now post an event to do the real reporting async
   RefPtr<nsIRunnable> event = new AsyncErrorReporter(xpcReport);
   if (win) {
     win->Dispatch(mozilla::TaskCategory::Other, event.forget());
   } else {
     NS_DispatchToMainThread(event);
   }
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -146,35 +146,38 @@ public:
   template <typename Callback, typename... Args>
   using IsHandlerCallback =
       IsSame<already_AddRefed<Promise>,
              decltype(DeclVal<Callback>()(
                 (JSContext*)(nullptr),
                 DeclVal<JS::Handle<JS::Value>>(),
                 DeclVal<Args>()...))>;
 
+  template <typename Callback, typename... Args>
+  using ThenResult = typename EnableIf<
+    IsHandlerCallback<Callback, Args...>::value,
+    Result<RefPtr<Promise>, nsresult>>::Type;
+
   // Similar to the JavaScript Then() function. Accepts a single lambda function
   // argument, which it attaches as a native resolution handler, and returns a
   // new promise which resolves with that handler's return value, or propagates
   // any rejections from this promise.
   //
   // Any additional arguments passed after the callback function are stored and
   // passed as additional arguments to the function when it is called. These
   // values will participate in cycle collection for the promise handler, and
   // therefore may safely form reference cycles with the promise chain.
   //
   // Any strong references required by the callback should be passed in this
   // manner, rather than using lambda capture, lambda captures do not support
   // cycle collection, and can easily lead to leaks.
   //
   // Does not currently support rejection handlers.
   template <typename Callback, typename... Args>
-  typename EnableIf<
-    IsHandlerCallback<Callback, Args...>::value,
-    Result<RefPtr<Promise>, nsresult>>::Type
+  ThenResult<Callback, Args...>
   ThenWithCycleCollectedArgs(Callback&& aOnResolve, Args&&... aArgs);
 
   Result<RefPtr<Promise>, nsresult>
   ThenWithoutCycleCollection(
     const std::function<already_AddRefed<Promise>(JSContext*,
                                                   JS::HandleValue)>& aCallback);
 
   JSObject* PromiseObj() const
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/unit/.eslintrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+  "extends": [
+    "plugin:mozilla/xpcshell-test",
+  ],
+};
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/unit/test_promise_unhandled_rejection.js
@@ -0,0 +1,43 @@
+"use strict";
+
+// Tests that unhandled promise rejections generate the appropriate
+// console messages.
+
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
+ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
+
+PromiseTestUtils.expectUncaughtRejection(/could not be cloned/);
+
+add_task(async function test_unhandled_dom_exception() {
+  let sandbox = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal());
+  sandbox.StructuredCloneHolder = StructuredCloneHolder;
+
+  let filename = "resource://foo/Bar.jsm";
+
+  let {messages} = await AddonTestUtils.promiseConsoleOutput(async () => {
+    let code = `new Promise(() => {
+      new StructuredCloneHolder(() => {});
+    });`;
+
+    Cu.evalInSandbox(code, sandbox, null, filename, 1);
+
+    // We need two trips through the event loop for this error to be reported.
+    await new Promise(executeSoon);
+    await new Promise(executeSoon);
+  });
+
+  // xpcshell tests on OS-X sometimes include an extra warning, which we
+  // unfortunately need to ignore:
+  messages = messages.filter(msg => !msg.message.includes(
+    "No chrome package registered for chrome://branding/locale/brand.properties"));
+
+  equal(messages.length, 1, "Got one console message");
+
+  let [msg] = messages;
+  ok(msg instanceof Ci.nsIScriptError, "Message is a script error");
+  equal(msg.sourceName, filename, "Got expected filename");
+  equal(msg.lineNumber, 2, "Got expected line number");
+  equal(msg.errorMessage, "DataCloneError: The object could not be cloned.",
+        "Got expected error message");
+});
--- a/dom/promise/tests/unit/xpcshell.ini
+++ b/dom/promise/tests/unit/xpcshell.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 head =
 
 [test_monitor_uncaught.js]
+[test_promise_unhandled_rejection.js]
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2266,17 +2266,18 @@ RuntimeService::ResumeWorkersForWindow(n
 }
 
 void
 RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() ==
-               nsICookieService::BEHAVIOR_REJECT_TRACKER);
+               nsICookieService::BEHAVIOR_REJECT_TRACKER &&
+             StaticPrefs::browser_contentblocking_enabled());
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     workers[index]->PropagateFirstPartyStorageAccessGranted();
   }
 }
@@ -2880,17 +2881,18 @@ ResumeWorkersForWindow(nsPIDOMWindowInne
   }
 }
 
 void
 PropagateFirstPartyStorageAccessGrantedToWorkers(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() ==
-               nsICookieService::BEHAVIOR_REJECT_TRACKER);
+               nsICookieService::BEHAVIOR_REJECT_TRACKER &&
+             StaticPrefs::browser_contentblocking_enabled());
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->PropagateFirstPartyStorageAccessGranted(aWindow);
   }
 }
 
 WorkerPrivate*
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -47,17 +47,16 @@
 #include "mozilla/dom/XBLChildrenElement.h"
 
 #include "nsNodeUtils.h"
 #include "nsJSUtils.h"
 
 #include "mozilla/DeferredFinalize.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/ShadowRoot.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Helper classes
 
 /***********************************************************************/
 //
@@ -99,57 +98,39 @@ static const JSClass gPrototypeJSClass =
 };
 
 // Implementation /////////////////////////////////////////////////////////////////
 
 // Constructors/Destructors
 nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
   : mMarkedForDeath(false)
   , mUsingContentXBLScope(false)
-  , mIsShadowRootBinding(false)
   , mPrototypeBinding(aBinding)
   , mBoundElement(nullptr)
 {
   NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
   // Grab a ref to the document info so the prototype binding won't die
   NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
 }
 
-// Constructor used by web components.
-nsXBLBinding::nsXBLBinding(ShadowRoot* aShadowRoot, nsXBLPrototypeBinding* aBinding)
-  : mMarkedForDeath(false),
-    mUsingContentXBLScope(false),
-    mIsShadowRootBinding(true),
-    mPrototypeBinding(aBinding),
-    mContent(aShadowRoot),
-    mBoundElement(nullptr)
+nsXBLBinding::~nsXBLBinding()
 {
-  NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
-  // Grab a ref to the document info so the prototype binding won't die
-  NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
-}
-
-nsXBLBinding::~nsXBLBinding(void)
-{
-  if (mContent && !mIsShadowRootBinding) {
-    // It is unnecessary to uninstall anonymous content in a shadow tree
-    // because the ShadowRoot itself is a DocumentFragment and does not
-    // need any additional cleanup.
+  if (mContent) {
     nsXBLBinding::UnbindAnonymousContent(mContent->OwnerDoc(), mContent);
   }
   nsXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo();
   NS_RELEASE(info);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLBinding)
   // XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because
   //     mPrototypeBinding is weak.
-  if (tmp->mContent && !tmp->mIsShadowRootBinding) {
+  if (tmp->mContent) {
     nsXBLBinding::UnbindAnonymousContent(tmp->mContent->OwnerDoc(),
                                          tmp->mContent);
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextBinding)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDefaultInsertionPoint)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInsertionPoints)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousContentList)
@@ -414,19 +395,17 @@ nsXBLBinding::GenerateAnonymousContent()
         attrInfo.mValue->ToString(value2);
         mBoundElement->SetAttr(namespaceID, name, attrInfo.mName->GetPrefix(),
                                value2, false);
       }
     }
 
     // Conserve space by wiping the attributes off the clone.
     //
-    // FIXME(emilio): It'd be nice to make `mContent` a `RefPtr<Element>`, but
-    // as of right now it can also be a ShadowRoot (we don't enter in this
-    // codepath though). Move Shadow DOM outside XBL and then fix that.
+    // FIXME(emilio): It'd be nice to make `mContent` a `RefPtr<Element>`.
     if (mContent)
       mContent->AsElement()->UnsetAttr(namespaceID, name, false);
   }
 }
 
 nsIURI*
 nsXBLBinding::GetSourceDocURI()
 {
@@ -797,17 +776,17 @@ nsXBLBinding::ChangeDocument(nsIDocument
     // Then do our ancestors.  This reverses the construction order, so that at
     // all times things are consistent as far as everyone is concerned.
     if (mNextBinding) {
       mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
     }
 
     // Update the anonymous content.
     // XXXbz why not only for style bindings?
-    if (mContent && !mIsShadowRootBinding) {
+    if (mContent) {
       nsXBLBinding::UnbindAnonymousContent(aOldDocument, mContent);
     }
 
     ClearInsertionPoints();
   }
 }
 
 bool
--- a/dom/xbl/nsXBLBinding.h
+++ b/dom/xbl/nsXBLBinding.h
@@ -20,32 +20,30 @@ class nsXBLPrototypeBinding;
 class nsIContent;
 class nsAtom;
 class nsIDocument;
 struct RawServoAuthorStyles;
 
 namespace mozilla {
 namespace dom {
 
-class ShadowRoot;
 class XBLChildrenElement;
 
 } // namespace dom
 } // namespace mozilla
 
 class nsAnonymousContentList;
 
 // *********************************************************************/
 // The XBLBinding class
 
 class nsXBLBinding final
 {
 public:
   explicit nsXBLBinding(nsXBLPrototypeBinding* aProtoBinding);
-  nsXBLBinding(mozilla::dom::ShadowRoot* aShadowRoot, nsXBLPrototypeBinding* aProtoBinding);
 
   /**
    * XBLBindings are refcounted.  They are held onto in 3 ways:
    * 1. The binding manager's binding table holds onto all bindings that are
    *    currently attached to a content node.
    * 2. Bindings hold onto their base binding.  This is important since
    *    the base binding itself may not be attached to anything.
    * 3. The binding manager holds an additional reference to bindings
@@ -160,17 +158,16 @@ public:
 
  nsIURI* GetSourceDocURI();
 
 // MEMBER VARIABLES
 protected:
 
   bool mMarkedForDeath;
   bool mUsingContentXBLScope;
-  bool mIsShadowRootBinding;
 
   nsXBLPrototypeBinding* mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
   nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
   RefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
 
   mozilla::dom::Element* mBoundElement; // [WEAK] We have a reference, but we don't own it.
 
   // The <xbl:children> elements that we found in our <xbl:content> when we
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -19,17 +19,16 @@
 #include "nsString.h"
 #include "plstr.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIXMLContentSink.h"
 #include "nsContentCID.h"
 #include "mozilla/dom/XMLDocument.h"
 #include "nsGkAtoms.h"
-#include "nsIMemory.h"
 #include "nsIObserverService.h"
 #include "nsXBLContentSink.h"
 #include "nsXBLBinding.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLDocumentInfo.h"
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 #include "nsSyncLoadService.h"
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -130,17 +130,19 @@ static const char* kPreloadPermissions[]
   "image",
   "manifest",
   "speculative",
 
   // This permission is preloaded to support properly blocking service worker
   // interception when a user has disabled storage for a specific site.  Once
   // service worker interception moves to the parent process this should be
   // removed.  See bug 1428130.
-  "cookie"
+  "cookie",
+  "trackingprotection",
+  "trackingprotection-pb"
 };
 
 // A list of permissions that can have a fallback default permission
 // set under the permissions.default.* pref.
 static const char* kPermissionsWithDefaults[] = {
   "camera",
   "microphone",
   "geo",
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-52862
+52869
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -12787,16 +12787,17 @@ WASP/SM
 WATS/M
 WC
 WHO/M
 WI
 WMD
 WNW/M
 WP
 WSW/M
+WTF
 WTO
 WV
 WW
 WWI
 WWII
 WWW/M
 WY
 WYSIWYG
@@ -13617,16 +13618,17 @@ accounted/U
 accounting/M
 accouter/SGD
 accouterments/M
 accoutre/DSG
 accoutrements
 accredit/SGD
 accreditation/M
 accredited/U
+accrete/SD
 accretion/MS
 accrual/MS
 accrue/GDS
 acct
 acculturate/DSGN
 acculturation/M
 accumulate/XGNVDS
 accumulation/M
@@ -16323,16 +16325,17 @@ beater/M
 beatific
 beatifically
 beatification/M
 beatify/GXNDS
 beating/M
 beatitude/SM
 beatnik/MS
 beau/SM
+beaucoup
 beaut/MS
 beauteous/Y
 beautician/SM
 beautification/M
 beautifier/M
 beautiful/Y
 beautify/NDRSZG
 beauty/SM
@@ -18514,16 +18517,17 @@ cardamom/SM
 cardamon/S
 cardboard/M
 carder/MS
 cardholder/S
 cardiac
 cardie/S
 cardigan/SM
 cardinal/SMY
+cardinality/S
 cardio
 cardiogram/SM
 cardiograph/M
 cardiographs
 cardiologist/MS
 cardiology/M
 cardiomyopathy
 cardiopulmonary
@@ -36454,16 +36458,17 @@ nevi
 nevus/M
 new/STMRYP
 newbie/MS
 newborn/SM
 newcomer/SM
 newel/SM
 newfangled
 newfound
+newish
 newline/S
 newlywed/SM
 newness/M
 news/M
 newsagent/S
 newsboy/SM
 newscast/SMRZ
 newscaster/M
@@ -38782,17 +38787,17 @@ patting
 patty/SM
 paucity/M
 paunch/MS
 paunchy/RT
 pauper/MS
 pauperism/M
 pauperize/DSG
 pause/DSMG
-pave/AGDS
+pave/AGDSRZ
 paved/U
 pavement/MS
 pavilion/SM
 paving/MS
 pavlova/S
 paw/SGMD
 pawl/MS
 pawn/MDSG
@@ -40290,16 +40295,17 @@ possess/AEVGSD
 possession/ASM
 possessive/SMYP
 possessiveness/M
 possessor/SM
 possibility/SM
 possible/SM
 possibly
 possum/SM
+post-partum
 post/ZGMDRSJ
 postage/M
 postal
 postbag/S
 postbox/S
 postcard/SM
 postcode/S
 postcolonial
@@ -40388,17 +40394,17 @@ potty/PRSMT
 pouch/MDSG
 pouf/S
 pouffe/S
 poulterer/MS
 poultice/DSMG
 poultry/M
 pounce/DSMG
 pound's
-pound/KDSG
+pound/KDSGRZ
 poundage/M
 pounding/SM
 pour/GDSJ
 pout/ZGMDRS
 pouter/M
 poutine/S
 poverty/M
 pow
@@ -47219,16 +47225,17 @@ stunk
 stunned
 stunner/S
 stunning/Y
 stunt/GSMD
 stuntman
 stuntmen
 stupefaction/M
 stupefy/DSG
+stupefyingly
 stupendous/Y
 stupid/TMRYS
 stupidity/SM
 stupor/MS
 sturdily
 sturdiness/M
 sturdy/TRP
 sturgeon/SM
--- a/gfx/src/moz.build
+++ b/gfx/src/moz.build
@@ -1,17 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
     'nsIFontEnumerator.idl',
-    'nsIScriptableRegion.idl',
 ]
 
 XPIDL_MODULE = 'gfx'
 
 DEFINES['MOZ_APP_VERSION'] = '"%s"' % CONFIG['MOZ_APP_VERSION']
 
 EXPORTS += [
     'DriverCrashGuard.h',
@@ -63,17 +62,16 @@ UNIFIED_SOURCES += [
     'FilterSupport.cpp',
     'gfxCrashReporterUtils.cpp',
     'gfxTelemetry.cpp',
     'nsColor.cpp',
     'nsFont.cpp',
     'nsFontMetrics.cpp',
     'nsRect.cpp',
     'nsRegion.cpp',
-    'nsScriptableRegion.cpp',
     'nsThebesFontEnumerator.cpp',
     'nsThebesGfxFactory.cpp',
     'nsTransform2D.cpp',
     'TiledRegion.cpp',
 ]
 
 # nsDeviceContext.cpp cannot be built in unified mode because it pulls in OS X system headers.
 SOURCES += [
deleted file mode 100644
--- a/gfx/src/nsIScriptableRegion.idl
+++ /dev/null
@@ -1,176 +0,0 @@
-/* -*- Mode: IDL; 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 "nsISupports.idl"
-
-%{C++
-#include "nsRegionFwd.h"
-%}
-
-native nsIntRegion(nsIntRegion);
-
-
-[scriptable, uuid(a5f44cc7-2820-489b-b817-ae8a08506ff6)]
-interface nsIScriptableRegion : nsISupports
-{
-  void init ( ) ;
-
-  /**
-  * copy operator equivalent that takes another region
-  *
-  * @param      region to copy
-  * @return     void
-  *
-  **/
-
-  void setToRegion ( in nsIScriptableRegion aRegion );
-
-  /**
-  * copy operator equivalent that takes a rect
-  *
-  * @param      aX xoffset of rect to set region to
-  * @param      aY yoffset of rect to set region to
-  * @param      aWidth width of rect to set region to
-  * @param      aHeight height of rect to set region to
-  * @return     void
-  *
-  **/
-
-  void setToRect ( in long aX, in long aY, in long aWidth, in long aHeight );
-
-  /**
-  * destructively intersect another region with this one
-  *
-  * @param      region to intersect
-  * @return     void
-  *
-  **/
-
-  void intersectRegion ( in nsIScriptableRegion aRegion ) ;
-
-  /**
-  * destructively intersect a rect with this region
-  *
-  * @param      aX xoffset of rect to intersect with region
-  * @param      aY yoffset of rect to intersect with region
-  * @param      aWidth width of rect to intersect with region
-  * @param      aHeight height of rect to intersect with region
-  * @return     void
-  *
-  **/
-
-  void intersectRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
-
-  /**
-  * destructively union another region with this one
-  *
-  * @param      region to union
-  * @return     void
-  *
-  **/
-
-  void unionRegion ( in nsIScriptableRegion aRegion ) ;
-
-  /**
-  * destructively union a rect with this region
-  *
-  * @param      aX xoffset of rect to union with region
-  * @param      aY yoffset of rect to union with region
-  * @param      aWidth width of rect to union with region
-  * @param      aHeight height of rect to union with region
-  * @return     void
-  *
-  **/
-
-  void unionRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
-
-  /**
-  * destructively subtract another region with this one
-  *
-  * @param      region to subtract
-  * @return     void
-  *
-  **/
-
-  void subtractRegion ( in nsIScriptableRegion aRegion ) ;
-
-  /**
-  * destructively subtract a rect from this region
-  *
-  * @param      aX xoffset of rect to subtract with region
-  * @param      aY yoffset of rect to subtract with region
-  * @param      aWidth width of rect to subtract with region
-  * @param      aHeight height of rect to subtract with region
-  * @return     void
-  *
-  **/
-
-  void subtractRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
-  
-  /**
-  * is this region empty? i.e. does it contain any pixels
-  *
-  * @param      none
-  * @return     returns whether the region is empty
-  *
-  **/
-
-  boolean isEmpty ( ) ;
-
-  /**
-  * == operator equivalent i.e. do the regions contain exactly
-  * the same pixels
-  *
-  * @param      region to compare
-  * @return     whether the regions are identical
-  *
-  **/
-
-  boolean isEqualRegion ( in nsIScriptableRegion aRegion ) ;
-
-  /**
-  * returns the bounding box of the region i.e. the smallest
-  * rectangle that completely contains the region.        
-  *
-  * @param      aX out parameter for xoffset of bounding rect for region
-  * @param      aY out parameter for yoffset of bounding rect for region
-  * @param      aWidth out parameter for width of bounding rect for region
-  * @param      aHeight out parameter for height of bounding rect for region
-  * @return     void
-  *
-  **/
-  void getBoundingBox ( out long aX, out long aY, out long aWidth, out long aHeight ) ;
-
-  /**
-  * offsets the region in x and y
-  *
-  * @param  xoffset  pixel offset in x
-  * @param  yoffset  pixel offset in y
-  * @return          void
-  *
-  **/
-  void offset ( in long aXOffset, in long aYOffset ) ;
-
-  /**
-   * @return null if there are no rects,
-   * @return flat array of rects,ie [x1,y1,width1,height1,x2...].
-   * The result will contain bogus data if values don't fit in 31 bit
-   **/
-  [implicit_jscontext] jsval getRects();
-
-  /**
-  * does the region intersect the rectangle?
-  *
-  * @param      rect to check for containment
-  * @return     true if the region intersects the rect
-  *
-  **/
-
-  boolean containsRect ( in long aX, in long aY, in long aWidth, in long aHeight ) ;
-  
-  [noscript] readonly attribute nsIntRegion region;
-  
-};
deleted file mode 100644
--- a/gfx/src/nsScriptableRegion.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsScriptableRegion.h"
-#include <stdint.h>                     // for uint32_t
-#include <sys/types.h>                  // for int32_t
-#include "js/RootingAPI.h"              // for Rooted
-#include "js/Value.h"                   // for INT_TO_JSVAL, etc
-#include "jsapi.h"                      // for JS_DefineElement, etc
-#include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
-#include "nsError.h"                    // for NS_OK, NS_ERROR_FAILURE, etc
-#include "nsID.h"
-#include "nsRect.h"                     // for mozilla::gfx::IntRect
-#include "nscore.h"                     // for NS_IMETHODIMP
-
-class JSObject;
-struct JSContext;
-
-nsScriptableRegion::nsScriptableRegion()
-{
-}
-
-NS_IMPL_ISUPPORTS(nsScriptableRegion, nsIScriptableRegion)
-
-NS_IMETHODIMP nsScriptableRegion::Init()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::SetToRegion(nsIScriptableRegion *aRegion)
-{
-  aRegion->GetRegion(&mRegion);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::SetToRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
-{
-  mRegion = mozilla::gfx::IntRect(aX, aY, aWidth, aHeight);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::IntersectRegion(nsIScriptableRegion *aRegion)
-{
-  nsIntRegion region;
-  aRegion->GetRegion(&region);
-  mRegion.And(mRegion, region);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::IntersectRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
-{
-  mRegion.And(mRegion, mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::UnionRegion(nsIScriptableRegion *aRegion)
-{
-  nsIntRegion region;
-  aRegion->GetRegion(&region);
-  mRegion.Or(mRegion, region);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::UnionRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
-{
-  mRegion.Or(mRegion, mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::SubtractRegion(nsIScriptableRegion *aRegion)
-{
-  nsIntRegion region;
-  aRegion->GetRegion(&region);
-  mRegion.Sub(mRegion, region);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::SubtractRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight)
-{
-  mRegion.Sub(mRegion, mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::IsEmpty(bool *isEmpty)
-{
-  *isEmpty = mRegion.IsEmpty();
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::IsEqualRegion(nsIScriptableRegion *aRegion, bool *isEqual)
-{
-  nsIntRegion region;
-  aRegion->GetRegion(&region);
-  *isEqual = mRegion.IsEqual(region);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::GetBoundingBox(int32_t *aX, int32_t *aY, int32_t *aWidth, int32_t *aHeight)
-{
-  mozilla::gfx::IntRect boundRect = mRegion.GetBounds();
-  boundRect.GetRect(aX, aY, aWidth, aHeight);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::Offset(int32_t aXOffset, int32_t aYOffset)
-{
-  mRegion.MoveBy(aXOffset, aYOffset);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::ContainsRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, bool *containsRect)
-{
-  *containsRect = mRegion.Contains(mozilla::gfx::IntRect(aX, aY, aWidth, aHeight));
-  return NS_OK;
-}
-
-
-NS_IMETHODIMP nsScriptableRegion::GetRegion(nsIntRegion* outRgn)
-{
-  *outRgn = mRegion;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptableRegion::GetRects(JSContext* aCx, JS::MutableHandle<JS::Value> aRects)
-{
-  uint32_t numRects = mRegion.GetNumRects();
-
-  if (!numRects) {
-    aRects.setNull();
-    return NS_OK;
-  }
-
-  JS::Rooted<JSObject*> destArray(aCx, JS_NewArrayObject(aCx, numRects * 4));
-  if (!destArray) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  aRects.setObject(*destArray);
-
-  uint32_t n = 0;
-  for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
-    const mozilla::gfx::IntRect& rect = iter.Get();
-    if (!JS_DefineElement(aCx, destArray, n, rect.X(), JSPROP_ENUMERATE) ||
-        !JS_DefineElement(aCx, destArray, n + 1, rect.Y(), JSPROP_ENUMERATE) ||
-        !JS_DefineElement(aCx, destArray, n + 2, rect.Width(), JSPROP_ENUMERATE) ||
-        !JS_DefineElement(aCx, destArray, n + 3, rect.Height(), JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-    n += 4;
-  }
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/gfx/src/nsScriptableRegion.h
+++ /dev/null
@@ -1,28 +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 nsScriptableRegion_h
-#define nsScriptableRegion_h
-
-#include "nsIScriptableRegion.h"
-#include "nsISupports.h"
-#include "nsRegion.h"
-#include "mozilla/Attributes.h"
-
-class nsScriptableRegion final : public nsIScriptableRegion {
-public:
-	nsScriptableRegion();
-
-	NS_DECL_ISUPPORTS
-
-	NS_DECL_NSISCRIPTABLEREGION
-
-private:
-        ~nsScriptableRegion() {}
-	nsIntRegion mRegion;
-};
-
-#endif
--- a/gfx/src/nsThebesGfxFactory.cpp
+++ b/gfx/src/nsThebesGfxFactory.cpp
@@ -9,50 +9,30 @@
 #include "mozilla/Attributes.h"         // for final
 #include "mozilla/Module.h"             // for Module, Module::CIDEntry, etc
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsError.h"                    // for NS_ERROR_NO_AGGREGATION, etc
 #include "nsGfxCIID.h"                  // for NS_FONT_ENUMERATOR_CID, etc
 #include "nsID.h"                       // for NS_DEFINE_NAMED_CID, etc
-#include "nsIScriptableRegion.h"        // for nsIScriptableRegion
 #include "nsISupports.h"                // for NS_DECL_ISUPPORTS, etc
-#include "nsScriptableRegion.h"         // for nsScriptableRegion
 #include "nsThebesFontEnumerator.h"     // for nsThebesFontEnumerator
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesFontEnumerator)
 
-static nsresult
-nsScriptableRegionConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult)
-{
-  if (!aResult) {
-    return NS_ERROR_NULL_POINTER;
-  }
-  *aResult = nullptr;
-  if (aOuter) {
-    return NS_ERROR_NO_AGGREGATION;
-  }
-
-  nsCOMPtr<nsIScriptableRegion> scriptableRgn = new nsScriptableRegion();
-  return scriptableRgn->QueryInterface(aIID, aResult);
-}
-
 NS_DEFINE_NAMED_CID(NS_FONT_ENUMERATOR_CID);
-NS_DEFINE_NAMED_CID(NS_SCRIPTABLE_REGION_CID);
 
 static const mozilla::Module::CIDEntry kThebesCIDs[] = {
     { &kNS_FONT_ENUMERATOR_CID, false, nullptr, nsThebesFontEnumeratorConstructor },
-    { &kNS_SCRIPTABLE_REGION_CID, false, nullptr, nsScriptableRegionConstructor },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kThebesContracts[] = {
     { "@mozilla.org/gfx/fontenumerator;1", &kNS_FONT_ENUMERATOR_CID },
-    { "@mozilla.org/gfx/region;1", &kNS_SCRIPTABLE_REGION_CID },
     { nullptr }
 };
 
 static const mozilla::Module kThebesModule = {
     mozilla::Module::kVersion,
     kThebesCIDs,
     kThebesContracts,
     nullptr,
--- a/gfx/tests/moz.build
+++ b/gfx/tests/moz.build
@@ -1,10 +1,9 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
 BROWSER_CHROME_MANIFESTS += ['browser/browser.ini']
-MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
\ No newline at end of file
+MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
deleted file mode 100644
--- a/gfx/tests/unit/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
-  "extends": [
-    "plugin:mozilla/xpcshell-test"
-  ]
-};
deleted file mode 100644
--- a/gfx/tests/unit/test_nsIScriptableRegion.js
+++ /dev/null
@@ -1,10 +0,0 @@
-function run_test()
-{
-  let rgn = Cc["@mozilla.org/gfx/region;1"].createInstance(Ci.nsIScriptableRegion);
-  Assert.ok (rgn.getRects() === null)
-  rgn.unionRect(0,0,80,60);
-  Assert.ok (rgn.getRects().toString() == "0,0,80,60")
-  rgn.unionRect(90,70,1,1);
-  Assert.ok (rgn.getRects().toString() == "0,0,80,60,90,70,1,1")
-}
-
deleted file mode 100644
--- a/gfx/tests/unit/xpcshell.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-head = 
-
-[test_nsIScriptableRegion.js]
--- a/ipc/chromium/src/base/atomicops.h
+++ b/ipc/chromium/src/base/atomicops.h
@@ -93,16 +93,30 @@ Atomic32 Barrier_AtomicIncrement(volatil
 // access.
 Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
                                 Atomic32 old_value,
                                 Atomic32 new_value);
 Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
                                 Atomic32 old_value,
                                 Atomic32 new_value);
 
+// On AArch64 Windows, MemoryBarrier is defined as:
+//
+// #define MemoryBarrier()             __dmb(_ARM_BARRIER_SY)
+//
+// which wreaks havoc with the declaration below.  Capture the definition
+// before undefining the macro.
+#if defined(_M_ARM64) && defined(MemoryBarrier)
+static inline void
+MemoryBarrierARM64()
+{
+  MemoryBarrier();
+}
+#undef MemoryBarrier
+#endif
 void MemoryBarrier();
 void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
 void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
 void Release_Store(volatile Atomic32* ptr, Atomic32 value);
 
 Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
 Atomic32 Acquire_Load(volatile const Atomic32* ptr);
 Atomic32 Release_Load(volatile const Atomic32* ptr);
@@ -131,16 +145,19 @@ Atomic64 Release_Load(volatile const Ato
 #endif  // CPU_ARCH_64_BITS
 
 }  // namespace base::subtle
 }  // namespace base
 
 // Include our platform specific implementation.
 #if defined(OS_WIN) && defined(ARCH_CPU_X86_FAMILY)
 #include "base/atomicops_internals_x86_msvc.h"
+#elif defined(OS_WIN) && defined(ARCH_CPU_AARCH64_FAMILY)
+// Works just fine, separate case in case we need to change things.
+#include "base/atomicops_internals_x86_msvc.h"
 #elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY)
 #include "base/atomicops_internals_x86_macosx.h"
 #elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
 #include "base/atomicops_internals_x86_gcc.h"
 #elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
 #include "base/atomicops_internals_arm_gcc.h"
 #elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
 #include "base/atomicops_internals_arm64_gcc.h"
--- a/ipc/chromium/src/base/atomicops_internals_x86_msvc.h
+++ b/ipc/chromium/src/base/atomicops_internals_x86_msvc.h
@@ -40,18 +40,23 @@ inline Atomic32 Barrier_AtomicIncrement(
 }
 
 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
                                           Atomic32 increment) {
   return Barrier_AtomicIncrement(ptr, increment);
 }
 
 inline void MemoryBarrier() {
-  // We use MemoryBarrier from WinNT.h
+  // We use MemoryBarrier from WinNT.h, except for AArch64.
+  // See the comment in atomicops.h.
+#if defined(_M_ARM64)
+  MemoryBarrierARM64();
+#else
   ::MemoryBarrier();
+#endif
 }
 
 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
                                        Atomic32 old_value,
                                        Atomic32 new_value) {
   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
 }
 
--- a/ipc/mscom/SpinEvent.cpp
+++ b/ipc/mscom/SpinEvent.cpp
@@ -8,25 +8,16 @@
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/TimeStamp.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsSystemInfo.h"
 
-// This gives us compiler intrinsics for the x86 PAUSE instruction
-#if defined(_MSC_VER)
-#include <intrin.h>
-#pragma intrinsic(_mm_pause)
-#define CPU_PAUSE() _mm_pause()
-#elif defined(__GNUC__) || defined(__clang__)
-#define CPU_PAUSE() __builtin_ia32_pause()
-#endif
-
 namespace mozilla {
 namespace mscom {
 
 static const TimeDuration kMaxSpinTime = TimeDuration::FromMilliseconds(30);
 bool SpinEvent::sIsMulticore = false;
 
 /* static */ bool
 SpinEvent::InitStatics()
@@ -63,20 +54,17 @@ SpinEvent::Wait(HANDLE aTargetThread)
     // entire time. At that point, a few extra ms isn't going to make much
     // difference to perceived responsiveness.
     TimeStamp start(TimeStamp::Now());
     while (!mDone) {
       TimeDuration elapsed(TimeStamp::Now() - start);
       if (elapsed >= kMaxSpinTime) {
         break;
       }
-      // The PAUSE instruction is a hint to the CPU that we're doing a spin
-      // loop. It is a no-op on older processors that don't support it, so
-      // it is safe to use here without any CPUID checks.
-      CPU_PAUSE();
+      YieldProcessor();
     }
     if (mDone) {
       return true;
     }
   }
 
   MOZ_ASSERT(mDoneEvent);
   HANDLE handles[] = {mDoneEvent, aTargetThread};
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -588,23 +588,16 @@ template <class T>
 static MOZ_ALWAYS_INLINE T*
 js_pod_malloc(size_t numElems)
 {
     return js_pod_arena_malloc<T>(js::MallocArena, numElems);
 }
 
 template <class T>
 static MOZ_ALWAYS_INLINE T*
-js_pod_malloc()
-{
-    return js_pod_malloc<T>(sizeof(T));
-}
-
-template <class T>
-static MOZ_ALWAYS_INLINE T*
 js_pod_arena_calloc(arena_id_t arena, size_t numElems)
 {
     size_t bytes;
     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
         return nullptr;
     return static_cast<T*>(js_arena_calloc(arena, bytes, 1));
 }
 
@@ -612,23 +605,16 @@ template <class T>
 static MOZ_ALWAYS_INLINE T*
 js_pod_calloc(size_t numElems)
 {
     return js_pod_arena_calloc<T>(js::MallocArena, numElems);
 }
 
 template <class T>
 static MOZ_ALWAYS_INLINE T*
-js_pod_calloc()
-{
-    return js_pod_calloc<T>(sizeof(T));
-}
-
-template <class T>
-static MOZ_ALWAYS_INLINE T*
 js_pod_realloc(T* prior, size_t oldSize, size_t newSize)
 {
     MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
     size_t bytes;
     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
         return nullptr;
     return static_cast<T*>(js_realloc(prior, bytes));
 }
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -936,20 +936,20 @@ obj_isPrototypeOf(JSContext* cx, unsigne
     }
 
     /* Step 2. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 3. */
-    bool isDelegate;
-    if (!IsDelegate(cx, obj, args[0], &isDelegate))
+    bool isPrototype;
+    if (!IsPrototypeOf(cx, obj, &args[0].toObject(), &isPrototype))
         return false;
-    args.rval().setBoolean(isDelegate);
+    args.rval().setBoolean(isPrototype);
     return true;
 }
 
 PlainObject*
 js::ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind,
                      HandleObjectGroup group)
 {
     // Give the new object a small number of fixed slots, like we do for empty
--- a/js/src/builtin/Symbol.cpp
+++ b/js/src/builtin/Symbol.cpp
@@ -26,16 +26,17 @@ SymbolObject::create(JSContext* cx, JS::
     SymbolObject* obj = NewBuiltinClassInstance<SymbolObject>(cx);
     if (!obj)
         return nullptr;
     obj->setPrimitiveValue(symbol);
     return obj;
 }
 
 const JSPropertySpec SymbolObject::properties[] = {
+    JS_PSG("description", descriptionGetter, 0),
     JS_PS_END
 };
 
 const JSFunctionSpec SymbolObject::methods[] = {
     JS_FN(js_toString_str, toString, 0, 0),
     JS_FN(js_valueOf_str, valueOf, 0, 0),
     JS_SYM_FN(toPrimitive, toPrimitive, 1, JSPROP_READONLY),
     JS_FS_END
@@ -226,16 +227,41 @@ SymbolObject::toPrimitive(JSContext* cx,
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // The specification gives exactly the same algorithm for @@toPrimitive as
     // for valueOf, so reuse the valueOf implementation.
     return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args);
 }
 
+bool
+SymbolObject::descriptionGetter_impl(JSContext* cx, const CallArgs& args)
+{
+    // Get symbol object pointer.
+    HandleValue thisv = args.thisv();
+    MOZ_ASSERT(IsSymbol(thisv));
+    Rooted<Symbol*> sym(cx, thisv.isSymbol()
+                            ? thisv.toSymbol()
+                            : thisv.toObject().as<SymbolObject>().unbox());
+
+    // Return the symbol's description if present, otherwise return undefined.
+    if (JSString* str = sym->description())
+        args.rval().setString(str);
+    else
+        args.rval().setUndefined();
+    return true;
+}
+
+bool
+SymbolObject::descriptionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsSymbol, descriptionGetter_impl>(cx, args);
+}
+
 JSObject*
 js::InitSymbolClass(JSContext* cx, Handle<GlobalObject*> global)
 {
     return SymbolObject::initClass(cx, global, true);
 }
 
 JSObject*
 js::InitBareSymbolCtor(JSContext* cx, Handle<GlobalObject*> global)
--- a/js/src/builtin/Symbol.h
+++ b/js/src/builtin/Symbol.h
@@ -49,16 +49,20 @@ class SymbolObject : public NativeObject
 
     // Methods defined on Symbol.prototype.
     static MOZ_MUST_USE bool toString_impl(JSContext* cx, const CallArgs& args);
     static MOZ_MUST_USE bool toString(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool valueOf_impl(JSContext* cx, const CallArgs& args);
     static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp);
 
+    // Properties defined on Symbol.prototype.
+    static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx, const CallArgs& args);
+    static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc, Value *vp);
+
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     static const JSFunctionSpec staticMethods[];
 };
 
 extern JSObject*
 InitSymbolClass(JSContext* cx, Handle<GlobalObject*> global);
 
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1208,17 +1208,17 @@ function TypedArraySort(comparefn) {
         }
         return QuickSort(obj, len, TypedArrayCompare);
     }
 
     // To satisfy step 2 from TypedArray SortCompare described in 22.2.3.26
     // the user supplied comparefn is wrapped.
     var wrappedCompareFn = function(x, y) {
         // Step a.
-        var v = comparefn(x, y);
+        var v = +comparefn(x, y);
 
         // Step b.
         var length;
         if (isTypedArray) {
             length = TypedArrayLength(obj);
         } else {
             length = callFunction(CallTypedArrayMethodIfWrapped, obj, "TypedArrayLengthMethod");
         }
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -358,19 +358,21 @@ AtomicOperations::isLockfreeJS(int32_t s
 #  error "No AtomicOperations support for this platform+compiler combination"
 # endif
 #elif defined(__arm__)
 # if defined(__clang__) || defined(__GNUC__)
 #  include "jit/arm/AtomicOperations-arm.h"
 # else
 #  error "No AtomicOperations support for this platform+compiler combination"
 # endif
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || defined(_M_ARM64)
 # if defined(__clang__) || defined(__GNUC__)
-#  include "jit/arm64/AtomicOperations-arm64.h"
+#  include "jit/arm64/AtomicOperations-arm64-gcc.h"
+# elif defined(_MSC_VER)
+#  include "jit/arm64/AtomicOperations-arm64-msvc.h"
 # else
 #  error "No AtomicOperations support for this platform+compiler combination"
 # endif
 #elif defined(__mips__)
 # if defined(__clang__) || defined(__GNUC__)
 #  include "jit/mips-shared/AtomicOperations-mips-shared.h"
 # else
 #  error "No AtomicOperations support for this platform+compiler combination"
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -12030,26 +12030,19 @@ CodeGenerator::visitInstanceOfO(LInstanc
 }
 
 void
 CodeGenerator::visitInstanceOfV(LInstanceOfV* ins)
 {
     emitInstanceOf(ins, ins->mir()->prototypeObject());
 }
 
-// Wrap IsDelegateOfObject, which takes a JSObject*, not a HandleObject
-static bool
-IsDelegateObject(JSContext* cx, HandleObject protoObj, HandleObject obj, bool* res)
-{
-    return IsDelegateOfObject(cx, protoObj, obj, res);
-}
-
-typedef bool (*IsDelegateObjectFn)(JSContext*, HandleObject, HandleObject, bool*);
-static const VMFunction IsDelegateObjectInfo =
-    FunctionInfo<IsDelegateObjectFn>(IsDelegateObject, "IsDelegateObject");
+typedef bool (*IsPrototypeOfFn)(JSContext*, HandleObject, JSObject*, bool*);
+static const VMFunction IsPrototypeOfInfo =
+    FunctionInfo<IsPrototypeOfFn>(IsPrototypeOf, "IsPrototypeOf");
 
 void
 CodeGenerator::emitInstanceOf(LInstruction* ins, JSObject* prototypeObject)
 {
     // This path implements fun_hasInstance when the function's prototype is
     // known to be prototypeObject.
 
     Label done;
@@ -12065,17 +12058,17 @@ CodeGenerator::emitInstanceOf(LInstructi
         masm.jump(&done);
         masm.bind(&isObject);
         objReg = masm.extractObject(lhsValue, output);
     } else {
         objReg = ToRegister(ins->toInstanceOfO()->lhs());
     }
 
     // Crawl the lhs's prototype chain in a loop to search for prototypeObject.
-    // This follows the main loop of js::IsDelegate, though additionally breaks
+    // This follows the main loop of js::IsPrototypeOf, though additionally breaks
     // out of the loop on Proxy::LazyProto.
 
     // Load the lhs's prototype.
     masm.loadObjProto(objReg, output);
 
     Label testLazy;
     {
         Label loopPrototypeChain;
@@ -12100,17 +12093,17 @@ CodeGenerator::emitInstanceOf(LInstructi
     }
 
     // Make a VM call if an object with a lazy proto was found on the prototype
     // chain. This currently occurs only for cross compartment wrappers, which
     // we do not expect to be compared with non-wrapper functions from this
     // compartment. Otherwise, we stopped on a nullptr prototype and the output
     // register is already correct.
 
-    OutOfLineCode* ool = oolCallVM(IsDelegateObjectInfo, ins,
+    OutOfLineCode* ool = oolCallVM(IsPrototypeOfInfo, ins,
                                    ArgList(ImmGCPtr(prototypeObject), objReg),
                                    StoreRegisterTo(output));
 
     // Regenerate the original lhs object for the VM call.
     Label regenerate, *lazyEntry;
     if (objReg != output) {
         lazyEntry = ool->entry();
     } else {
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -12973,17 +12973,17 @@ IonBuilder::hasOnProtoChain(TypeSet::Obj
     }
 
     MOZ_CRASH("Unreachable");
 }
 
 AbortReasonOr<Ok>
 IonBuilder::tryFoldInstanceOf(bool* emitted, MDefinition* lhs, JSObject* protoObject)
 {
-    // Try to fold the js::IsDelegate part of the instanceof operation.
+    // Try to fold the js::IsPrototypeOf part of the instanceof operation.
     MOZ_ASSERT(*emitted == false);
 
     if (!lhs->mightBeType(MIRType::Object)) {
         // If the lhs is a primitive, the result is false.
         lhs->setImplicitlyUsedUnchecked();
         pushConstant(BooleanValue(false));
         *emitted = true;
         return Ok();
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1405,24 +1405,24 @@ GetPcScript(JSContext* cx, JSScript** sc
         retAddr = it.frame().returnAddress();
     }
 
     uint32_t hash;
     if (retAddr) {
         hash = PcScriptCache::Hash(retAddr);
 
         // Lazily initialize the cache. The allocation may safely fail and will not GC.
-        if (MOZ_UNLIKELY(cx->ionPcScriptCache == nullptr)) {
-            cx->ionPcScriptCache = js_pod_malloc<PcScriptCache>();
-            if (cx->ionPcScriptCache)
-                cx->ionPcScriptCache->clear(cx->runtime()->gc.gcNumber());
+        if (MOZ_UNLIKELY(cx->ionPcScriptCache == nullptr))
+            cx->ionPcScriptCache = MakeUnique<PcScriptCache>(cx->runtime()->gc.gcNumber());
+
+        if (cx->ionPcScriptCache.ref() &&
+            cx->ionPcScriptCache->get(cx->runtime(), hash, retAddr, scriptRes, pcRes))
+        {
+            return;
         }
-
-        if (cx->ionPcScriptCache && cx->ionPcScriptCache->get(cx->runtime(), hash, retAddr, scriptRes, pcRes))
-            return;
     }
 
     // Lookup failed: undertake expensive process to recover the innermost inlined frame.
     jsbytecode* pc = nullptr;
     if (it.frame().isIonJS() || it.frame().isBailoutJS()) {
         InlineFrameIterator ifi(cx, &it.frame());
         *scriptRes = ifi.script();
         pc = ifi.pc();
@@ -1430,17 +1430,17 @@ GetPcScript(JSContext* cx, JSScript** sc
         MOZ_ASSERT(it.frame().isBaselineJS());
         it.frame().baselineScriptAndPc(scriptRes, &pc);
     }
 
     if (pcRes)
         *pcRes = pc;
 
     // Add entry to cache.
-    if (retAddr && cx->ionPcScriptCache)
+    if (retAddr && cx->ionPcScriptCache.ref())
         cx->ionPcScriptCache->add(hash, retAddr, pc, *scriptRes);
 }
 
 uint32_t
 OsiIndex::returnPointDisplacement() const
 {
     // In general, pointer arithmetic on code is bad, but in this case,
     // getting the return address from a call instruction, stepping over pools
--- a/js/src/jit/PcScriptCache.h
+++ b/js/src/jit/PcScriptCache.h
@@ -20,26 +20,32 @@ struct PcScriptCacheEntry
 {
     uint8_t* returnAddress; // Key into the hash table.
     jsbytecode* pc;         // Cached PC.
     JSScript* script;       // Cached script.
 };
 
 struct PcScriptCache
 {
+  private:
     static const uint32_t Length = 73;
 
     // GC number at the time the cache was filled or created.
     // Storing and checking against this number allows us to not bother
     // clearing this cache on every GC -- only when actually necessary.
     uint64_t gcNumber;
 
     // List of cache entries.
     mozilla::Array<PcScriptCacheEntry, Length> entries;
 
+  public:
+    explicit PcScriptCache(uint64_t gcNumber) {
+        clear(gcNumber);
+    }
+
     void clear(uint64_t gcNumber) {
         for (uint32_t i = 0; i < Length; i++)
             entries[i].returnAddress = nullptr;
         this->gcNumber = gcNumber;
     }
 
     // Get a value from the cache. May perform lazy allocation.
     MOZ_MUST_USE bool get(JSRuntime* rt, uint32_t hash, uint8_t* addr,
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -1248,18 +1248,19 @@ class Redirection
         Redirection* current = SimulatorProcess::redirection();
         for (; current != nullptr; current = current->next_) {
             if (current->nativeFunction_ == nativeFunction) {
                 MOZ_ASSERT(current->type() == type);
                 return current;
             }
         }
 
+        // Note: we can't use js_new here because the constructor is private.
         AutoEnterOOMUnsafeRegion oomUnsafe;
-        Redirection* redir = js_pod_malloc<Redirection>();
+        Redirection* redir = js_pod_malloc<Redirection>(1);
         if (!redir)
             oomUnsafe.crash("Simulator redirection");
         new(redir) Redirection(nativeFunction, type);
         return redir;
     }
 
     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
         uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
rename from js/src/jit/arm64/AtomicOperations-arm64.h
rename to js/src/jit/arm64/AtomicOperations-arm64-gcc.h
copy from js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
copy to js/src/jit/arm64/AtomicOperations-arm64-msvc.h
--- a/js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
+++ b/js/src/jit/arm64/AtomicOperations-arm64-msvc.h
@@ -56,17 +56,17 @@ js::jit::AtomicOperations::isLockfree8()
 
     return true;
 }
 
 inline void
 js::jit::AtomicOperations::fenceSeqCst()
 {
     _ReadWriteBarrier();
-    _mm_mfence();
+    MemoryBarrier();
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::loadSeqCst(T* addr)
 {
     MOZ_ASSERT(tier1Constraints(addr));
     _ReadWriteBarrier();
--- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
@@ -383,18 +383,19 @@ class Redirection
     Redirection* current = SimulatorProcess::redirection();
     for (; current != nullptr; current = current->next_) {
       if (current->nativeFunction_ == nativeFunction) {
         VIXL_ASSERT(current->type() == type);
         return current;
       }
     }
 
+    // Note: we can't use js_new here because the constructor is private.
     js::AutoEnterOOMUnsafeRegion oomUnsafe;
-    Redirection* redir = js_pod_malloc<Redirection>();
+    Redirection* redir = js_pod_malloc<Redirection>(1);
     if (!redir)
         oomUnsafe.crash("Simulator redirection");
     new(redir) Redirection(nativeFunction, type);
     return redir;
   }
 
   static const Redirection* FromSvcInstruction(const Instruction* svcInstruction) {
     const uint8_t* addrOfSvc = reinterpret_cast<const uint8_t*>(svcInstruction);
--- a/js/src/jit/mips32/Simulator-mips32.cpp
+++ b/js/src/jit/mips32/Simulator-mips32.cpp
@@ -1338,18 +1338,19 @@ class Redirection
         Redirection* current = SimulatorProcess::redirection();
         for (; current != nullptr; current = current->next_) {
             if (current->nativeFunction_ == nativeFunction) {
                 MOZ_ASSERT(current->type() == type);
                 return current;
             }
         }
 
+        // Note: we can't use js_new here because the constructor is private.
         AutoEnterOOMUnsafeRegion oomUnsafe;
-        Redirection* redir = js_pod_malloc<Redirection>();
+        Redirection* redir = js_pod_malloc<Redirection>(1);
         if (!redir) {
             oomUnsafe.crash("Simulator redirection");
         }
         new(redir) Redirection(nativeFunction, type);
         return redir;
     }
 
     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
--- a/js/src/jit/mips64/Simulator-mips64.cpp
+++ b/js/src/jit/mips64/Simulator-mips64.cpp
@@ -1346,18 +1346,19 @@ class Redirection
         Redirection* current = SimulatorProcess::redirection();
         for (; current != nullptr; current = current->next_) {
             if (current->nativeFunction_ == nativeFunction) {
                 MOZ_ASSERT(current->type() == type);
                 return current;
             }
         }
 
+        // Note: we can't use js_new here because the constructor is private.
         AutoEnterOOMUnsafeRegion oomUnsafe;
-        Redirection* redir = js_pod_malloc<Redirection>();
+        Redirection* redir = js_pod_malloc<Redirection>(1);
         if (!redir) {
             oomUnsafe.crash("Simulator redirection");
         }
         new(redir) Redirection(nativeFunction, type);
         return redir;
     }
 
     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
--- a/js/src/jit/shared/Disassembler-shared.cpp
+++ b/js/src/jit/shared/Disassembler-shared.cpp
@@ -232,17 +232,17 @@ DisassemblerSpew::lookup(const Label* ke
         ;
     return p;
 }
 
 DisassemblerSpew::Node*
 DisassemblerSpew::add(const Label* key, uint32_t value)
 {
     MOZ_ASSERT(!lookup(key));
-    Node* node = js_pod_malloc<Node>();
+    Node* node = js_new<Node>();
     if (node) {
         node->key = key;
         node->value = value;
         node->bound = false;
         node->next = nodes_;
         nodes_ = node;
     }
     return node;
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_x64_MacroAssembler_x64_h
 #define jit_x64_MacroAssembler_x64_h
 
 #include "jit/JitFrames.h"
 #include "jit/MoveResolver.h"
 #include "jit/x86-shared/MacroAssembler-x86-shared.h"
+#include "js/HeapAPI.h"
 
 namespace js {
 namespace jit {
 
 struct ImmShiftedTag : public ImmWord
 {
     explicit ImmShiftedTag(JSValueShiftedTag shtag)
       : ImmWord((uintptr_t)shtag)
@@ -158,16 +159,30 @@ class MacroAssemblerX64 : public MacroAs
     template <typename T>
     void storeValue(JSValueType type, Register reg, const T& dest) {
         // Value types with 32-bit payloads can be emitted as two 32-bit moves.
         if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
             movl(reg, Operand(dest));
             movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest)));
         } else {
             ScratchRegisterScope scratch(asMasm());
+#ifdef NIGHTLY_BUILD
+            // Bug 1485209 - Diagnostic assert for constructing Values with
+            // nullptr or misaligned (eg poisoned) JSObject/JSString pointers.
+            if (type == JSVAL_TYPE_OBJECT || type == JSVAL_TYPE_STRING) {
+                Label crash, ok;
+                testPtr(reg, Imm32(js::gc::CellAlignMask));
+                j(Assembler::NonZero, &crash);
+                testPtr(reg, reg);
+                j(Assembler::NonZero, &ok);
+                bind(&crash);
+                breakpoint();
+                bind(&ok);
+            }
+#endif
             boxValue(type, reg, scratch);
             movq(scratch, Operand(dest));
         }
     }
     template <typename T>
     void storeValue(const Value& val, const T& dest) {
         ScratchRegisterScope scratch(asMasm());
         if (val.isGCThing()) {
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_x86_MacroAssembler_x86_h
 #define jit_x86_MacroAssembler_x86_h
 
 #include "jit/JitFrames.h"
 #include "jit/MoveResolver.h"
 #include "jit/x86-shared/MacroAssembler-x86-shared.h"
+#include "js/HeapAPI.h"
 #include "vm/Realm.h"
 
 namespace js {
 namespace jit {
 
 // See documentation for ScratchTagScope and ScratchTagScopeRelease in
 // MacroAssembler-x64.h.
 
@@ -144,16 +145,30 @@ class MacroAssemblerX86 : public MacroAs
         movl(val.payloadReg(), ToPayload(dest));
         movl(val.typeReg(), ToType(dest));
     }
     void storeValue(ValueOperand val, const Address& dest) {
         storeValue(val, Operand(dest));
     }
     template <typename T>
     void storeValue(JSValueType type, Register reg, const T& dest) {
+#ifdef NIGHTLY_BUILD
+        // Bug 1485209 - Diagnostic assert for constructing Values with
+        // nullptr or misaligned (eg poisoned) JSObject/JSString pointers.
+        if (type == JSVAL_TYPE_OBJECT || type == JSVAL_TYPE_STRING) {
+            Label crash, ok;
+            testPtr(reg, Imm32(js::gc::CellAlignMask));
+            j(Assembler::NonZero, &crash);
+            testPtr(reg, reg);
+            j(Assembler::NonZero, &ok);
+            bind(&crash);
+            breakpoint();
+            bind(&ok);
+        }
+#endif
         storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest));
         storePayload(reg, Operand(dest));
     }
     template <typename T>
     void storeValue(const Value& val, const T& dest) {
         storeTypeTag(ImmTag(val.toNunboxTag()), Operand(dest));
         storePayload(val, Operand(dest));
     }
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1104,17 +1104,17 @@ then
     LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}"
 fi
 
 
 dnl Checks for library functions.
 dnl ========================================================
 AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
-AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r pthread_getname_np])
+AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r pthread_getname_np pthread_get_name_np])
 
 dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
 dnl avoid this on Darwin, since depending on your system config, we may think
 dnl it exists but it really doesn't
 case "$OS_TARGET" in
 Darwin)
   ;;
 *)
--- a/js/src/tests/test262-update.py
+++ b/js/src/tests/test262-update.py
@@ -25,17 +25,16 @@ UNSUPPORTED_FEATURES = set([
     "regexp-dotall",
     "regexp-lookbehind",
     "regexp-named-groups",
     "regexp-unicode-property-escapes",
     "numeric-separator-literal",
     "Intl.Locale",
     "String.prototype.matchAll",
     "Symbol.matchAll",
-    "Symbol.prototype.description",
     "global",
     "export-star-as-namespace-from-module",
 ])
 FEATURE_CHECK_NEEDED = {
     "Atomics": "!this.hasOwnProperty('Atomics')",
     "BigInt": "!this.hasOwnProperty('BigInt')",
     "SharedArrayBuffer": "!this.hasOwnProperty('SharedArrayBuffer')",
 }
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/description-symboldescriptivestring.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/description-symboldescriptivestring.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright (C) 2018 Rick Waldron. All rights reserved.
 // Copyright (C) 2018 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-symbol.prototype.description
 description: >
   SymbolDescriptiveString(sym) via Symbol.prototype.toString()
 info: |
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/descriptor.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/descriptor.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright 2018 Igalia, S.L. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-symbol.prototype.description
 description: >
     Test the descriptor of Symbol.prototype.description.
 info: |
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/get.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/get.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright 2018 Igalia, S.L. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-symbol.prototype.description
 description: >
     Test the get accessor function of Symbol.prototype.description.
 info: |
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/is-not-own-property.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/is-not-own-property.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright 2018 Igalia, S.L. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-symbol.prototype.description
 description: Ensure that 'description' is not an own property of Symbols
 features: [Symbol.prototype.description]
 ---*/
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/this-val-non-symbol.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/this-val-non-symbol.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright 2018 Igalia, S.L. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-symbol.prototype.description
 description: >
     Behavior when "this" value is an object without a [[SymbolData]] internal
     slot.
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/this-val-symbol.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/this-val-symbol.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright 2018 Igalia, S.L. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-symbol.prototype.description
 description: >
     Test that calling the getter on a Symbol or a Symbol wrapper object works.
 info: |
--- a/js/src/tests/test262/built-ins/Symbol/prototype/description/wrapper.js
+++ b/js/src/tests/test262/built-ins/Symbol/prototype/description/wrapper.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Symbol.prototype.description is not supported
 // Copyright 2018 Igalia, S.L. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-symbol.prototype.description
 description: >
     Test Symbol.prototype.description called on wrapper objects.
 info: |
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/TypedArray/prototype/sort/sort-tonumber.js
@@ -0,0 +1,39 @@
+// Copyright (C) 2018 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-%typedarray%.prototype.sort
+description: The result of compareFn is immediately passed through ToNumber
+info: |
+  22.2.3.26 %TypedArray%.prototype.sort ( comparefn )
+
+  ...
+  2. If comparefn is not undefined, then
+    a. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
+    b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
+    ...
+  ...
+includes: [testTypedArray.js, detachArrayBuffer.js]
+features: [TypedArray]
+---*/
+
+testWithTypedArrayConstructors(function(TA) {
+  var ta = new TA(4);
+  var ab = ta.buffer;
+
+  var called = false;
+  assert.throws(TypeError, function() {
+    ta.sort(function(a, b) {
+      // IsDetachedBuffer is checked right after calling comparefn.
+      // So, detach the ArrayBuffer to cause sort to throw, to make sure we're actually calling ToNumber immediately (as spec'd)
+      // (a possible bug is to wait until the result is inspected to call ToNumber, rather than immediately)
+      $DETACHBUFFER(ab);
+      return {
+        [Symbol.toPrimitive]() { called = true; }
+      };
+    });
+  });
+
+  assert.sameValue(true, called);
+});
+
+reportCompare(0, 0);
--- a/js/src/threading/ProtectedData.h
+++ b/js/src/threading/ProtectedData.h
@@ -82,16 +82,19 @@ class ProtectedData
     DECLARE_BOOL_OPERATORS(T)
 
     operator const T&() const { return ref(); }
     const T& operator->() const { return ref(); }
 
     template <typename U>
     ThisType& operator=(const U& p) { this->ref() = p; return *this; }
 
+    template <typename U>
+    ThisType& operator=(U&& p) { this->ref() = std::move(p); return *this; }
+
     template <typename U> T& operator +=(const U& rhs) { return ref() += rhs; }
     template <typename U> T& operator -=(const U& rhs) { return ref() -= rhs; }
     template <typename U> T& operator *=(const U& rhs) { return ref() *= rhs; }
     template <typename U> T& operator /=(const U& rhs) { return ref() /= rhs; }
     template <typename U> T& operator &=(const U& rhs) { return ref() &= rhs; }
     template <typename U> T& operator |=(const U& rhs) { return ref() |= rhs; }
     T& operator ++() { return ++ref(); }
     T& operator --() { return --ref(); }
@@ -127,42 +130,40 @@ class ProtectedData
     Check check;
 #endif
 };
 
 // Intermediate class for protected data whose checks take no constructor arguments.
 template <typename Check, typename T>
 class ProtectedDataNoCheckArgs : public ProtectedData<Check, T>
 {
-    typedef ProtectedDataNoCheckArgs<Check, T> ThisType;
+    using Base = ProtectedData<Check, T>;
 
   public:
     template <typename... Args>
     explicit ProtectedDataNoCheckArgs(Args&&... args)
       : ProtectedData<Check, T>(Check(), std::forward<Args>(args)...)
     {}
 
-    template <typename U>
-    ThisType& operator=(const U& p) { this->ref() = p; return *this; }
+    using Base::operator=;
 };
 
 // Intermediate class for protected data whose checks take a Zone constructor argument.
 template <typename Check, typename T>
 class ProtectedDataZoneArg : public ProtectedData<Check, T>
 {
-    typedef ProtectedDataZoneArg<Check, T> ThisType;
+    using Base = ProtectedData<Check, T>;
 
   public:
     template <typename... Args>
     explicit ProtectedDataZoneArg(JS::Zone* zone, Args&&... args)
       : ProtectedData<Check, T>(Check(zone), std::forward<Args>(args)...)
     {}
 
-    template <typename U>
-    ThisType& operator=(const U& p) { this->ref() = p; return *this; }
+    using Base::operator=;
 };
 
 class CheckUnprotected
 {
 #ifdef JS_HAS_PROTECTED_DATA_CHECKS
   public:
     inline void check() const {}
 #endif
--- a/js/src/threading/posix/Thread.cpp
+++ b/js/src/threading/posix/Thread.cpp
@@ -203,15 +203,18 @@ js::ThisThread::SetName(const char* name
 void
 js::ThisThread::GetName(char* nameBuffer, size_t len)
 {
   MOZ_RELEASE_ASSERT(len >= 16);
 
   int rv = -1;
 #ifdef HAVE_PTHREAD_GETNAME_NP
   rv = pthread_getname_np(pthread_self(), nameBuffer, len);
+#elif defined(HAVE_PTHREAD_GET_NAME_NP)
+  pthread_get_name_np(pthread_self(), nameBuffer, len);
+  rv = 0;
 #elif defined(__linux__)
   rv = prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(nameBuffer));
 #endif
 
   if (rv)
     nameBuffer[0] = '\0';
 }
--- a/js/src/vm/BigIntType.cpp
+++ b/js/src/vm/BigIntType.cpp
@@ -404,26 +404,32 @@ js::ToBigInt(JSContext* cx, HandleValue 
 {
     RootedValue v(cx, val);
 
     // Step 1.
     if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
         return nullptr;
 
     // Step 2.
-    // String conversions are not yet supported.
     if (v.isBigInt())
         return v.toBigInt();
 
     if (v.isBoolean())
         return BigInt::createFromBoolean(cx, v.toBoolean());
 
     if (v.isString()) {
         RootedString str(cx, v.toString());
-        return StringToBigInt(cx, str, 0);
+        BigInt* bi;
+        JS_TRY_VAR_OR_RETURN_NULL(cx, bi, StringToBigInt(cx, str, 0));
+        if (!bi) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+                                      JSMSG_BIGINT_INVALID_SYNTAX);
+            return nullptr;
+        }
+        return bi;
     }
 
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_BIGINT);
     return nullptr;
 }
 
 // ES 2019 draft 6.1.6
 double
@@ -432,16 +438,75 @@ BigInt::numberValue(BigInt* x)
     // mpz_get_d may cause a hardware overflow trap, so use
     // mpz_get_d_2exp to get the fractional part and exponent
     // separately.
     signed long int exp;
     double d = mpz_get_d_2exp(&exp, x->num_);
     return ldexp(d, exp);
 }
 
+bool
+BigInt::equal(BigInt* lhs, BigInt* rhs)
+{
+    if (lhs == rhs)
+        return true;
+    if (mpz_cmp(lhs->num_, rhs->num_) == 0)
+        return true;
+    return false;
+}
+
+bool
+BigInt::equal(BigInt* lhs, double rhs)
+{
+    // The result of mpz_cmp_d is undefined for comparisons to NaN.
+    if (mozilla::IsNaN(rhs))
+        return false;
+    if (mpz_cmp_d(lhs->num_, rhs) == 0)
+        return true;
+    return false;
+}
+
+// BigInt proposal section 3.2.5
+JS::Result<bool>
+BigInt::looselyEqual(JSContext* cx, HandleBigInt lhs, HandleValue rhs)
+{
+    // Step 1.
+    if (rhs.isBigInt())
+        return equal(lhs, rhs.toBigInt());
+
+    // Steps 2-5 (not applicable).
+
+    // Steps 6-7.
+    if (rhs.isString()) {
+        RootedBigInt rhsBigInt(cx);
+        RootedString rhsString(cx, rhs.toString());
+        MOZ_TRY_VAR(rhsBigInt, StringToBigInt(cx, rhsString, 0));
+        if (!rhsBigInt)
+            return false;
+        return equal(lhs, rhsBigInt);
+    }
+
+    // Steps 8-9 (not applicable).
+
+    // Steps 10-11.
+    if (rhs.isObject()) {
+        RootedValue rhsPrimitive(cx, rhs);
+        if (!ToPrimitive(cx, &rhsPrimitive))
+            return cx->alreadyReportedError();
+        return looselyEqual(cx, lhs, rhsPrimitive);
+    }
+
+    // Step 12.
+    if (rhs.isNumber())
+        return equal(lhs, rhs.toNumber());
+
+    // Step 13.
+    return false;
+}
+
 JSLinearString*
 BigInt::toString(JSContext* cx, BigInt* x, uint8_t radix)
 {
     MOZ_ASSERT(2 <= radix && radix <= 36);
     // We need two extra chars for '\0' and potentially '-'.
     size_t strSize = mpz_sizeinbase(x->num_, 10) + 2;
     UniqueChars str(js_pod_malloc<char>(strSize));
     if (!str) {
@@ -514,38 +579,38 @@ js::StringToBigIntImpl(const Range<const
     }
 
     if (sign.valueOr(1) < 0)
         mpz_neg(res->num_, res->num_);
 
     return true;
 }
 
-BigInt*
+JS::Result<BigInt*, JS::OOM&>
 js::StringToBigInt(JSContext* cx, HandleString str, uint8_t radix)
 {
     RootedBigInt res(cx, BigInt::create(cx));
+    if (!res)
+        return cx->alreadyReportedOOM();
 
     JSLinearString* linear = str->ensureLinear(cx);
     if (!linear)
-        return nullptr;
+        return cx->alreadyReportedOOM();
 
     {
         JS::AutoCheckCannotGC nogc;
         if (linear->hasLatin1Chars()) {
             if (StringToBigIntImpl(linear->latin1Range(nogc), radix, res))
-                return res;
+                return res.get();
         } else {
             if (StringToBigIntImpl(linear->twoByteRange(nogc), radix, res))
-                return res;
+                return res.get();
         }
     }
 
-    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
-                              JSMSG_BIGINT_INVALID_SYNTAX);
     return nullptr;
 }
 
 size_t
 BigInt::byteLength(BigInt* x)
 {
     if (mpz_sgn(x->num_) == 0)
         return 0;
--- a/js/src/vm/BigIntType.h
+++ b/js/src/vm/BigIntType.h
@@ -12,16 +12,17 @@
 
 #include <gmp.h>
 
 #include "gc/Barrier.h"
 #include "gc/GC.h"
 #include "gc/Heap.h"
 #include "js/AllocPolicy.h"
 #include "js/GCHashTable.h"
+#include "js/Result.h"
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "vm/StringType.h"
 
 namespace js {
 
 template <typename CharT>
 static bool StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
@@ -94,16 +95,20 @@ class BigInt final : public js::gc::Tenu
     static bool div(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res);
     static bool mod(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res);
     static bool pow(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res);
     static bool neg(JSContext* cx, Handle<Value> operand, MutableHandle<Value> res);
 
     static double numberValue(BigInt* x);
     static JSLinearString* toString(JSContext* cx, BigInt* x, uint8_t radix);
 
+    static bool equal(BigInt* lhs, BigInt* rhs);
+    static bool equal(BigInt* lhs, double rhs);
+    static JS::Result<bool> looselyEqual(JSContext* cx, HandleBigInt lhs, HandleValue rhs);
+
     // Return the length in bytes of the representation used by
     // writeBytes.
     static size_t byteLength(BigInt* x);
 
     // Write a little-endian representation of a BigInt's absolute value
     // to a byte array.
     static void writeBytes(BigInt* x, mozilla::RangedPtr<uint8_t> buffer);
 };
@@ -116,17 +121,18 @@ static_assert(sizeof(BigInt) >= js::gc::
 namespace js {
 
 extern JSAtom*
 BigIntToAtom(JSContext* cx, JS::BigInt* bi);
 
 extern JS::BigInt*
 NumberToBigInt(JSContext* cx, double d);
 
-extern JS::BigInt*
+// Convert a string to a BigInt, returning nullptr if parsing fails.
+extern JS::Result<JS::BigInt*, JS::OOM&>
 StringToBigInt(JSContext* cx, JS::Handle<JSString*> str, uint8_t radix);
 
 extern JS::BigInt*
 ToBigInt(JSContext* cx, JS::Handle<JS::Value> v);
 
 } // namespace js
 
 #endif
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -862,16 +862,22 @@ EqualGivenSameType(JSContext* cx, Handle
     MOZ_ASSERT(SameType(lval, rval));
 
     if (lval.isString())
         return EqualStrings(cx, lval.toString(), rval.toString(), equal);
     if (lval.isDouble()) {
         *equal = (lval.toDouble() == rval.toDouble());
         return true;
     }
+#ifdef ENABLE_BIGINT
+    if (lval.isBigInt()) {
+        *equal = BigInt::equal(lval.toBigInt(), rval.toBigInt());
+        return true;
+    }
+#endif
     if (lval.isGCThing()) {  // objects or symbols
         *equal = (lval.toGCThing() == rval.toGCThing());
         return true;
     }
     *equal = lval.get().payloadAsRawUint32() == rval.get().payloadAsRawUint32();
     MOZ_ASSERT_IF(lval.isUndefined() || lval.isNull(), *equal);
     return true;
 }
@@ -965,16 +971,34 @@ js::LooselyEqual(JSContext* cx, HandleVa
     // Step 11.
     if (lval.isObject() && (rval.isString() || rval.isNumber() || rval.isSymbol())) {
         RootedValue lvalue(cx, lval);
         if (!ToPrimitive(cx, &lvalue))
             return false;
         return LooselyEqual(cx, lvalue, rval, result);
     }
 
+#ifdef ENABLE_BIGINT
+    if (lval.isBigInt()) {
+        RootedBigInt lbi(cx, lval.toBigInt());
+        bool tmpResult;
+        JS_TRY_VAR_OR_RETURN_FALSE(cx, tmpResult, BigInt::looselyEqual(cx, lbi, rval));
+        *result = tmpResult;
+        return true;
+    }
+
+    if (rval.isBigInt()) {
+        RootedBigInt rbi(cx, rval.toBigInt());
+        bool tmpResult;
+        JS_TRY_VAR_OR_RETURN_FALSE(cx, tmpResult, BigInt::looselyEqual(cx, rbi, lval));
+        *result = tmpResult;
+        return true;
+    }
+#endif
+
     // Step 12.
     *result = false;
     return true;
 }
 
 bool
 js::StrictlyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal)
 {
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -1354,18 +1354,16 @@ JSContext::~JSContext()
 {
     // Clear the ContextKind first, so that ProtectedData checks will allow us to
     // destroy this context even if the runtime is already gone.
     kind_ = ContextKind::HelperThread;
 
     /* Free the stuff hanging off of cx. */
     MOZ_ASSERT(!resolvingList);
 
-    js_delete(ionPcScriptCache.ref());
-
     if (dtoaState)
         DestroyDtoaState(dtoaState);
 
     fx.destroyInstance();
     freeOsrTempData();
 
 #ifdef JS_SIMULATOR
     js::jit::Simulator::Destroy(simulator_);
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -651,17 +651,17 @@ struct JSContext : public JS::RootingCon
     js::ThreadData<js::LifoAlloc> tempLifoAlloc_;
   public:
     js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
     const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
 
     js::ThreadData<uint32_t> debuggerMutations;
 
     // Cache for jit::GetPcScript().
-    js::ThreadData<js::jit::PcScriptCache*> ionPcScriptCache;
+    js::ThreadData<js::UniquePtr<js::jit::PcScriptCache>> ionPcScriptCache;
 
   private:
     /* Exception state -- the exception member is a GC root by definition. */
     js::ThreadData<bool> throwing;            /* is there a pending exception? */
     js::ThreadData<JS::PersistentRooted<JS::Value>> unwrappedException_; /* most-recently-thrown exception */
 
     JS::Value& unwrappedException() {
         if (!unwrappedException_.ref().initialized())
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -767,20 +767,20 @@ JS::OrdinaryHasInstance(JSContext* cx, H
          */
         RootedValue val(cx, ObjectValue(*obj));
         ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, nullptr);
         return false;
     }
 
     /* Step 6. */
     RootedObject pobj(cx, &pval.toObject());
-    bool isDelegate;
-    if (!IsDelegate(cx, pobj, v, &isDelegate))
+    bool isPrototype;
+    if (!IsPrototypeOf(cx, pobj, &v.toObject(), &isPrototype))
         return false;
-    *bp = isDelegate;
+    *bp = isPrototype;
     return true;
 }
 
 inline void
 JSFunction::trace(JSTracer* trc)
 {
     if (isExtended()) {
         TraceRange(trc, ArrayLength(toExtended()->extendedSlots),
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -3168,27 +3168,17 @@ js::ToPropertyKeySlow(JSContext* cx, Han
 
     // Steps 3-4.
     return ValueToId<CanGC>(cx, key, result);
 }
 
 /* * */
 
 bool
-js::IsDelegate(JSContext* cx, HandleObject obj, const js::Value& v, bool* result)
-{
-    if (v.isPrimitive()) {
-        *result = false;
-        return true;
-    }
-    return IsDelegateOfObject(cx, obj, &v.toObject(), result);
-}
-
-bool
-js::IsDelegateOfObject(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result)
+js::IsPrototypeOf(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result)
 {
     RootedObject obj2(cx, obj);
     for (;;) {
         if (!GetPrototype(cx, obj2, &obj2))
             return false;
         if (!obj2) {
             *result = false;
             return true;
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -1176,23 +1176,20 @@ GetOwnPropertyDescriptor(JSContext* cx, 
  * Use JS::FromPropertyDescriptor for getOwnPropertyDescriptor, since desc.object()
  * is used to indicate whether a result was found or not.  Use this instead for
  * defineProperty: it would be senseless to define a "missing" property.
  */
 extern bool
 FromPropertyDescriptorToObject(JSContext* cx, Handle<JS::PropertyDescriptor> desc,
                                MutableHandleValue vp);
 
-extern bool
-IsDelegate(JSContext* cx, HandleObject obj, const Value& v, bool* result);
-
 // obj is a JSObject*, but we root it immediately up front. We do it
 // that way because we need a Rooted temporary in this method anyway.
 extern bool
-IsDelegateOfObject(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result);
+IsPrototypeOf(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result);
 
 /* Wrap boolean, number or string as Boolean, Number or String object. */
 extern JSObject*
 PrimitiveToObject(JSContext* cx, const Value& v);
 
 } /* namespace js */
 
 namespace js {
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -70,31 +70,16 @@
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::Maybe;
 using mozilla::PodCopy;
 
 
-// Check that JSScript::data hasn't experienced obvious memory corruption.
-// This is a diagnositic for Bug 1367896.
-static void
-CheckScriptDataIntegrity(JSScript* script)
-{
-    ScopeArray* sa = script->scopes();
-    uint8_t* ptr = reinterpret_cast<uint8_t*>(sa->vector);
-
-    // Check that scope data - who's pointer is stored in data region - also
-    // points within the data region.
-    MOZ_RELEASE_ASSERT(ptr >= script->data &&
-                       ptr + sa->length <= script->data + script->dataSize(),
-                       "Corrupt JSScript::data");
-}
-
 template<XDRMode mode>
 XDRResult
 js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
 {
     JSContext* cx = xdr->cx();
 
     enum ConstTag {
         SCRIPT_INT,
@@ -365,18 +350,16 @@ js::XDRScript(XDRState<mode>* xdr, Handl
     RootedScript script(cx);
     natoms = nsrcnotes = 0;
     nconsts = nobjects = nscopes = nregexps = ntrynotes = nscopenotes = nyieldoffsets = 0;
 
     if (mode == XDR_ENCODE) {
         script = scriptp.get();
         MOZ_ASSERT(script->functionNonDelazifying() == fun);
 
-        CheckScriptDataIntegrity(script);
-
         if (!fun && script->treatAsRunOnce() && script->hasRunOnce()) {
             // This is a toplevel or eval script that's runOnce.  We want to
             // make sure that we're not XDR-saving an object we emitted for
             // JSOP_OBJECT that then got modified.  So throw if we're not
             // cloning in JSOP_OBJECT or if we ever didn't clone in it in the
             // past.
             Realm* realm = cx->realm();
             if (!realm->creationOptions().cloneSingletons() ||
@@ -545,25 +528,28 @@ js::XDRScript(XDRState<mode>* xdr, Handl
     } else {
         // When encoding, we do not mutate any of the JSScript or LazyScript, so
         // we can safely unwrap it here.
         sourceObject = &script->scriptSourceUnwrap();
     }
 
     if (mode == XDR_DECODE) {
         if (!JSScript::partiallyInit(cx, script, nscopes, nconsts, nobjects, ntrynotes,
-                                     nscopenotes, nyieldoffsets, nTypeSets))
+                                     nscopenotes, nyieldoffsets))
         {
             return xdr->fail(JS::TranscodeResult_Throw);
         }
 
         MOZ_ASSERT(!script->mainOffset());
         script->mainOffset_ = prologueLength;
         script->funLength_ = funLength;
 
+        MOZ_ASSERT(nTypeSets <= UINT16_MAX);
+        script->nTypeSets_ = uint16_t(nTypeSets);
+
         scriptp.set(script);
 
         if (scriptBits & (1 << Strict))
             script->bitFields_.strict_ = true;
         if (scriptBits & (1 << ExplicitUseStrict))
             script->bitFields_.explicitUseStrict_ = true;
         if (scriptBits & (1 << ContainsDynamicNameAccess))
             script->bitFields_.bindingsAccessedDynamically_ = true;
@@ -882,18 +868,16 @@ js::XDRScript(XDRState<mode>* xdr, Handl
 
         MOZ_TRY(XDRRelazificationInfo(xdr, fun, script, scriptEnclosingScope, &lazy));
 
         if (mode == XDR_DECODE)
             script->setLazyScript(lazy);
     }
 
     if (mode == XDR_DECODE) {
-        CheckScriptDataIntegrity(script);
-
         scriptp.set(script);
 
         /* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
         if (!fun && !cx->helperThread())
             Debugger::onNewScript(cx, script);
     }
 
     return Ok();
@@ -2746,31 +2730,28 @@ AllocScriptData(JSContext* cx, size_t si
         return nullptr;
     MOZ_ASSERT(size_t(data) % sizeof(Value) == 0);
     return data;
 }
 
 /* static */ bool
 JSScript::partiallyInit(JSContext* cx, HandleScript script, uint32_t nscopes,
                         uint32_t nconsts, uint32_t nobjects, uint32_t ntrynotes,
-                        uint32_t nscopenotes, uint32_t nyieldoffsets, uint32_t nTypeSets)
+                        uint32_t nscopenotes, uint32_t nyieldoffsets)
 {
     cx->check(script);
 
     size_t size = ScriptDataSize(nscopes, nconsts, nobjects, ntrynotes,
                                  nscopenotes, nyieldoffsets);
     script->data = AllocScriptData(cx, size);
     if (size && !script->data)
         return false;
 
     script->dataSize_ = size;
 
-    MOZ_ASSERT(nTypeSets <= UINT16_MAX);
-    script->nTypeSets_ = uint16_t(nTypeSets);
-
     uint8_t* cursor = script->data;
 
     // There must always be at least 1 scope, the body scope.
     MOZ_ASSERT(nscopes != 0);
     cursor += sizeof(ScopeArray);
 
     if (nconsts != 0) {
         script->setHasArray(CONSTS);
@@ -2851,23 +2832,24 @@ JSScript::initFunctionPrototype(JSContex
                                 HandleFunction functionProto)
 {
     uint32_t numScopes = 1;
     uint32_t numConsts = 0;
     uint32_t numObjects = 0;
     uint32_t numTryNotes = 0;
     uint32_t numScopeNotes = 0;
     uint32_t numYieldAndAwaitOffsets = 0;
-    uint32_t numTypeSets = 0;
     if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
-                       numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
+                       numScopeNotes, numYieldAndAwaitOffsets))
     {
         return false;
     }
 
+    script->nTypeSets_ = 0;
+
     RootedScope enclosing(cx, &cx->global()->emptyGlobalScope());
     Scope* functionProtoScope = FunctionScope::create(cx, nullptr, false, false, functionProto,
                                                       enclosing);
     if (!functionProtoScope)
         return false;
     script->scopes()->vector[0].init(functionProtoScope);
 
     uint32_t codeLength = 1;
@@ -2966,24 +2948,24 @@ JSScript::fullyInitFromEmitter(JSContext
     uint32_t prologueLength = bce->prologueOffset();
     uint32_t nsrcnotes;
     if (!bce->finishTakingSrcNotes(&nsrcnotes))
         return false;
     uint32_t natoms = bce->atomIndices->count();
     if (!partiallyInit(cx, script,
                        bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
                        bce->tryNoteList.length(), bce->scopeNoteList.length(),
-                       bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
+                       bce->yieldAndAwaitOffsetList.length()))
     {
         return false;
     }
 
     MOZ_ASSERT(script->mainOffset() == 0);
     script->mainOffset_ = prologueLength;
-
+    script->nTypeSets_ = bce->typesetCount;
     script->lineno_ = bce->firstLine;
 
     if (!script->createScriptData(cx, prologueLength + mainLength, nsrcnotes, natoms))
         return false;
 
     // Any fallible operation after JSScript::createScriptData should reset
     // JSScript.scriptData_, in order to treat this script as uncompleted,
     // in JSScript::isUncompleted.
@@ -3452,18 +3434,16 @@ js::detail::CopyScript(JSContext* cx, Ha
 {
     if (src->treatAsRunOnce() && !src->functionNonDelazifying()) {
         JS_ReportErrorASCII(cx, "No cloning toplevel run-once scripts");
         return false;
     }
 
     /* NB: Keep this in sync with XDRScript. */
 
-    CheckScriptDataIntegrity(src);
-
     /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
     MOZ_ASSERT(!src->sourceObject()->isMarkedGray());
 
     uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
     uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
     uint32_t nscopes   = src->scopes()->length;
     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
     uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -1216,18 +1216,17 @@ class JSScript : public js::gc::TenuredC
                             uint32_t toStringStart, uint32_t toStringEnd);
 
     // Three ways ways to initialize a JSScript. Callers of partiallyInit()
     // are responsible for notifying the debugger after successfully creating
     // any kind (function or other) of new JSScript.  However, callers of
     // fullyInitFromEmitter() do not need to do this.
     static bool partiallyInit(JSContext* cx, JS::Handle<JSScript*> script,
                               uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
-                              uint32_t ntrynotes, uint32_t nscopenotes, uint32_t nyieldoffsets,
-                              uint32_t nTypeSets);
+                              uint32_t ntrynotes, uint32_t nscopenotes, uint32_t nyieldoffsets);
 
   private:
     static void initFromFunctionBox(js::HandleScript script, js::frontend::FunctionBox* funbox);
     static void initFromModuleContext(js::HandleScript script);
 
   public:
     static bool fullyInitFromEmitter(JSContext* cx, js::HandleScript script,
                                      js::frontend::BytecodeEmitter* bce);
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4264,16 +4264,20 @@ PresShell::DoFlushPendingNotifications(m
     mDocument->UpdateSVGUseElementShadowTrees();
 
     // Process pending restyles, since any flush of the presshell wants
     // up-to-date style data.
     if (!mIsDestroying) {
       viewManager->FlushDelayedResize(false);
       mPresContext->FlushPendingMediaFeatureValuesChanged();
 
+      // Now that we have flushed media queries, update the rules before looking
+      // up @font-face / @counter-style / @font-feature-values rules.
+      mStyleSet->UpdateStylistIfNeeded();
+
       // Flush any pending update of the user font set, since that could
       // cause style changes (for updating ex/ch units, and to cause a
       // reflow).
       mDocument->FlushUserFontSet();
 
       mPresContext->FlushCounterStyles();
 
       mPresContext->FlushFontFeatureValues();
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1126,16 +1126,17 @@ nsPresContext::CompatibilityModeChanged(
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "failed to insert quirk.css");
   } else {
     DebugOnly<nsresult> rv =
       styleSet->RemoveStyleSheet(SheetType::Agent, sheet);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "failed to remove quirk.css");
   }
 
   mQuirkSheetAdded = needsQuirkSheet;
+  mShell->ApplicableStylesChanged();
 }
 
 // Helper function for setting Anim Mode on image
 static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode)
 {
   if (aImgReq) {
     nsCOMPtr<imgIContainer> imgCon;
     aImgReq->GetImage(getter_AddRefs(imgCon));
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -56,25 +56,27 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_From
                    mozilla::css::Loader* loader,
                    mozilla::StyleSheet* gecko_stylesheet,
                    mozilla::css::SheetLoadData* load_data,
                    const nsACString* bytes,
                    mozilla::css::SheetParsingMode parsing_mode,
                    RawGeckoURLExtraData* extra_data,
                    uint32_t line_number_offset,
                    nsCompatibility quirks_mode,
-                   mozilla::css::LoaderReusableStyleSheets* reusable_sheets)
+                   mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
+                   StyleUseCountersBorrowedOrNull use_counters)
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8BytesAsync,
                    void,
                    mozilla::css::SheetLoadDataHolder* load_data,
                    RawGeckoURLExtraData* extra_data,
                    const nsACString* bytes,
                    mozilla::css::SheetParsingMode parsing_mode,
                    uint32_t line_number_offset,
-                   nsCompatibility quirks_mode)
+                   nsCompatibility quirks_mode,
+                   bool should_record_use_counters)
 SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetContentsStrong,
                    mozilla::css::SheetParsingMode parsing_mode)
 SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
                    RawServoStyleSheetContentsBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
                    RawServoStyleSheetContentsBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_Clone, RawServoStyleSheetContentsStrong,
                    RawServoStyleSheetContentsBorrowed sheet,
@@ -901,15 +903,24 @@ SERVO_BINDING_FUNC(Servo_Property_IsShor
 SERVO_BINDING_FUNC(Servo_Property_IsInherited, bool,
                    const nsACString* name);
 SERVO_BINDING_FUNC(Servo_Property_SupportsType, bool,
                    const nsACString* name, uint32_t ty, bool* found);
 SERVO_BINDING_FUNC(Servo_Property_GetCSSValuesForProperty, void,
                    const nsACString* name, bool* found, nsTArray<nsString>* result)
 SERVO_BINDING_FUNC(Servo_PseudoClass_GetStates, uint64_t,
                    const nsACString* name)
+SERVO_BINDING_FUNC(Servo_UseCounters_Create, StyleUseCounters*)
+SERVO_BINDING_FUNC(Servo_UseCounters_Drop, void, StyleUseCountersOwned)
+SERVO_BINDING_FUNC(Servo_UseCounters_Merge, void,
+                   StyleUseCountersBorrowed doc_counters,
+                   StyleUseCountersBorrowed sheet_counters)
+SERVO_BINDING_FUNC(Servo_IsCssPropertyRecordedInUseCounter, bool,
+                   StyleUseCountersBorrowed,
+                   const nsACString* property,
+                   bool* out_known_prop)
 
 // AddRef / Release functions
 #define SERVO_ARC_TYPE(name_, type_)                                \
   SERVO_BINDING_FUNC(Servo_##name_##_AddRef, void, type_##Borrowed) \
   SERVO_BINDING_FUNC(Servo_##name_##_Release, void, type_##Borrowed)
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -18,16 +18,17 @@
 #include "nsTArray.h"
 
 struct RawServoAuthorStyles;
 struct RawServoStyleSet;
 struct RawServoSelectorList;
 struct RawServoSourceSizeList;
 struct RawServoAnimationValueMap;
 struct RustString;
+struct StyleUseCounters;
 
 #define SERVO_ARC_TYPE(name_, type_) struct type_;
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
 
 namespace mozilla {
 class ServoElementSnapshot;
 class ComputedStyle;
@@ -194,16 +195,20 @@ DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSProp
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoCSSPropertyIDList)
 DECL_BORROWED_REF_TYPE_FOR(nsXBLBinding)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoStyleChildrenIterator)
 DECL_OWNED_REF_TYPE_FOR(RawServoSelectorList)
 DECL_BORROWED_REF_TYPE_FOR(RawServoSelectorList)
 DECL_OWNED_REF_TYPE_FOR(RawServoSourceSizeList)
 DECL_BORROWED_REF_TYPE_FOR(RawServoSourceSizeList)
 DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoSourceSizeList)
+DECL_OWNED_REF_TYPE_FOR(StyleUseCounters)
+DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleUseCounters)
+DECL_BORROWED_REF_TYPE_FOR(StyleUseCounters)
+DECL_NULLABLE_BORROWED_REF_TYPE_FOR(StyleUseCounters)
 
 #undef DECL_ARC_REF_TYPE_FOR
 #undef DECL_OWNED_REF_TYPE_FOR
 #undef DECL_NULLABLE_OWNED_REF_TYPE_FOR
 #undef DECL_BORROWED_REF_TYPE_FOR
 #undef DECL_NULLABLE_BORROWED_REF_TYPE_FOR
 #undef DECL_BORROWED_MUT_REF_TYPE_FOR
 #undef DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR
@@ -239,16 +244,17 @@ DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawS
     }                                                       \
   };                                                        \
   }
 
 DEFINE_BOXED_TYPE(StyleSet, RawServoStyleSet);
 DEFINE_BOXED_TYPE(AuthorStyles, RawServoAuthorStyles);
 DEFINE_BOXED_TYPE(SelectorList, RawServoSelectorList);
 DEFINE_BOXED_TYPE(SourceSizeList, RawServoSourceSizeList);
+DEFINE_BOXED_TYPE(UseCounters, StyleUseCounters);
 
 #undef DEFINE_BOXED_TYPE
 
 // used for associating sheet type with specific @font-face rules
 struct nsFontFaceRuleContainer
 {
   RefPtr<RawServoFontFaceRule> mRule;
   mozilla::SheetType mSheetType;
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2573,25 +2573,34 @@ Gecko_GetAppUnitsPerPhysicalInch(RawGeck
   nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
   return presContext->DeviceContext()->AppUnitsPerPhysicalInch();
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SheetLoadDataHolder, SheetLoadDataHolder);
 
 void
 Gecko_StyleSheet_FinishAsyncParse(SheetLoadDataHolder* aData,
-                                  RawServoStyleSheetContentsStrong aSheetContents)
+                                  RawServoStyleSheetContentsStrong aSheetContents,
+                                  StyleUseCountersOwned aUseCounters)
 {
+  UniquePtr<StyleUseCounters> useCounters(aUseCounters);
   RefPtr<SheetLoadDataHolder> loadData = aData;
   RefPtr<RawServoStyleSheetContents> sheetContents = aSheetContents.Consume();
   NS_DispatchToMainThread(NS_NewRunnableFunction(__func__,
                                                  [d = std::move(loadData),
-                                                  s = std::move(sheetContents)]() mutable {
+                                                  contents = std::move(sheetContents),
+                                                  counters = std::move(useCounters)]() mutable {
     MOZ_ASSERT(NS_IsMainThread());
-    d->get()->mSheet->FinishAsyncParse(s.forget());
+    SheetLoadData* data = d->get();
+    if (nsIDocument* doc = data->mLoader->GetDocument()) {
+      if (const StyleUseCounters* docCounters = doc->GetStyleUseCounters()) {
+        Servo_UseCounters_Merge(docCounters, counters.get());
+      }
+    }
+    data->mSheet->FinishAsyncParse(contents.forget());
   }));
 }
 
 static already_AddRefed<StyleSheet>
 LoadImportSheet(css::Loader* aLoader,
                 StyleSheet* aParent,
                 SheetLoadData* aParentLoadData,
                 css::LoaderReusableStyleSheets* aReusableSheets,
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -166,17 +166,18 @@ void Gecko_ComputedStyle_Destroy(mozilla
 void Gecko_ConstructStyleChildrenIterator(RawGeckoElementBorrowed aElement,
                                           RawGeckoStyleChildrenIteratorBorrowedMut aIterator);
 void Gecko_DestroyStyleChildrenIterator(RawGeckoStyleChildrenIteratorBorrowedMut aIterator);
 RawGeckoNodeBorrowedOrNull Gecko_GetNextStyleChild(RawGeckoStyleChildrenIteratorBorrowedMut it);
 
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::SheetLoadDataHolder, SheetLoadDataHolder);
 
 void Gecko_StyleSheet_FinishAsyncParse(mozilla::css::SheetLoadDataHolder* data,
-                                       RawServoStyleSheetContentsStrong sheet_contents);
+                                       RawServoStyleSheetContentsStrong sheet_contents,
+                                       StyleUseCountersOwnedOrNull use_counters);
 
 mozilla::StyleSheet*
 Gecko_LoadStyleSheet(mozilla::css::Loader* loader,
                      mozilla::StyleSheet* parent,
                      mozilla::css::SheetLoadData* parent_load_data,
                      mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
                      ServoBundledURI url,
                      RawServoMediaListStrong media_list);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -510,16 +510,17 @@ structs-types = [
     "RawGeckoStyleChildrenIterator",
     "RawGeckoServoStyleRuleList",
     "RawGeckoURLExtraData",
     "RawGeckoXBLBinding",
     "RawServoSelectorList",
     "RawServoSourceSizeList",
     "RefPtr",
     "RustString",
+    "StyleUseCounters",
     "CSSPseudoElementType",
     "ServoTraversalFlags",
     "ComputedTimingFunction_BeforeFlag",
     "CounterStylePtr",
     "FontFamilyType",
     "FontSizePrefs",
     "GeckoFontMetrics",
     "IterationCompositeOperation",
@@ -622,16 +623,17 @@ structs-types = [
 array-types = [
     { cpp-type = "uintptr_t", rust-type = "usize" },
 ]
 servo-owned-types = [
     { name = "RawServoStyleSet", opaque = true },
     { name = "RawServoAuthorStyles", opaque = true },
     { name = "RawServoSelectorList", opaque = false },
     { name = "RawServoSourceSizeList", opaque = false },
+    { name = "StyleUseCounters", opaque = false },
     { name = "ServoElementSnapshot", opaque = false },
     { name = "RawServoAnimationValueMap", opaque = true },
 ]
 servo-immutable-borrow-types = [
     "RawGeckoNode",
     "RawGeckoElement",
     "RawGeckoDocument",
     "RawServoDeclarationBlockStrong",
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1406,34 +1406,33 @@ ServoStyleSet::ResolveStyleLazilyInterna
                         aElement->OwnerDoc()->GetBFCacheEntry());
 
   return computedValues.forget();
 }
 
 bool
 ServoStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
 {
+  // TODO(emilio): Can we make this so this asserts instead?
   UpdateStylistIfNeeded();
   Servo_StyleSet_GetFontFaceRules(mRawSet.get(), &aArray);
   return true;
 }
 
 const RawServoCounterStyleRule*
 ServoStyleSet::CounterStyleRuleForName(nsAtom* aName)
 {
   MOZ_ASSERT(!StylistNeedsUpdate());
   return Servo_StyleSet_GetCounterStyleRule(mRawSet.get(), aName);
 }
 
 already_AddRefed<gfxFontFeatureValueSet>
 ServoStyleSet::BuildFontFeatureValueSet()
 {
-  // FIXME(emilio): This should assert once we update the stylist from
-  // FlushPendingNotifications explicitly.
-  UpdateStylistIfNeeded();
+  MOZ_ASSERT(!StylistNeedsUpdate());
   RefPtr<gfxFontFeatureValueSet> set =
     Servo_StyleSet_BuildFontFeatureValueSet(mRawSet.get());
   return set.forget();
 }
 
 already_AddRefed<ComputedStyle>
 ServoStyleSet::ResolveForDeclarations(
   const ComputedStyle* aParentOrNull,
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -1000,48 +1000,54 @@ AllowParallelParse(css::Loader* aLoader,
     return false;
   }
 
   return true;
 }
 
 RefPtr<StyleSheetParsePromise>
 StyleSheet::ParseSheet(css::Loader* aLoader,
-                            const nsACString& aBytes,
-                            css::SheetLoadData* aLoadData)
+                       const nsACString& aBytes,
+                       css::SheetLoadData* aLoadData)
 {
   MOZ_ASSERT(aLoader);
   MOZ_ASSERT(aLoadData);
   MOZ_ASSERT(mParsePromise.IsEmpty());
   RefPtr<StyleSheetParsePromise> p = mParsePromise.Ensure(__func__);
   Inner().mURLData =
     new URLExtraData(GetBaseURI(), GetSheetURI(), Principal()); // RefPtr
 
+  const StyleUseCounters* useCounters = aLoader->GetDocument()
+    ? aLoader->GetDocument()->GetStyleUseCounters()
+    : nullptr;
+
   if (!AllowParallelParse(aLoader, GetSheetURI())) {
     RefPtr<RawServoStyleSheetContents> contents =
       Servo_StyleSheet_FromUTF8Bytes(aLoader,
                                      this,
                                      aLoadData,
                                      &aBytes,
                                      mParsingMode,
                                      Inner().mURLData,
                                      aLoadData->mLineNumber,
                                      aLoader->GetCompatibilityMode(),
-                                     /* reusable_sheets = */ nullptr)
+                                     /* reusable_sheets = */ nullptr,
+                                     useCounters)
       .Consume();
     FinishAsyncParse(contents.forget());
   } else {
     RefPtr<css::SheetLoadDataHolder> loadDataHolder =
       new css::SheetLoadDataHolder(__func__, aLoadData);
     Servo_StyleSheet_FromUTF8BytesAsync(loadDataHolder,
                                         Inner().mURLData,
                                         &aBytes,
                                         mParsingMode,
                                         aLoadData->mLineNumber,
-                                        aLoader->GetCompatibilityMode());
+                                        aLoader->GetCompatibilityMode(),
+                                        /* should_record_counters = */ !!useCounters);
   }
 
   return p;
 }
 
 void
 StyleSheet::FinishAsyncParse(already_AddRefed<RawServoStyleSheetContents> aSheetContents)
 {
@@ -1058,26 +1064,31 @@ StyleSheet::ParseSheetSync(css::Loader* 
                            const nsACString& aBytes,
                            css::SheetLoadData* aLoadData,
                            uint32_t aLineNumber,
                            css::LoaderReusableStyleSheets* aReusableSheets)
 {
   nsCompatibility compatMode =
     aLoader ? aLoader->GetCompatibilityMode() : eCompatibility_FullStandards;
 
+  const StyleUseCounters* useCounters = aLoader && aLoader->GetDocument()
+    ? aLoader->GetDocument()->GetStyleUseCounters()
+    : nullptr;
+
   Inner().mURLData = new URLExtraData(GetBaseURI(), GetSheetURI(), Principal()); // RefPtr
   Inner().mContents = Servo_StyleSheet_FromUTF8Bytes(aLoader,
                                                      this,
                                                      aLoadData,
                                                      &aBytes,
                                                      mParsingMode,
                                                      Inner().mURLData,
                                                      aLineNumber,
                                                      compatMode,
-                                                     aReusableSheets)
+                                                     aReusableSheets,
+                                                     useCounters)
                          .Consume();
 
   FinishParse();
 }
 
 void
 StyleSheet::FinishParse()
 {
--- a/layout/style/test/gtest/StyloParsingBench.cpp
+++ b/layout/style/test/gtest/StyloParsingBench.cpp
@@ -19,18 +19,18 @@ using namespace mozilla::net;
 
 // Bug 1436018 - Disable Stylo microbenchmark on Windows
 #if !defined(_WIN32) && !defined(_WIN64)
 
 #define PARSING_REPETITIONS 20
 #define SETPROPERTY_REPETITIONS (1000 * 1000)
 #define GETPROPERTY_REPETITIONS (1000 * 1000)
 
-static void ServoParsingBench() {
-
+static void ServoParsingBench(const StyleUseCounters* aCounters)
+{
   auto css = AsBytes(MakeStringSpan(EXAMPLE_STYLESHEET));
   nsCString cssStr;
   cssStr.Append(css);
   ASSERT_EQ(Encoding::UTF8ValidUpTo(css), css.Length());
 
   RefPtr<URLExtraData> data = new URLExtraData(
     NullPrincipalURI::Create(), nullptr, NullPrincipal::CreateWithoutOriginAttributes());
   for (int i = 0; i < PARSING_REPETITIONS; i++) {
@@ -38,22 +38,24 @@ static void ServoParsingBench() {
       Servo_StyleSheet_FromUTF8Bytes(nullptr,
                                      nullptr,
                                      nullptr,
                                      &cssStr,
                                      eAuthorSheetFeatures,
                                      data,
                                      0,
                                      eCompatibility_FullStandards,
-                                     nullptr)
+                                     nullptr,
+                                     aCounters)
         .Consume();
   }
 }
 
-static void ServoSetPropertyByIdBench(const nsACString& css) {
+static void ServoSetPropertyByIdBench(const nsACString& css)
+{
   RefPtr<RawServoDeclarationBlock> block = Servo_DeclarationBlock_CreateEmpty().Consume();
   RefPtr<URLExtraData> data = new URLExtraData(
     NullPrincipalURI::Create(), nullptr, NullPrincipal::CreateWithoutOriginAttributes());
 
   ASSERT_TRUE(IsUTF8(css));
 
   for (int i = 0; i < SETPROPERTY_REPETITIONS; i++) {
     Servo_DeclarationBlock_SetPropertyById(
@@ -95,17 +97,24 @@ static void ServoGetPropertyValueById() 
       block,
       eCSSProperty_width,
       &value
     );
     ASSERT_TRUE(value.EqualsLiteral("10px"));
   }
 }
 
-MOZ_GTEST_BENCH(Stylo, Servo_StyleSheet_FromUTF8Bytes_Bench, ServoParsingBench);
+MOZ_GTEST_BENCH(Stylo, Servo_StyleSheet_FromUTF8Bytes_Bench, [] {
+    ServoParsingBench(nullptr);
+});
+
+MOZ_GTEST_BENCH(Stylo, Servo_StyleSheet_FromUTF8Bytes_Bench_UseCounters, [] {
+    UniquePtr<StyleUseCounters> counters(Servo_UseCounters_Create());
+    ServoParsingBench(counters.get());
+});
 
 MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_SetPropertyById_Bench, [] {
   ServoSetPropertyByIdBench(NS_LITERAL_CSTRING("10px"));
 });
 
 MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_SetPropertyById_WithInitialSpace_Bench, [] {
   ServoSetPropertyByIdBench(NS_LITERAL_CSTRING(" 10px"));
 });
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -367,8 +367,9 @@ skip-if = toolkit == 'android' # TIMED_O
 [test_webkit_appearance_basic.html]
 [test_webkit_device_pixel_ratio.html]
 [test_webkit_flex_display.html]
 [test_first_letter_restrictions.html]
 [test_first_line_restrictions.html]
 [test_placeholder_restrictions.html]
 [test_mql_event_listener_leaks.html]
 [test_non_matching_sheet_media.html]
+[test_use_counters.html]
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_use_counters.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<title>Test for Bug 1425700: CSS properties use-counters</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<body>
+<script>
+const utils = SpecialPowers.getDOMWindowUtils(window);
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+  { "set": [["layout.css.use-counters.enabled", true ]]},
+  run,
+);
+
+function assert_recorded(recorded, properties) {
+  for (const prop of properties) {
+    try {
+      is(utils.isCssPropertyRecordedInUseCounter(prop), recorded, prop)
+    } catch(ex) {
+      ok(false, "Threw: " + prop);
+    }
+  }
+}
+
+function run() {
+  const style = document.createElement('style');
+  style.textContent = `
+    * {
+      grid-gap: 1px; /* shorthand alias */
+      -webkit-background-size: 100px 100px; /* longhand alias */
+      transform-origin: top left; /* longhand */
+      background: green; /* shorthand */
+    }
+  `;
+
+  document.body.appendChild(style);
+
+  assert_recorded(true, [
+    "grid-gap",
+    "-webkit-background-size",
+    "transform-origin",
+    "background"
+  ]);
+
+  // Should only record the aliases, not the non-aliased property.
+  // Should only record shorthands, not the longhands it expands to.
+  assert_recorded(false, [
+    "gap",
+    "background-size",
+    "-moz-transform-origin",
+    "-webkit-transform-origin",
+    "background-color"
+  ]);
+
+  // TODO(emilio): Make work (and test) inline style and maybe even CSSOM and
+  // such?
+  //
+  // Make sure that something on the lines of the following passes:
+  //
+  //   element.style.webkitTransform = "rotate(1deg)"
+  //   assert_recorded(true, ["-webkit-transform"]);
+  //   assert_recorded(false, ["transform"]);
+  //
+  SimpleTest.finish();
+}
+</script>
+</body>
--- a/mobile/android/config/mozconfigs/android-aarch64/nightly
+++ b/mobile/android/config/mozconfigs/android-aarch64/nightly
@@ -1,22 +1,13 @@
 . "$topsrcdir/mobile/android/config/mozconfigs/common"
 
 # Android
 ac_add_options --with-android-min-sdk=21
 ac_add_options --target=aarch64-linux-android
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
-export AR="$topsrcdir/clang/bin/llvm-ar"
-export NM="$topsrcdir/clang/bin/llvm-nm"
-export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
-
-# Enable LTO if the NDK is available.
-if [ -z "$NO_NDK" ]; then
-  ac_add_options --enable-lto
-fi
-
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_POCKET=1
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-api-16/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16/nightly
@@ -11,18 +11,9 @@ ac_add_options --target=arm-linux-androi
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_MMA=1
 export MOZ_ANDROID_POCKET=1
 
-export AR="$topsrcdir/clang/bin/llvm-ar"
-export NM="$topsrcdir/clang/bin/llvm-nm"
-export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
-
-# Enable LTO if the NDK is available.
-if [ -z "$NO_NDK" ]; then
-  ac_add_options --enable-lto
-fi
-
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-x86/nightly
+++ b/mobile/android/config/mozconfigs/android-x86/nightly
@@ -9,18 +9,9 @@ ac_add_options --target=i686-linux-andro
 ac_add_options --with-android-min-sdk=16
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_POCKET=1
 
-export AR="$topsrcdir/clang/bin/llvm-ar"
-export NM="$topsrcdir/clang/bin/llvm-nm"
-export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
-
-# Enable LTO if the NDK is available.
-if [ -z "$NO_NDK" ]; then
-  ac_add_options --enable-lto
-fi
-
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/common
+++ b/mobile/android/config/mozconfigs/common
@@ -30,23 +30,17 @@ if [ -z "$NO_NDK" ]; then
     ac_add_options --with-android-ndk="$topsrcdir/android-ndk"
 fi
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-fennec-geoloc-api.key
 
-# Marionette is disabled on Android by default. This condition enables it only on some
-# Fennec builds. It remains disabled on "nightly-try", "nightly", release", "beta", etc.
-if [ -z "$MOZ_UPDATE_CHANNEL" ] || [ "$MOZ_UPDATE_CHANNEL" = "default" ] \
-   || [ "$MOZ_UPDATE_CHANNEL" = "try" ];
-then
-    ac_add_options --enable-marionette
-fi
+ac_add_options --enable-marionette
 
 # MOZ_INSTALL_TRACKING does not guarantee MOZ_UPDATE_CHANNEL will be set so we
 # provide a default state. Currently, the default state provides a default
 # keyfile because an assertion will be thrown if MOZ_INSTALL_TRACKING is
 # specified but a keyfile is not. This assertion can catch if we misconfigure a
 # release or beta build and it does not have a valid keyfile.
 #
 # However, by providing a default keyfile, if we misconfigure beta or release,
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -256,16 +256,29 @@ VARCACHE_PREF(
 
 // Is parallel CSS parsing enabled?
 VARCACHE_PREF(
   "layout.css.parsing.parallel",
    layout_css_parsing_parallel,
   bool, true
 )
 
+// Are style system use counters enabled?
+#ifdef RELEASE_OR_BETA
+#define PREF_VALUE false
+#else
+#define PREF_VALUE true
+#endif
+VARCACHE_PREF(
+  "layout.css.use-counters.enabled",
+   layout_css_use_counters_enabled,
+  bool, PREF_VALUE
+)
+#undef PREF_VALUE
+
 // Is CSS error reporting enabled?
 VARCACHE_PREF(
   "layout.css.report_errors",
   layout_css_report_errors,
   bool, true
 )
 
 // Is support for the font-display @font-face descriptor enabled?
@@ -1248,20 +1261,21 @@ VARCACHE_PREF(
 //---------------------------------------------------------------------------
 
 PREF("preferences.allow.omt-write", bool, true)
 
 //---------------------------------------------------------------------------
 // Privacy prefs
 //---------------------------------------------------------------------------
 
+// Whether Content Blocking has been enabled
 VARCACHE_PREF(
-  "privacy.restrict3rdpartystorage.ui.enabled",
-   privacy_restrict3rdpartystorage_ui_enabled,
-  RelaxedAtomicBool, false
+  "browser.contentblocking.enabled",
+   browser_contentblocking_enabled,
+  bool, true
 )
 
 // Anti-tracking permission expiration
 VARCACHE_PREF(
   "privacy.restrict3rdpartystorage.expiration",
    privacy_restrict3rdpartystorage_expiration,
   uint32_t, 2592000 // 30 days (in seconds)
 )
--- a/mozglue/build/WindowsDllBlocklist.h
+++ b/mozglue/build/WindowsDllBlocklist.h
@@ -1,17 +1,18 @@
 /* -*- 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 mozilla_windowsdllblocklist_h
 #define mozilla_windowsdllblocklist_h
 
-#if (defined(_MSC_VER) || defined(__MINGW32__))  && (defined(_M_IX86) || defined(_M_X64))
+#if (defined(_MSC_VER) || defined(__MINGW32__)) && \
+  (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64))
 
 #include <windows.h>
 #ifdef ENABLE_TESTS
 #include <winternl.h>
 #endif // ENABLE_TESTS
 #include "mozilla/Attributes.h"
 #include "mozilla/Types.h"
 
--- a/mozglue/misc/interceptor/PatcherDetour.h
+++ b/mozglue/misc/interceptor/PatcherDetour.h
@@ -47,16 +47,19 @@ public:
     if (!this->mVMPolicy.ShouldUnhookUponDestruction()) {
       return;
     }
 
 #if defined(_M_IX86)
     size_t nBytes = 1 + sizeof(intptr_t);
 #elif defined(_M_X64)
     size_t nBytes = 2 + sizeof(intptr_t);
+#elif defined(_M_ARM64)
+    size_t nBytes = 4;
+    MOZ_RELEASE_ASSERT(false, "Shouldn't get here");
 #else
 #error "Unknown processor type"
 #endif
 
     const auto& tramps = this->mVMPolicy.Items();
     for (auto&& tramp : tramps) {
       // First we read the pointer to the interceptor instance.
       Maybe<uintptr_t> instance = tramp.ReadEncodedPointer();
@@ -125,16 +128,18 @@ public:
       if (opcode2 != 0xBB) {
         continue;
       }
 
       origBytes.WritePointer(tramp.GetCurrentRemoteAddress());
       if (!origBytes) {
         continue;
       }
+#elif defined(_M_ARM64)
+      MOZ_RELEASE_ASSERT(false, "Shouldn't get here")
 #else
 #error "Unknown processor type"
 #endif
 
       origBytes.Commit();
     }
 
     this->mVMPolicy.Clear();
@@ -958,16 +963,18 @@ protected:
           return;
         }
         COPY_CODES(len + 1);
       } else {
         MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
         return;
       }
     }
+#elif defined(_M_ARM64)
+      MOZ_RELEASE_ASSERT(false, "Shouldn't get here")
 #else
 #error "Unknown processor type"
 #endif
 
     if (origBytes.GetOffset() > 100) {
       //printf ("Too big!");
       return;
     }
--- a/mozglue/misc/interceptor/TargetFunction.h
+++ b/mozglue/misc/interceptor/TargetFunction.h
@@ -356,17 +356,17 @@ private:
   // In an ideal world, we'd only read 5 bytes on 32-bit and 13 bytes on 64-bit,
   // to match the minimum bytes that we need to write in in order to patch the
   // target function. Since the actual opcodes will often require us to pull in
   // extra bytes above that minimum, we set the inline storage to be larger than
   // those minima in an effort to give the Vector extra wiggle room before it
   // needs to touch the heap.
 #if defined(_M_IX86)
   static const size_t kInlineStorage = 16;
-#elif defined(_M_X64)
+#elif defined(_M_X64) || defined(_M_ARM64)
   static const size_t kInlineStorage = 32;
 #endif
   Vector<uint8_t, kInlineStorage> mLocalBytes;
   bool mAccumulatedStatus;
   AutoProtect mProtect;
 };
 
 template <typename MMPolicy>
@@ -581,17 +581,17 @@ private:
   // In an ideal world, we'd only read 5 bytes on 32-bit and 13 bytes on 64-bit,
   // to match the minimum bytes that we need to write in in order to patch the
   // target function. Since the actual opcodes will often require us to pull in
   // extra bytes above that minimum, we set the inline storage to be larger than
   // those minima in an effort to give the Vector extra wiggle room before it
   // needs to touch the heap.
 #if defined(_M_IX86)
   static const size_t kInlineStorage = 16;
-#elif defined(_M_X64)
+#elif defined(_M_X64) || defined(_M_ARM64)
   static const size_t kInlineStorage = 32;
 #endif
 
   const MMPolicyOutOfProcess&     mMMPolicy;
   Vector<uint8_t, kInlineStorage> mLocalBytes;
   uint8_t const * const           mBase;
 };
 
--- a/mozglue/misc/nsWindowsDllInterceptor.h
+++ b/mozglue/misc/nsWindowsDllInterceptor.h
@@ -427,16 +427,21 @@ private:
    * TestDllInterceptor in order to detect future failures.  Even if this
    * succeeds now, updates to the detoured DLL could cause it to fail in
    * the future.
    */
   bool AddDetour(const char* aName, intptr_t aHookDest, void** aOrigFunc)
   {
     // Generally, code should not call this method directly. Use AddHook unless
     // there is a specific need to avoid nop space patches.
+#if defined(_M_ARM64)
+    // XXX: this is just to get things compiling; we'll have to add real
+    // support at some future point.
+    return false;
+#endif
 
     if (!mModule) {
       return false;
     }
 
     FARPROC proc = ::GetProcAddress(mModule, aName);
     if (!proc) {
       return false;
--- a/netwerk/base/nsChannelClassifier.cpp
+++ b/netwerk/base/nsChannelClassifier.cpp
@@ -59,19 +59,28 @@ static LazyLogModule gChannelClassifierL
 #undef LOG
 #define LOG(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Info, args)
 #define LOG_DEBUG(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Debug, args)
 #define LOG_WARN(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Warning, args)
 #define LOG_ENABLED() MOZ_LOG_TEST(gChannelClassifierLog, LogLevel::Info)
 
 #define URLCLASSIFIER_SKIP_HOSTNAMES       "urlclassifier.skipHostnames"
 #define URLCLASSIFIER_ANNOTATION_TABLE     "urlclassifier.trackingAnnotationTable"
+#define URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES "urlclassifier.trackingAnnotationTable.testEntries"
 #define URLCLASSIFIER_ANNOTATION_WHITELIST "urlclassifier.trackingAnnotationWhitelistTable"
+#define URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES "urlclassifier.trackingAnnotationWhitelistTable.testEntries"
 #define URLCLASSIFIER_TRACKING_TABLE       "urlclassifier.trackingTable"
+#define URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES "urlclassifier.trackingTable.testEntries"
 #define URLCLASSIFIER_TRACKING_WHITELIST   "urlclassifier.trackingWhitelistTable"
+#define URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES "urlclassifier.trackingWhitelistTable.testEntries"
+
+#define TABLE_TRACKING_BLACKLIST_PREF "tracking-blacklist-pref"
+#define TABLE_TRACKING_WHITELIST_PREF "tracking-whitelist-pref"
+#define TABLE_ANNOTATION_BLACKLIST_PREF "annotation-blacklist-pref"
+#define TABLE_ANNOTATION_WHITELIST_PREF "annotation-whitelist-pref"
 
 static const nsCString::size_type sMaxSpecLength = 128;
 
 // Put CachedPrefs in anonymous namespace to avoid any collision from outside of
 // this file.
 namespace {
 
 /**
@@ -86,25 +95,33 @@ public:
 
   void Init();
   bool IsAllowListExample() { return sAllowListExample;}
   bool IsLowerNetworkPriority() { return sLowerNetworkPriority;}
   bool IsAnnotateChannelEnabled() { return sAnnotateChannelEnabled;}
 
   nsCString GetSkipHostnames() const { return mSkipHostnames; }
   nsCString GetAnnotationBlackList() const { return mAnnotationBlacklist; }
+  nsCString GetAnnotationBlackListExtraEntries() const { return mAnnotationBlacklistExtraEntries; }
   nsCString GetAnnotationWhiteList() const { return mAnnotationWhitelist; }
+  nsCString GetAnnotationWhiteListExtraEntries() const { return mAnnotationWhitelistExtraEntries; }
   nsCString GetTrackingBlackList() const { return mTrackingBlacklist; }
+  nsCString GetTrackingBlackListExtraEntries() { return mTrackingBlacklistExtraEntries; }
   nsCString GetTrackingWhiteList() const { return mTrackingWhitelist; }
+  nsCString GetTrackingWhiteListExtraEntries() { return mTrackingWhitelistExtraEntries; }
 
   void SetSkipHostnames(const nsACString& aHostnames) { mSkipHostnames = aHostnames; }
   void SetAnnotationBlackList(const nsACString& aList) { mAnnotationBlacklist = aList; }
+  void SetAnnotationBlackListExtraEntries(const nsACString& aList) { mAnnotationBlacklistExtraEntries = aList; }
   void SetAnnotationWhiteList(const nsACString& aList) { mAnnotationWhitelist = aList; }
+  void SetAnnotationWhiteListExtraEntries(const nsACString& aList) { mAnnotationWhitelistExtraEntries = aList; }
   void SetTrackingBlackList(const nsACString& aList) { mTrackingBlacklist = aList; }
+  void SetTrackingBlackListExtraEntries(const nsACString& aList) { mTrackingBlacklistExtraEntries = aList; }
   void SetTrackingWhiteList(const nsACString& aList) { mTrackingWhitelist = aList; }
+  void SetTrackingWhiteListExtraEntries(const nsACString& aList) { mTrackingWhitelistExtraEntries = aList; }
 
 private:
   friend class StaticAutoPtr<CachedPrefs>;
   CachedPrefs();
   ~CachedPrefs();
 
   static void OnPrefsChange(const char* aPrefName, CachedPrefs*);
 
@@ -113,19 +130,23 @@ private:
   static bool sAnnotateChannelEnabled;
   // Whether the priority of the channels annotated as being on the tracking
   // protection list should be lowered.
   static bool sLowerNetworkPriority;
   static bool sAllowListExample;
 
   nsCString mSkipHostnames;
   nsCString mAnnotationBlacklist;
+  nsCString mAnnotationBlacklistExtraEntries;
   nsCString mAnnotationWhitelist;
+  nsCString mAnnotationWhitelistExtraEntries;
   nsCString mTrackingBlacklist;
+  nsCString mTrackingBlacklistExtraEntries;
   nsCString mTrackingWhitelist;
+  nsCString mTrackingWhitelistExtraEntries;
 
   static StaticAutoPtr<CachedPrefs> sInstance;
 };
 
 bool CachedPrefs::sAllowListExample = false;
 bool CachedPrefs::sLowerNetworkPriority = false;
 bool CachedPrefs::sAnnotateChannelEnabled = false;
 
@@ -140,30 +161,49 @@ CachedPrefs::OnPrefsChange(const char* a
     Preferences::GetCString(URLCLASSIFIER_SKIP_HOSTNAMES, skipHostnames);
     ToLowerCase(skipHostnames);
     aPrefs->SetSkipHostnames(skipHostnames);
   } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_TABLE)) {
     nsAutoCString annotationBlacklist;
     Preferences::GetCString(URLCLASSIFIER_ANNOTATION_TABLE,
                             annotationBlacklist);
     aPrefs->SetAnnotationBlackList(annotationBlacklist);
+  } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES)) {
+    nsAutoCString annotationBlacklistExtraEntries;
+    Preferences::GetCString(URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES,
+                            annotationBlacklistExtraEntries);
+    aPrefs->SetAnnotationBlackListExtraEntries(annotationBlacklistExtraEntries);
   } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_WHITELIST)) {
     nsAutoCString annotationWhitelist;
     Preferences::GetCString(URLCLASSIFIER_ANNOTATION_WHITELIST,
                             annotationWhitelist);
     aPrefs->SetAnnotationWhiteList(annotationWhitelist);
+  } else if (!strcmp(aPref, URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES)) {
+    nsAutoCString annotationWhitelistExtraEntries;
+    Preferences::GetCString(URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES,
+                            annotationWhitelistExtraEntries);
+    aPrefs->SetAnnotationWhiteListExtraEntries(annotationWhitelistExtraEntries);
   } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_WHITELIST)) {
     nsCString trackingWhitelist;
     Preferences::GetCString(URLCLASSIFIER_TRACKING_WHITELIST,
                             trackingWhitelist);
     aPrefs->SetTrackingWhiteList(trackingWhitelist);
+  } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES)) {
+    nsCString trackingWhitelistExtraEntries;
+    Preferences::GetCString(URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES,
+                            trackingWhitelistExtraEntries);
+    aPrefs->SetTrackingWhiteListExtraEntries(trackingWhitelistExtraEntries);
   } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_TABLE)) {
     nsCString trackingBlacklist;
     Preferences::GetCString(URLCLASSIFIER_TRACKING_TABLE, trackingBlacklist);
     aPrefs->SetTrackingBlackList(trackingBlacklist);
+  } else if (!strcmp(aPref, URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES)) {
+    nsCString trackingBlacklistExtraEntries;
+    Preferences::GetCString(URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES, trackingBlacklistExtraEntries);
+    aPrefs->SetTrackingBlackListExtraEntries(trackingBlacklistExtraEntries);
   }
 }
 
 void
 CachedPrefs::Init()
 {
   Preferences::AddBoolVarCache(&sAnnotateChannelEnabled,
                                "privacy.trackingprotection.annotate_channels");
@@ -171,21 +211,29 @@ CachedPrefs::Init()
                                "privacy.trackingprotection.lower_network_priority");
   Preferences::AddBoolVarCache(&sAllowListExample,
                                "channelclassifier.allowlist_example");
   Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
                                        URLCLASSIFIER_SKIP_HOSTNAMES, this);
   Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
                                        URLCLASSIFIER_ANNOTATION_TABLE, this);
   Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
+                                       URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES, this);
+  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
                                        URLCLASSIFIER_ANNOTATION_WHITELIST, this);
   Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
+                                       URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES, this);
+  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
                                        URLCLASSIFIER_TRACKING_WHITELIST, this);
   Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
+                                       URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES, this);
+  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
                                        URLCLASSIFIER_TRACKING_TABLE, this);
+  Preferences::RegisterCallbackAndCall(CachedPrefs::OnPrefsChange,
+                                       URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES, this);
 }
 
 // static
 CachedPrefs*
 CachedPrefs::GetInstance()
 {
   if (!sInstance) {
     sInstance = new CachedPrefs();
@@ -202,19 +250,23 @@ CachedPrefs::CachedPrefs()
 }
 
 CachedPrefs::~CachedPrefs()
 {
   MOZ_COUNT_DTOR(CachedPrefs);
 
   Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_SKIP_HOSTNAMES, this);
   Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_TABLE, this);
+  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_TABLE_TEST_ENTRIES, this);
   Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_WHITELIST, this);
+  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_ANNOTATION_WHITELIST_TEST_ENTRIES, this);
   Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_WHITELIST, this);
+  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_WHITELIST_TEST_ENTRIES, this);
   Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_TABLE, this);
+  Preferences::UnregisterCallback(CachedPrefs::OnPrefsChange, URLCLASSIFIER_TRACKING_TABLE_TEST_ENTRIES, this);
 }
 } // anonymous namespace
 
 static nsresult
 IsThirdParty(nsIChannel* aChannel, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   *aResult = false;
@@ -969,25 +1021,28 @@ TrackingURICallback::OnClassifyComplete(
     const nsCString annotationTable =
       CachedPrefs::GetInstance()->GetAnnotationBlackList();
     const nsCString trackingTable =
       CachedPrefs::GetInstance()->GetTrackingBlackList();
 
     bool inTrackingTable = false;
     bool inAnnotationTable = false;
 
+
     nsCCharSeparatedTokenizer tokenizer(aLists, ',');
     while (tokenizer.hasMoreTokens()) {
       const nsACString& list = tokenizer.nextToken();
       if (shouldEnableTrackingProtection && !inTrackingTable &&
-          FindInReadable(list, trackingTable)) {
+          (list == TABLE_TRACKING_BLACKLIST_PREF ||
+           FindInReadable(list, trackingTable))) {
         inTrackingTable = true;
       }
       if (shouldEnableTrackingAnnotation && !inAnnotationTable &&
-          FindInReadable(list, annotationTable)) {
+          (list == TABLE_ANNOTATION_BLACKLIST_PREF ||
+           FindInReadable(list, annotationTable))) {
         inAnnotationTable = true;
       }
     }
 
     MOZ_ASSERT(shouldEnableTrackingProtection || !inTrackingTable);
     MOZ_ASSERT(shouldEnableTrackingAnnotation || !inAnnotationTable);
 
     if ((shouldEnableTrackingProtection && inTrackingTable) ||
@@ -1020,20 +1075,24 @@ TrackingURICallback::OnClassifyComplete(
     const nsCString annotationWhitelistTable =
       CachedPrefs::GetInstance()->GetAnnotationWhiteList();
     const nsCString trackingWhitelistTable =
       CachedPrefs::GetInstance()->GetTrackingWhiteList();
 
     nsCCharSeparatedTokenizer tokenizer(aLists, ',');
     while (tokenizer.hasMoreTokens() && (isTracker || isAnnotation)) {
       const nsACString& list = tokenizer.nextToken();
-      if (isTracker && FindInReadable(list, trackingWhitelistTable)) {
+      if (isTracker &&
+          (list == TABLE_TRACKING_WHITELIST_PREF ||
+           FindInReadable(list, trackingWhitelistTable))) {
         isTracker = false;
       }
-      if (isAnnotation && FindInReadable(list, annotationWhitelistTable)) {
+      if (isAnnotation &&
+          (list == TABLE_ANNOTATION_WHITELIST_PREF ||
+           FindInReadable(list, annotationWhitelistTable))) {
         isAnnotation = false;
       }
     }
   }
 
   MOZ_ASSERT(shouldEnableTrackingProtection || !isTracker);
   MOZ_ASSERT(shouldEnableTrackingAnnotation || !isAnnotation);
 
@@ -1294,32 +1353,40 @@ nsChannelClassifier::IsTrackerWhiteliste
   }
 
   nsresult rv;
   nsCOMPtr<nsIURIClassifier> uriClassifier =
     do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString whitelist;
+  nsTArray<nsCString> whitelistExtraTables;
+  nsTArray<nsCString> whitelistExtraEntries;
   if (aUseAnnotationTable) {
     whitelist += CachedPrefs::GetInstance()->GetAnnotationWhiteList();
     whitelist += NS_LITERAL_CSTRING(",");
+    whitelistExtraTables.AppendElement(TABLE_ANNOTATION_WHITELIST_PREF);
+    whitelistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetAnnotationWhiteListExtraEntries());
   }
   if (aUseTrackingTable) {
     whitelist += CachedPrefs::GetInstance()->GetTrackingWhiteList();
+    whitelistExtraTables.AppendElement(TABLE_TRACKING_WHITELIST_PREF);
+    whitelistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetTrackingWhiteListExtraEntries());
   }
 
   if (whitelist.IsEmpty()) {
     LOG(("nsChannelClassifier[%p]:IsTrackerWhitelisted whitelist disabled",
          this));
     return aUseTrackingTable ? NS_ERROR_TRACKING_URI :
       NS_ERROR_TRACKING_ANNOTATION_URI;
   }
 
   return uriClassifier->AsyncClassifyLocalWithTables(aWhiteListURI, whitelist,
+                                                     whitelistExtraTables,
+                                                     whitelistExtraEntries,
                                                      aCallback);
 }
 
 /* static */
 nsresult
 nsChannelClassifier::SendThreatHitReport(nsIChannel *aChannel,
                                          const nsACString& aProvider,
                                          const nsACString& aList,
@@ -1427,22 +1494,28 @@ nsChannelClassifier::CheckIsTrackerWithL
 
   nsCOMPtr<nsIURI> uri;
   rv = mChannel->GetURI(getter_AddRefs(uri));
   if (NS_FAILED(rv) || !uri) {
     return rv;
   }
 
   nsAutoCString blacklist;
+  nsTArray<nsCString> blacklistExtraTables;
+  nsTArray<nsCString> blacklistExtraEntries;
   if (shouldEnableTrackingAnnotation) {
     blacklist += CachedPrefs::GetInstance()->GetAnnotationBlackList();
     blacklist += NS_LITERAL_CSTRING(",");
+    blacklistExtraTables.AppendElement(TABLE_ANNOTATION_BLACKLIST_PREF);
+    blacklistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetAnnotationBlackListExtraEntries());
   }
   if (shouldEnableTrackingProtection) {
     blacklist += CachedPrefs::GetInstance()->GetTrackingBlackList();
+    blacklistExtraTables.AppendElement(TABLE_TRACKING_BLACKLIST_PREF);
+    blacklistExtraEntries.AppendElement(CachedPrefs::GetInstance()->GetTrackingBlackListExtraEntries());
   }
   if (blacklist.IsEmpty()) {
     LOG_WARN(("nsChannelClassifier[%p]:CheckIsTrackerWithLocalTable blacklist is empty",
               this));
     return NS_ERROR_FAILURE;
   }
   // Note: duplicate lists will be removed in Classifier::SplitTables().
 
@@ -1450,17 +1523,20 @@ nsChannelClassifier::CheckIsTrackerWithL
     new TrackingURICallback(this, std::move(aCallback));
 
   if (LOG_ENABLED()) {
     nsCString spec = uri->GetSpecOrDefault();
     spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
     LOG(("nsChannelClassifier[%p]: Checking blacklist for uri=%s\n",
          this, spec.get()));
   }
-  return uriClassifier->AsyncClassifyLocalWithTables(uri, blacklist, callback);
+  return uriClassifier->AsyncClassifyLocalWithTables(uri, blacklist,
+                                                     blacklistExtraTables,
+                                                     blacklistExtraEntries,
+                                                     callback);
 }
 
 already_AddRefed<nsIChannel>
 nsChannelClassifier::GetChannel()
 {
   nsCOMPtr<nsIChannel> channel = mChannel;
   return channel.forget();
 }
--- a/netwerk/base/nsIURIClassifier.idl
+++ b/netwerk/base/nsIURIClassifier.idl
@@ -90,16 +90,18 @@ interface nsIURIClassifier : nsISupports
    * containing the given tables. This does not make network requests.
    * The callback does NOT totally follow nsIURIClassifierCallback's
    * semantics described above. Only |aList| will be meaningful, which
    * is a comma separated list of table names. (same as what classifyLocal
    * returns.)
    */
   void asyncClassifyLocalWithTables(in nsIURI aURI,
                                     in ACString aTables,
+                                    in Array<ACString> aExtraTablesByPrefs,
+                                    in Array<ACString> aExtraEntriesByPrefs,
                                     in nsIURIClassifierCallback aCallback);
   /**
    * Same as above, but returns a comma separated list of table names.
    * This is an internal interface used only for testing purposes.
    */
   ACString classifyLocal(in nsIURI aURI, in ACString aTables);
 
   /**
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -491,16 +491,17 @@ CookieServiceChild::SetCookieInternal(ns
   RecordDocumentCookie(cookie, aAttrs);
 }
 
 bool
 CookieServiceChild::RequireThirdPartyCheck()
 {
   return mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
     mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
+    mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
     mThirdPartySession ||
     mThirdPartyNonsecureSession;
 }
 
 void
 CookieServiceChild::RecordDocumentCookie(nsCookie               *aCookie,
                                          const OriginAttributes &aAttrs)
 {
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -690,33 +690,32 @@ IsContentPolicyTypeWhitelistedForFastBlo
 }
 
 bool
 nsHttpChannel::CheckFastBlocked()
 {
     LOG(("nsHttpChannel::CheckFastBlocked [this=%p]\n", this));
 
     static bool sFastBlockInited = false;
-    static bool sIsContentBlockingEnabled = false;
     static bool sIsFastBlockEnabled = false;
     static uint32_t sFastBlockTimeout = 0;
 
     if (!sFastBlockInited) {
         sFastBlockInited = true;
-        Preferences::AddBoolVarCache(&sIsContentBlockingEnabled, "browser.contentblocking.enabled");
         Preferences::AddBoolVarCache(&sIsFastBlockEnabled, "browser.fastblock.enabled");
         Preferences::AddUintVarCache(&sFastBlockTimeout, "browser.fastblock.timeout");
     }
 
     TimeStamp timestamp;
     if (NS_FAILED(GetNavigationStartTimeStamp(&timestamp))) {
         return false;
     }
 
-    if (!sIsContentBlockingEnabled || !sIsFastBlockEnabled ||
+    if (!StaticPrefs::browser_contentblocking_enabled() ||
+        !sIsFastBlockEnabled ||
         IsContentPolicyTypeWhitelistedForFastBlock(mLoadInfo) ||
         !timestamp) {
         return false;
     }
 
     TimeDuration duration = TimeStamp::NowLoRes() - timestamp;
     bool isFastBlocking = duration.ToMilliseconds() >= sFastBlockTimeout;
 
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-34274ae8c85e
+NSPR_4_20_RTM
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/nsprpub/pr/include/prinit.h
+++ b/nsprpub/pr/include/prinit.h
@@ -26,21 +26,21 @@ PR_BEGIN_EXTERN_C
 /*
 ** NSPR's version is used to determine the likelihood that the version you
 ** used to build your component is anywhere close to being compatible with
 ** what is in the underlying library.
 **
 ** The format of the version string is
 **     "<major version>.<minor version>[.<patch level>] [<Beta>]"
 */
-#define PR_VERSION  "4.20 Beta"
+#define PR_VERSION  "4.20"
 #define PR_VMAJOR   4
 #define PR_VMINOR   20
 #define PR_VPATCH   0
-#define PR_BETA     PR_TRUE
+#define PR_BETA     PR_FALSE
 
 /*
 ** PRVersionCheck
 **
 ** The basic signature of the function that is called to provide version
 ** checking. The result will be a boolean that indicates the likelihood
 ** that the underling library will perform as the caller expects.
 **
--- a/old-configure.in
+++ b/old-configure.in
@@ -2928,21 +2928,28 @@ case "$CPU_ARCH" in
       else
           dnl On x86 system with assembly optimizations disabled, the ffvp9 and
           dnl ffvp8 decoders give worse performance than libvpx ones. So we only
           dnl enable the FFmpeg FLAC decoder on those machines.
           MOZ_FFVPX_FLACONLY=1
       fi
   ;;
   arm*|aarch64)
-      MOZ_FFVPX=1
-      MOZ_FFVPX_FLACONLY=1
-      dnl Use same conditional as MOZ_LIBVPX to enable FFmpeg's ffvpx assembly decoder.
-      dnl aarch 64 FLAC decoder for now will be C only.
-      FFVPX_ASFLAGS=$VPX_ASFLAGS
+      case "$OS_TARGET" in
+        WINNT)
+          dnl don't set up anything special
+          ;;
+        *)
+          MOZ_FFVPX=1
+          MOZ_FFVPX_FLACONLY=1
+          dnl Use same conditional as MOZ_LIBVPX to enable FFmpeg's ffvpx assembly decoder.
+          dnl aarch 64 FLAC decoder for now will be C only.
+          FFVPX_ASFLAGS=$VPX_ASFLAGS
+          ;;
+      esac
   ;;
 esac
 
 if test -n "$MOZ_FFVPX"; then
   AC_DEFINE(MOZ_FFVPX)
 fi
 if test -n "$MOZ_FFVPX_FLACONLY"; then
   AC_DEFINE(MOZ_FFVPX_FLACONLY)
--- a/python/mozboot/mozboot/base.py
+++ b/python/mozboot/mozboot/base.py
@@ -293,22 +293,25 @@ class BaseBootstrapper(object):
         if not sys.executable:
             raise ValueError("cannot determine path to Python executable")
 
         cmd = [sys.executable, mach_binary, 'artifact', 'toolchain',
                '--from-build', toolchain_job]
 
         subprocess.check_call(cmd, cwd=state_dir)
 
-    def which(self, name):
+    def which(self, name, *extra_search_dirs):
         """Python implementation of which.
 
         It returns the path of an executable or None if it couldn't be found.
         """
-        for path in os.environ['PATH'].split(os.pathsep):
+        search_dirs = os.environ['PATH'].split(os.pathsep)
+        search_dirs.extend(extra_search_dirs)
+
+        for path in search_dirs:
             test = os.path.join(path, name)
             if os.path.isfile(test) and os.access(test, os.X_OK):
                 return test
 
         return None
 
     def run_as_root(self, command):
         if os.geteuid() != 0:
@@ -566,18 +569,18 @@ class BaseBootstrapper(object):
 
     def upgrade_python(self, current):
         """Upgrade Python.
 
         Child classes should reimplement this.
         """
         print(PYTHON_UNABLE_UPGRADE % (current, MODERN_PYTHON_VERSION))
 
-    def is_rust_modern(self):
-        rustc = self.which('rustc')
+    def is_rust_modern(self, cargo_bin):
+        rustc = self.which('rustc', cargo_bin)
         if not rustc:
             print('Could not find a Rust compiler.')
             return False, None
 
         our = self._parse_version(rustc)
         if not our:
             return False, None
 
@@ -611,49 +614,39 @@ class BaseBootstrapper(object):
             cargo_bin = self.win_to_msys_path(cargo_bin)
             cmd = 'export PATH=%s:$PATH' % cargo_bin
         print(template % {
             'cargo_bin': cargo_bin,
             'cmd': cmd,
         })
 
     def ensure_rust_modern(self):
-        modern, version = self.is_rust_modern()
+        cargo_home, cargo_bin = self.cargo_home()
+        modern, version = self.is_rust_modern(cargo_bin)
 
         if modern:
             print('Your version of Rust (%s) is new enough.' % version)
-            rustup = self.which('rustup')
+            rustup = self.which('rustup', cargo_bin)
             if rustup:
                 self.ensure_rust_targets(rustup)
             return
 
-        if not version:
-            # Rust wasn't in PATH. Check the standard location.
-            cargo_home, cargo_bin = self.cargo_home()
-            try_rustc = os.path.join(cargo_bin, 'rustc' + rust.exe_suffix())
-            try_cargo = os.path.join(cargo_bin, 'cargo' + rust.exe_suffix())
-            have_rustc = os.path.exists(try_rustc)
-            have_cargo = os.path.exists(try_cargo)
-            if have_rustc or have_cargo:
-                self.print_rust_path_advice(RUST_NOT_IN_PATH,
-                                            cargo_home, cargo_bin)
-                sys.exit(1)
-        else:
+        if version:
             print('Your version of Rust (%s) is too old.' % version)
 
-        rustup = self.which('rustup')
+        rustup = self.which('rustup', cargo_bin)
         if rustup:
             rustup_version = self._parse_version(rustup)
             if not rustup_version:
                 print(RUSTUP_OLD)
                 sys.exit(1)
             print('Found rustup. Will try to upgrade.')
             self.upgrade_rust(rustup)
 
-            modern, after = self.is_rust_modern()
+            modern, after = self.is_rust_modern(cargo_bin)
             if not modern:
                 print(RUST_UPGRADE_FAILED % (MODERN_RUST_VERSION, after))
                 sys.exit(1)
         else:
             # No rustup. Download and run the installer.
             print('Will try to install Rust.')
             self.install_rust()
 
--- a/python/mozboot/mozboot/mozillabuild.py
+++ b/python/mozboot/mozboot/mozillabuild.py
@@ -13,18 +13,18 @@ from mozboot.base import BaseBootstrappe
 
 class MozillaBuildBootstrapper(BaseBootstrapper):
     '''Bootstrapper for MozillaBuild to install rustup.'''
     def __init__(self, no_interactive=False, no_system_changes=False):
         BaseBootstrapper.__init__(self, no_interactive=no_interactive,
                                   no_system_changes=no_system_changes)
         print("mach bootstrap is not fully implemented in MozillaBuild")
 
-    def which(self, name):
-        return BaseBootstrapper.which(self, name + '.exe')
+    def which(self, name, *extra_search_dirs):
+        return BaseBootstrapper.which(self, name + '.exe', *extra_search_dirs)
 
     def install_system_packages(self):
         pass
 
     def ensure_mercurial_modern(self):
         # Overrides default implementation to always run pip because.
         print('Running pip to ensure Mercurial is up-to-date...')
         self.run([self.which('pip'), 'install', '--upgrade', 'Mercurial'])
--- a/python/mozboot/mozboot/windows.py
+++ b/python/mozboot/mozboot/windows.py
@@ -45,18 +45,18 @@ class WindowsBootstrapper(BaseBootstrapp
                                       'Windows. If you are testing Windows Bootstrap support, '
                                       'try `export MOZ_WINDOWS_BOOTSTRAP=1`')
         BaseBootstrapper.__init__(self, **kwargs)
         if not self.which('pacman'):
             raise NotImplementedError('The Windows bootstrapper only works with msys2 with '
                                       'pacman. Get msys2 at http://msys2.github.io/')
         print('Using an experimental bootstrapper for Windows.')
 
-    def which(self, name):
-        return BaseBootstrapper.which(self, name + '.exe')
+    def which(self, name, *extra_search_dirs):
+        return BaseBootstrapper.which(self, name + '.exe', *extra_search_dirs)
 
     def install_system_packages(self):
         self.pacman_install(*self.SYSTEM_PACKAGES)
 
     def upgrade_mercurial(self, current):
         self.pip_install('mercurial')
 
     def upgrade_python(self, current):
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-5bc69334e84f
+NSS_3_39_BETA2
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/gtests/nss_bogo_shim/config.json
+++ b/security/nss/gtests/nss_bogo_shim/config.json
@@ -1,28 +1,29 @@
 {
     "DisabledTests": {
         "### These tests break whenever we rev versions, so just leave them here for easy uncommenting":"",
-        "*TLS13Draft23*":"NSS supports draft 28 only.",
+        "*TLS13Draft*":"NSS supports RFC 8446 only.",
         "IgnoreClientVersionOrder":"Uses draft23",
         "DuplicateCertCompressionExt*":"BoGo expects that an alert is sent if more than one compression algorithm is sent.",
         "ServerBogusVersion":"Check that SH.legacy_version=TLS12 when the server picks TLS 1.3 (Bug 1443761)",
         "DummyPQPadding-Server*":"Boring is testing a dummy PQ padding extension",
         "VerifyPreferences-Enforced":"NSS sends alerts in response to errors in protected handshake messages in the clear",
         "Draft-Downgrade-Server":"Boring implements a draft downgrade sentinel used for measurements.",
         "FilterExtraAlgorithms":"NSS doesn't allow sending unsupported signature algorithms",
         "SendBogusAlertType":"Unexpected TLS alerts should abort connections (Bug 1438263)",
         "VerifyPreferences-Ed25519":"Add Ed25519 support (Bug 1325335)",
         "Ed25519DefaultDisable*":"Add Ed25519 support (Bug 1325335)",
         "ServerCipherFilter*":"Add Ed25519 support (Bug 1325335)",
         "GarbageCertificate*":"Send bad_certificate alert when certificate parsing fails (Bug 1441565)",
         "SupportedVersionSelection-TLS12":"Should maybe reject TLS 1.2 in SH.supported_versions (Bug 1438266)",
         "Resume-Server-BinderWrongLength":"Alert disagreement (Bug 1317633)",
         "Resume-Server-NoPSKBinder":"Alert disagreement (Bug 1317633)",
         "CheckRecordVersion-TLS*":"Bug 1317634",
+        "GarbageInitialRecordVersion-TLS*":"NSS doesn't strictly check the ClientHello record version",
         "GREASE-Server-TLS13":"BoringSSL GREASEs without a flag, but we ignore it",
         "TLS13-ExpectNoSessionTicketOnBadKEMode-Server":"Bug in NSS. Don't send ticket when not permitted by KE modes (Bug 1317635)",
         "*KeyUpdate*":"KeyUpdate Unimplemented",
         "ClientAuth-NoFallback-TLS13":"Disagreement about alerts. Bug 1294975",
         "SendWarningAlerts-TLS13":"NSS needs to trigger on warning alerts",
         "NoSupportedCurves":"This tests a non-spec behavior for TLS 1.2 and expects the wrong alert for TLS 1.3",
         "SendEmptyRecords":"Tests a non-spec behavior in BoGo where it chokes on too many empty records",
         "LargePlaintext":"NSS needs to check for over-long records. Bug 1294978",
--- a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
+++ b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
@@ -579,16 +579,18 @@ std::unique_ptr<const Config> ReadConfig
     cfg->AddEntry<bool>(flag, false);
   }
   cfg->AddEntry<bool>("fallback-scsv", false);
   cfg->AddEntry<bool>("false-start", false);
   cfg->AddEntry<bool>("enable-ocsp-stapling", false);
   cfg->AddEntry<bool>("write-then-read", false);
   cfg->AddEntry<bool>("require-any-client-certificate", false);
   cfg->AddEntry<bool>("verify-peer", false);
+  cfg->AddEntry<bool>("is-handshaker-supported", false);
+  cfg->AddEntry<std::string>("handshaker-path", "");  // Ignore this
   cfg->AddEntry<std::string>("advertise-alpn", "");
   cfg->AddEntry<std::string>("expect-alpn", "");
   cfg->AddEntry<std::vector<int>>("signing-prefs", std::vector<int>());
   cfg->AddEntry<std::vector<int>>("verify-prefs", std::vector<int>());
   cfg->AddEntry<int>("expect-peer-signature-algorithm", 0);
   cfg->AddEntry<std::string>("nss-cipher", "");
 
   auto rv = cfg->ParseArgs(argc, argv);
@@ -623,16 +625,21 @@ int GetExitCode(bool success) {
 }
 
 int main(int argc, char** argv) {
   std::unique_ptr<const Config> cfg = ReadConfig(argc, argv);
   if (!cfg) {
     return GetExitCode(false);
   }
 
+  if (cfg->get<bool>("is-handshaker-supported")) {
+    std::cout << "No\n";
+    return 0;
+  }
+
   if (cfg->get<bool>("server")) {
     if (SSL_ConfigServerSessionIDCache(1024, 0, 0, ".") != SECSuccess) {
       std::cerr << "Couldn't configure session cache\n";
       return 1;
     }
   }
 
   if (NSS_NoDB_Init(nullptr) != SECSuccess) {
--- a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -29,17 +29,17 @@ const static uint8_t kCannedTls13ClientH
     0x0a, 0x00, 0x12, 0x00, 0x10, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01,
     0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x33, 0x00,
     0x47, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04, 0x86, 0x4a, 0xb9, 0xdc,
     0x6a, 0x38, 0xa7, 0xce, 0xe7, 0xc2, 0x4f, 0xa6, 0x28, 0xb9, 0xdc, 0x65,
     0xbf, 0x73, 0x47, 0x3c, 0x9c, 0x65, 0x8c, 0x47, 0x6d, 0x57, 0x22, 0x8a,
     0xc2, 0xb3, 0xc6, 0x80, 0x72, 0x86, 0x08, 0x86, 0x8f, 0x52, 0xc5, 0xcb,
     0xbf, 0x2a, 0xb5, 0x59, 0x64, 0xcc, 0x0c, 0x49, 0x95, 0x36, 0xe4, 0xd9,
     0x2f, 0xd4, 0x24, 0x66, 0x71, 0x6f, 0x5d, 0x70, 0xe2, 0xa0, 0xea, 0x26,
-    0x00, 0x2b, 0x00, 0x03, 0x02, 0x7f, kD13, 0x00, 0x0d, 0x00, 0x20, 0x00,
+    0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d, 0x00, 0x20, 0x00,
     0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08,
     0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x01, 0x04,
     0x02, 0x05, 0x02, 0x06, 0x02, 0x02, 0x02};
 static const size_t kFirstFragmentSize = 20;
 static const char *k0RttData = "ABCDEF";
 
 TEST_P(TlsAgentTest, EarlyFinished) {
   DataBuffer buffer;
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -4,16 +4,19 @@
  * 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 "ssl.h"
 #include "ssl3prot.h"
 #include "sslerr.h"
 #include "sslproto.h"
 
+// This is only to get DTLS_1_3_DRAFT_VERSION
+#include "ssl3prot.h"
+
 #include <memory>
 
 #include "tls_connect.h"
 #include "tls_filter.h"
 #include "tls_parser.h"
 
 namespace nss_test {
 
@@ -926,33 +929,42 @@ TEST_P(TlsExtensionTest13, RemoveTls13Fr
   ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
 
 // 3. Server supports 1.2 and 1.3, client supports 1.2 and 1.3
 // but advertises 1.2 (because we changed things).
 TEST_P(TlsExtensionTest13, RemoveTls13FromVersionListBothV12) {
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
-#ifndef TLS_1_3_DRAFT_VERSION
-  ExpectAlert(server_, kTlsAlertIllegalParameter);
-#else
-  ExpectAlert(server_, kTlsAlertDecryptError);
+// The downgrade check is disabled in DTLS 1.3, so all that happens when we
+// tamper with the supported versions is that the Finished check fails.
+#ifdef DTLS_1_3_DRAFT_VERSION
+  if (variant_ == ssl_variant_datagram) {
+    ExpectAlert(server_, kTlsAlertDecryptError);
+  } else
 #endif
+  {
+    ExpectAlert(client_, kTlsAlertIllegalParameter);
+  }
   ConnectWithReplacementVersionList(SSL_LIBRARY_VERSION_TLS_1_2);
-#ifndef TLS_1_3_DRAFT_VERSION
-  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
-  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
-#else
-  client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
-  server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+#ifdef DTLS_1_3_DRAFT_VERSION
+  if (variant_ == ssl_variant_datagram) {
+    client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+    server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+  } else
 #endif
+  {
+    client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+    server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+  }
 }
 
 TEST_P(TlsExtensionTest13, HrrThenRemoveSignatureAlgorithms) {
   ExpectAlert(server_, kTlsAlertMissingExtension);
   HrrThenRemoveExtensionsTest(ssl_signature_algorithms_xtn,
                               SSL_ERROR_MISSING_EXTENSION_ALERT,
                               SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
 }
--- a/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
@@ -10,16 +10,17 @@
 namespace nss_test {
 
 class GatherV2ClientHelloTest : public TlsConnectTestBase {
  public:
   GatherV2ClientHelloTest() : TlsConnectTestBase(ssl_variant_stream, 0) {}
 
   void ConnectExpectMalformedClientHello(const DataBuffer &data) {
     EnsureTlsSetup();
+    server_->SetOption(SSL_ENABLE_V2_COMPATIBLE_HELLO, PR_TRUE);
     server_->ExpectSendAlert(kTlsAlertIllegalParameter);
     client_->SendDirect(data);
     server_->StartConnect();
     server_->Handshake();
     ASSERT_TRUE_WAIT(
         (server_->error_code() == SSL_ERROR_RX_MALFORMED_CLIENT_HELLO), 2000);
   }
 };
--- a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "secerr.h"
 #include "ssl.h"
 #include "sslerr.h"
 #include "sslproto.h"
 
-// This is internal, just to get TLS_1_3_DRAFT_VERSION.
+// This is internal, just to get DTLS_1_3_DRAFT_VERSION.
 #include "ssl3prot.h"
 
 #include "gtest_utils.h"
 #include "scoped_ptrs.h"
 #include "tls_connect.h"
 #include "tls_filter.h"
 #include "tls_parser.h"
 
@@ -1002,17 +1002,20 @@ class HelloRetryRequestAgentTest : publi
     i = hrr_data.Write(i, static_cast<uint32_t>(0), 1);  // session_id
     i = hrr_data.Write(i, TLS_AES_128_GCM_SHA256, 2);
     i = hrr_data.Write(i, ssl_compression_null, 1);
     // Add extensions.  First a length, which includes the supported version.
     i = hrr_data.Write(i, static_cast<uint32_t>(len) + 6, 2);
     // Now the supported version.
     i = hrr_data.Write(i, ssl_tls13_supported_versions_xtn, 2);
     i = hrr_data.Write(i, 2, 2);
-    i = hrr_data.Write(i, 0x7f00 | TLS_1_3_DRAFT_VERSION, 2);
+    i = hrr_data.Write(i, (variant_ == ssl_variant_datagram)
+                              ? (0x7f00 | DTLS_1_3_DRAFT_VERSION)
+                              : SSL_LIBRARY_VERSION_TLS_1_3,
+                       2);
     if (len) {
       hrr_data.Write(i, body, len);
     }
     DataBuffer hrr;
     MakeHandshakeMessage(kTlsHandshakeServerHello, hrr_data.data(),
                          hrr_data.len(), &hrr, seq_num);
     MakeRecord(ssl_ct_handshake, SSL_LIBRARY_VERSION_TLS_1_3, hrr.data(),
                hrr.len(), hrr_record, seq_num);
--- a/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
@@ -146,16 +146,17 @@ class SSLv2ClientHelloTestF : public Tls
       : TlsConnectTestBase(ssl_variant_stream, 0), filter_(nullptr) {}
 
   SSLv2ClientHelloTestF(SSLProtocolVariant variant, uint16_t version)
       : TlsConnectTestBase(variant, version), filter_(nullptr) {}
 
   void SetUp() override {
     TlsConnectTestBase::SetUp();
     filter_ = MakeTlsFilter<SSLv2ClientHelloFilter>(client_, version_);
+    server_->SetOption(SSL_ENABLE_V2_COMPATIBLE_HELLO, PR_TRUE);
   }
 
   void SetExpectedVersion(uint16_t version) {
     TlsConnectTestBase::SetExpectedVersion(version);
     filter_->SetVersion(version);
   }
 
   void SetAvailableCipherSuite(uint16_t cipher) {
@@ -192,16 +193,37 @@ class SSLv2ClientHelloTest : public SSLv
 };
 
 // Test negotiating TLS 1.0 - 1.2.
 TEST_P(SSLv2ClientHelloTest, Connect) {
   SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
   Connect();
 }
 
+TEST_P(SSLv2ClientHelloTest, ConnectDisabled) {
+  server_->SetOption(SSL_ENABLE_V2_COMPATIBLE_HELLO, PR_FALSE);
+  SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
+
+  StartConnect();
+  client_->Handshake();  // Send the modified ClientHello.
+  server_->Handshake();  // Read some.
+  // The problem here is that the v2 ClientHello puts the version where the v3
+  // ClientHello puts a version number.  So the version number (0x0301+) appears
+  // to be a length and server blocks waiting for that much data.
+  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+  // This is usually what happens with v2-compatible: the server hangs.
+  // But to be certain, feed in more data to see if an error comes out.
+  uint8_t zeros[SSL_LIBRARY_VERSION_TLS_1_2] = {0};
+  client_->SendDirect(DataBuffer(zeros, sizeof(zeros)));
+  ExpectAlert(server_, kTlsAlertIllegalParameter);
+  server_->Handshake();
+  client_->Handshake();
+}
+
 // Sending a v2 ClientHello after a no-op v3 record must fail.
 TEST_P(SSLv2ClientHelloTest, ConnectAfterEmptyV3Record) {
   DataBuffer buffer;
 
   size_t idx = 0;
   idx = buffer.Write(idx, 0x16, 1);    // handshake
   idx = buffer.Write(idx, 0x0301, 2);  // record_version
   (void)buffer.Write(idx, 0U, 2);      // length=0
--- a/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
@@ -43,100 +43,145 @@ TEST_P(TlsConnectGeneric, ServerNegotiat
 
   uint16_t minver, maxver;
   client_->GetVersionRange(&minver, &maxver);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, maxver);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   Connect();
 }
-#ifndef TLS_1_3_DRAFT_VERSION
 
 // Test the ServerRandom version hack from
 // [draft-ietf-tls-tls13-11 Section 6.3.1.1].
 // The first three tests test for active tampering. The next
 // two validate that we can also detect fallback using the
 // SSL_SetDowngradeCheckVersion() API.
 TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
   MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
                                              SSL_LIBRARY_VERSION_TLS_1_1);
-  ConnectExpectFail();
-  ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
-/* Attempt to negotiate the bogus DTLS 1.1 version. */
+// Attempt to negotiate the bogus DTLS 1.1 version.
 TEST_F(DtlsConnectTest, TestDtlsVersion11) {
   MakeTlsFilter<TlsClientHelloVersionSetter>(client_, ((~0x0101) & 0xffff));
-  ConnectExpectFail();
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   // It's kind of surprising that SSL_ERROR_NO_CYPHER_OVERLAP is
   // what is returned here, but this is deliberate in ssl3_HandleAlert().
-  EXPECT_EQ(SSL_ERROR_NO_CYPHER_OVERLAP, client_->error_code());
-  EXPECT_EQ(SSL_ERROR_UNSUPPORTED_VERSION, server_->error_code());
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
 }
 
-// Disabled as long as we have draft version.
 TEST_F(TlsConnectTest, TestDowngradeDetectionToTls12) {
-  EnsureTlsSetup();
-  MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
-                                             SSL_LIBRARY_VERSION_TLS_1_2);
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
+  MakeTlsFilter<TlsExtensionDropper>(client_, ssl_tls13_supported_versions_xtn);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
-  ConnectExpectFail();
-  ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+// Disabling downgrade checks will be caught when the Finished MAC check fails.
+TEST_F(TlsConnectTest, TestDisableDowngradeDetection) {
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_FALSE);
+  MakeTlsFilter<TlsExtensionDropper>(client_, ssl_tls13_supported_versions_xtn);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  ConnectExpectAlert(server_, kTlsAlertDecryptError);
+  client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+  server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 // TLS 1.1 clients do not check the random values, so we should
 // instead get a handshake failure alert from the server.
 TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
+  // Setting the option here has no effect.
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
   MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
                                              SSL_LIBRARY_VERSION_TLS_1_0);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
                            SSL_LIBRARY_VERSION_TLS_1_1);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
                            SSL_LIBRARY_VERSION_TLS_1_2);
-  ConnectExpectFail();
-  ASSERT_EQ(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE, server_->error_code());
-  ASSERT_EQ(SSL_ERROR_DECRYPT_ERROR_ALERT, client_->error_code());
+  ConnectExpectAlert(server_, kTlsAlertDecryptError);
+  server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+  client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
 }
 
 TEST_F(TlsConnectTest, TestFallbackFromTls12) {
-  EnsureTlsSetup();
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
   client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_1);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_2);
-  ConnectExpectFail();
-  ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+static SECStatus AllowFalseStart(PRFileDesc* fd, void* arg,
+                                 PRBool* can_false_start) {
+  bool* false_start_attempted = reinterpret_cast<bool*>(arg);
+  *false_start_attempted = true;
+  *can_false_start = PR_TRUE;
+  return SECSuccess;
+}
+
+// If we disable the downgrade check, the sentinel is still generated, and we
+// disable false start instead.
+TEST_F(TlsConnectTest, DisableFalseStartOnFallback) {
+  // Don't call client_->EnableFalseStart(), because that sets the client up for
+  // success, and we want false start to fail.
+  client_->SetOption(SSL_ENABLE_FALSE_START, PR_TRUE);
+  bool false_start_attempted = false;
+  EXPECT_EQ(SECSuccess,
+            SSL_SetCanFalseStartCallback(client_->ssl_fd(), AllowFalseStart,
+                                         &false_start_attempted));
+
+  client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_2);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  Connect();
+  EXPECT_FALSE(false_start_attempted);
 }
 
 TEST_F(TlsConnectTest, TestFallbackFromTls13) {
-  EnsureTlsSetup();
+  client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
   client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
-  ConnectExpectFail();
-  ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
-#endif
 
 TEST_P(TlsConnectGeneric, TestFallbackSCSVVersionMatch) {
   client_->SetOption(SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
   Connect();
 }
 
 TEST_P(TlsConnectGenericPre13, TestFallbackSCSVVersionMismatch) {
   client_->SetOption(SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
   server_->SetVersionRange(version_, version_ + 1);
   ConnectExpectAlert(server_, kTlsAlertInappropriateFallback);
   client_->CheckErrorCode(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT);
+  server_->CheckErrorCode(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT);
 }
 
 // The TLS v1.3 spec section C.4 states that 'Implementations MUST NOT send or
 // accept any records with a version less than { 3, 0 }'. Thus we will not
 // allow version ranges including both SSL v3 and TLS v1.3.
 TEST_F(TlsConnectTest, DisallowSSLv3HelloWithTLSv13Enabled) {
   SECStatus rv;
   SSLVersionRange vrange = {SSL_LIBRARY_VERSION_3_0,
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -10,16 +10,19 @@
 #include "pk11func.h"
 #include "ssl.h"
 #include "sslerr.h"
 #include "sslexp.h"
 #include "sslproto.h"
 #include "tls_filter.h"
 #include "tls_parser.h"
 
+// This is an internal header, used to get DTLS_1_3_DRAFT_VERSION.
+#include "ssl3prot.h"
+
 extern "C" {
 // This is not something that should make you happy.
 #include "libssl_internals.h"
 }
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
@@ -48,17 +51,17 @@ const std::string TlsAgent::kServerDsa =
 static const uint8_t kCannedTls13ServerHello[] = {
     0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
     0xf0, 0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b,
     0xdf, 0xe5, 0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76,
     0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24,
     0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf, 0x23, 0x17, 0x64, 0x23, 0x03,
     0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65, 0x24, 0xa1, 0x6c, 0xa9,
     0x80, 0x8f, 0x2c, 0xac, 0x0a, 0xea, 0x53, 0x3a, 0xcb, 0xe3, 0x08,
-    0x84, 0xae, 0x19, 0x00, 0x2b, 0x00, 0x02, 0x7f, kD13};
+    0x84, 0xae, 0x19, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04};
 
 TlsAgent::TlsAgent(const std::string& nm, Role rl, SSLProtocolVariant var)
     : name_(nm),
       variant_(var),
       role_(rl),
       server_key_bits_(0),
       adapter_(new DummyPrSocket(role_str(), var)),
       ssl_fd_(nullptr),
@@ -1169,13 +1172,18 @@ void TlsAgentTestBase::MakeTrivialHandsh
     index = out->Write(index, 1, 1);
   }
 }
 
 DataBuffer TlsAgentTestBase::MakeCannedTls13ServerHello() {
   DataBuffer sh(kCannedTls13ServerHello, sizeof(kCannedTls13ServerHello));
   if (variant_ == ssl_variant_datagram) {
     sh.Write(0, SSL_LIBRARY_VERSION_DTLS_1_2_WIRE, 2);
+    // The version should be at the end.
+    uint32_t v;
+    EXPECT_TRUE(sh.Read(sh.len() - 2, 2, &v));
+    EXPECT_EQ(static_cast<uint32_t>(SSL_LIBRARY_VERSION_TLS_1_3), v);
+    sh.Write(sh.len() - 2, 0x7f00 | DTLS_1_3_DRAFT_VERSION, 2);
   }
   return sh;
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -5,19 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef tls_agent_h_
 #define tls_agent_h_
 
 #include "prio.h"
 #include "ssl.h"
 
-// This is an internal header, used to get TLS_1_3_DRAFT_VERSION.
-#include "ssl3prot.h"
-
 #include <functional>
 #include <iostream>
 
 #include "test_io.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "scoped_ptrs.h"
@@ -55,18 +52,16 @@ typedef std::function<SECStatus(TlsAgent
     AuthCertificateCallbackFunction;
 
 typedef std::function<void(TlsAgent* agent)> HandshakeCallbackFunction;
 
 typedef std::function<int32_t(TlsAgent* agent, const SECItem* srvNameArr,
                               PRUint32 srvNameArrSize)>
     SniCallbackFunction;
 
-static const uint8_t kD13 = TLS_1_3_DRAFT_VERSION;
-
 class TlsAgent : public PollTarget {
  public:
   enum Role { CLIENT, SERVER };
   enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED, STATE_ERROR };
 
   static const std::string kClient;     // the client key is sign only
   static const std::string kRsa2048;    // bigger sign and encrypt for either
   static const std::string kRsa8192;    // biggest sign and encrypt for either
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -277,16 +277,33 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
  * are dropped if there is reordering.
  *
  * This applies to TLS 1.3 only.  This is not a parameter that is negotiated
  * during the TLS handshake. Unlike other socket options, this option can be
  * changed after a handshake is complete.
  */
 #define SSL_ENABLE_DTLS_SHORT_HEADER 36
 
+/*
+ * Enables the processing of the downgrade sentinel that can be added to the
+ * ServerHello.random by a server that supports Section 4.1.3 of TLS 1.3
+ * [RFC8446].  This sentinel will always be generated by a server that
+ * negotiates a version lower than its maximum, this only controls whether a
+ * client will treat receipt of a value that indicates a downgrade as an error.
+ */
+#define SSL_ENABLE_HELLO_DOWNGRADE_CHECK 37
+
+/* Enables the SSLv2-compatible ClientHello for servers. NSS does not support
+ * SSLv2 and will never send an SSLv2-compatible ClientHello as a client.  An
+ * NSS server with this option enabled will accept a ClientHello that is
+ * v2-compatible as defined in Appendix E.1 of RFC 6101.
+ *
+ * This is disabled by default and will be removed in a future version. */
+#define SSL_ENABLE_V2_COMPATIBLE_HELLO 38
+
 #ifdef SSL_DEPRECATED_FUNCTION
 /* Old deprecated function names */
 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
 SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRIntn on);
 #endif
 
 /* Set (and get) options for sockets and defaults for newly created sockets.
  *
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -6393,35 +6393,67 @@ ssl_CheckServerSessionIdCorrectness(sslS
     if (sentRealSid || sentFakeSid) {
         return sidMatch;
     }
 
     /* TLS 1.3: The server shouldn't send a session ID. */
     return sidBytes->len == 0;
 }
 
+static SECStatus
+ssl_CheckServerRandom(sslSocket *ss)
+{
+    /* Check the ServerHello.random per [RFC 8446 Section 4.1.3].
+     *
+     * TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below
+     * MUST check that the last 8 bytes are not equal to either of these
+     * values.  TLS 1.2 clients SHOULD also check that the last 8 bytes are
+     * not equal to the second value if the ServerHello indicates TLS 1.1 or
+     * below.  If a match is found, the client MUST abort the handshake with
+     * an "illegal_parameter" alert.
+     */
+    SSL3ProtocolVersion checkVersion =
+        ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion
+                                       : ss->vrange.max;
+
+    if (checkVersion >= SSL_LIBRARY_VERSION_TLS_1_2 &&
+        checkVersion > ss->version) {
+        /* Both sections use the same sentinel region. */
+        PRUint8 *downgrade_sentinel =
+            ss->ssl3.hs.server_random +
+            SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
+        if (!PORT_Memcmp(downgrade_sentinel,
+                         tls13_downgrade_random,
+                         sizeof(tls13_downgrade_random)) ||
+            !PORT_Memcmp(downgrade_sentinel,
+                         tls12_downgrade_random,
+                         sizeof(tls12_downgrade_random))) {
+            return SECFailure;
+        }
+    }
+
+    return SECSuccess;
+}
+
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 ServerHello message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     PRUint32 cipher;
     int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
     PRUint32 compression;
     SECStatus rv;
     SECItem sidBytes = { siBuffer, NULL, 0 };
     PRBool isHelloRetry;
     SSL3AlertDescription desc = illegal_parameter;
     const PRUint8 *savedMsg = b;
     const PRUint32 savedLength = length;
-#ifndef TLS_1_3_DRAFT_VERSION
-    SSL3ProtocolVersion downgradeCheckVersion;
-#endif
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->ssl3.hs.ws != wait_server_hello) {
         errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO;
@@ -6548,49 +6580,29 @@ ssl3_HandleServerHello(sslSocket *ss, PR
      * us to be getting this version number, but it's what we have.
      * (1294697). */
     if (ss->firstHsDone && (ss->version != ss->ssl3.crSpec->version)) {
         desc = protocol_version;
         errCode = SSL_ERROR_UNSUPPORTED_VERSION;
         goto alert_loser;
     }
 
-#ifndef TLS_1_3_DRAFT_VERSION
-    /* Check the ServerHello.random per
-     * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
-     *
-     * TLS 1.3 clients receiving a TLS 1.2 or below ServerHello MUST check
-     * that the top eight octets are not equal to either of these values.
-     * TLS 1.2 clients SHOULD also perform this check if the ServerHello
-     * indicates TLS 1.1 or below.  If a match is found the client MUST
-     * abort the handshake with a fatal "illegal_parameter" alert.
-     *
-     * Disable this test during the TLS 1.3 draft version period.
-     */
-    downgradeCheckVersion = ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion
-                                                           : ss->vrange.max;
-
-    if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 &&
-        downgradeCheckVersion > ss->version) {
-        /* Both sections use the same sentinel region. */
-        PRUint8 *downgrade_sentinel =
-            ss->ssl3.hs.server_random +
-            SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
-        if (!PORT_Memcmp(downgrade_sentinel,
-                         tls13_downgrade_random,
-                         sizeof(tls13_downgrade_random)) ||
-            !PORT_Memcmp(downgrade_sentinel,
-                         tls12_downgrade_random,
-                         sizeof(tls12_downgrade_random))) {
+    if (ss->opt.enableHelloDowngradeCheck
+#ifdef DTLS_1_3_DRAFT_VERSION
+        /* Disable this check while we are on draft DTLS 1.3 versions. */
+        && !IS_DTLS(ss)
+#endif
+            ) {
+        rv = ssl_CheckServerRandom(ss);
+        if (rv != SECSuccess) {
             desc = illegal_parameter;
             errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
             goto alert_loser;
         }
     }
-#endif
 
     /* Finally, now all the version-related checks have passed. */
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
     /* Update the write cipher spec to match the version. But not after
      * HelloRetryRequest, because cwSpec might be a 0-RTT cipher spec,
      * in which case this is a no-op. */
     if (!ss->firstHsDone && !isHelloRetry) {
         ssl_GetSpecWriteLock(ss);
@@ -7421,26 +7433,35 @@ ssl3_CheckFalseStart(sslSocket *ss)
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(!ss->ssl3.hs.authCertificatePending);
     PORT_Assert(!ss->ssl3.hs.canFalseStart);
 
     if (!ss->canFalseStartCallback) {
         SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start",
                     SSL_GETPID(), ss->fd));
     } else {
-        PRBool maybeFalseStart;
+        PRBool maybeFalseStart = PR_TRUE;
         SECStatus rv;
 
+        rv = ssl_CheckServerRandom(ss);
+        if (rv != SECSuccess) {
+            SSL_TRC(3, ("%d: SSL[%d]: no false start due to possible downgrade",
+                        SSL_GETPID(), ss->fd));
+            maybeFalseStart = PR_FALSE;
+        }
+
         /* An attacker can control the selected ciphersuite so we only wish to
          * do False Start in the case that the selected ciphersuite is
          * sufficiently strong that the attack can gain no advantage.
          * Therefore we always require an 80-bit cipher. */
-        ssl_GetSpecReadLock(ss);
-        maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10;
-        ssl_ReleaseSpecReadLock(ss);
+        if (maybeFalseStart) {
+            ssl_GetSpecReadLock(ss);
+            maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10;
+            ssl_ReleaseSpecReadLock(ss);
+        }
 
         if (!maybeFalseStart) {
             SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher",
                         SSL_GETPID(), ss->fd));
         } else {
             PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
                         ssl_preinfo_all);
             rv = (ss->canFalseStartCallback)(ss->fd,
@@ -8093,16 +8114,72 @@ ssl3_SelectServerCert(sslSocket *ss)
             ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
         return SECSuccess;
     }
 
     PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
     return SECFailure;
 }
 
+static SECStatus
+ssl_GenerateServerRandom(sslSocket *ss)
+{
+    SECStatus rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    if (ss->version == ss->vrange.max) {
+        return SECSuccess;
+    }
+#ifdef DTLS_1_3_DRAFT_VERSION
+    if (IS_DTLS(ss)) {
+        return SECSuccess;
+    }
+#endif
+
+    /*
+     * [RFC 8446 Section 4.1.3].
+     *
+     * TLS 1.3 servers which negotiate TLS 1.2 or below in response to a
+     * ClientHello MUST set the last 8 bytes of their Random value specially in
+     * their ServerHello.
+     *
+     * If negotiating TLS 1.2, TLS 1.3 servers MUST set the last 8 bytes of
+     * their Random value to the bytes:
+     *
+     *   44 4F 57 4E 47 52 44 01
+     *
+     * If negotiating TLS 1.1 or below, TLS 1.3 servers MUST, and TLS 1.2
+     * servers SHOULD, set the last 8 bytes of their ServerHello.Random value to
+     * the bytes:
+     *
+     *   44 4F 57 4E 47 52 44 00
+     */
+    PRUint8 *downgradeSentinel =
+        ss->ssl3.hs.server_random +
+        SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
+
+    switch (ss->vrange.max) {
+        case SSL_LIBRARY_VERSION_TLS_1_3:
+            PORT_Memcpy(downgradeSentinel,
+                        tls13_downgrade_random, sizeof(tls13_downgrade_random));
+            break;
+        case SSL_LIBRARY_VERSION_TLS_1_2:
+            PORT_Memcpy(downgradeSentinel,
+                        tls12_downgrade_random, sizeof(tls12_downgrade_random));
+            break;
+        default:
+            /* Do not change random. */
+            break;
+    }
+
+    return SECSuccess;
+}
+
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Client Hello message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     sslSessionID *sid = NULL;
@@ -8287,66 +8364,16 @@ ssl3_HandleClientHello(sslSocket *ss, PR
         rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.fakeSid, &sidBytes);
         if (rv != SECSuccess) {
             desc = internal_error;
             errCode = PORT_GetError();
             goto alert_loser;
         }
     }
 
-    /* Generate the Server Random now so it is available
-     * when we process the ClientKeyShare in TLS 1.3 */
-    rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random);
-    if (rv != SECSuccess) {
-        errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE;
-        goto loser;
-    }
-
-#ifndef TLS_1_3_DRAFT_VERSION
-    /*
-     * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
-     * TLS 1.3 server implementations which respond to a ClientHello with a
-     * client_version indicating TLS 1.2 or below MUST set the last eight
-     * bytes of their Random value to the bytes:
-     *
-     * 44 4F 57 4E 47 52 44 01
-     *
-     * TLS 1.2 server implementations which respond to a ClientHello with a
-     * client_version indicating TLS 1.1 or below SHOULD set the last eight
-     * bytes of their Random value to the bytes:
-     *
-     * 44 4F 57 4E 47 52 44 00
-     *
-     * TODO(ekr@rtfm.com): Note this change was not added in the SSLv2
-     * compat processing code since that will most likely be removed before
-     * we ship the final version of TLS 1.3. Bug 1306672.
-     */
-    if (ss->vrange.max > ss->version) {
-        PRUint8 *downgrade_sentinel =
-            ss->ssl3.hs.server_random +
-            SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
-
-        switch (ss->vrange.max) {
-            case SSL_LIBRARY_VERSION_TLS_1_3:
-                PORT_Memcpy(downgrade_sentinel,
-                            tls13_downgrade_random,
-                            sizeof(tls13_downgrade_random));
-                break;
-            case SSL_LIBRARY_VERSION_TLS_1_2:
-                PORT_Memcpy(downgrade_sentinel,
-                            tls12_downgrade_random,
-                            sizeof(tls12_downgrade_random));
-                break;
-            default:
-                /* Do not change random. */
-                break;
-        }
-    }
-#endif
-
     /* If there is a cookie, then this is a second ClientHello (TLS 1.3). */
     if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) {
         ss->ssl3.hs.helloRetry = PR_TRUE;
     }
 
     if (ss->ssl3.hs.receivedCcs) {
         /* This is only valid if we sent HelloRetryRequest, so we should have
          * negotiated TLS 1.3 and there should be a cookie extension. */
@@ -9083,28 +9110,37 @@ loser:
 
 SECStatus
 ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
                          const sslBuffer *extensionBuf, sslBuffer *messageBuf)
 {
     SECStatus rv;
     SSL3ProtocolVersion version;
     sslSessionID *sid = ss->sec.ci.sid;
+    const PRUint8 *random;
 
     version = PR_MIN(ss->version, SSL_LIBRARY_VERSION_TLS_1_2);
     if (IS_DTLS(ss)) {
         version = dtls_TLSVersionToDTLSVersion(version);
     }
     rv = sslBuffer_AppendNumber(messageBuf, version, 2);
     if (rv != SECSuccess) {
         return SECFailure;
     }
-    /* Random already generated in ssl3_HandleClientHello */
-    rv = sslBuffer_Append(messageBuf, helloRetry ? ssl_hello_retry_random : ss->ssl3.hs.server_random,
-                          SSL3_RANDOM_LENGTH);
+
+    if (helloRetry) {
+        random = ssl_hello_retry_random;
+    } else {
+        rv = ssl_GenerateServerRandom(ss);
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
+        random = ss->ssl3.hs.server_random;
+    }
+    rv = sslBuffer_Append(messageBuf, random, SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         if (sid) {
             rv = sslBuffer_AppendVariable(messageBuf, sid->u.ssl3.sessionID,
                                           sid->u.ssl3.sessionIDLength, 1);
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -465,32 +465,32 @@ ssl3_GatherCompleteHandshake(sslSocket *
             PORT_Assert(!IS_DTLS(ss));
             rv = ssl3_HandleNonApplicationData(ss, ssl_ct_handshake,
                                                0, 0, &ss->gs.buf);
         } else {
             /* State for SSLv2 client hello support. */
             ssl2Gather ssl2gs = { PR_FALSE, 0 };
             ssl2Gather *ssl2gs_ptr = NULL;
 
-            /* If we're a server and waiting for a client hello, accept v2. */
-            if (ss->sec.isServer && ss->ssl3.hs.ws == wait_client_hello) {
+            if (ss->sec.isServer && ss->opt.enableV2CompatibleHello &&
+                ss->ssl3.hs.ws == wait_client_hello) {
                 ssl2gs_ptr = &ssl2gs;
             }
 
             /* bring in the next sslv3 record. */
             if (ss->recvdCloseNotify) {
                 /* RFC 5246 Section 7.2.1:
                  *   Any data received after a closure alert is ignored.
                  */
                 return 0;
             }
 
             if (!IS_DTLS(ss)) {
-                /* If we're a server waiting for a ClientHello then pass
-                 * ssl2gs to support SSLv2 ClientHello messages. */
+                /* Passing a non-NULL ssl2gs here enables detection of
+                 * SSLv2-compatible ClientHello messages. */
                 rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr);
             } else {
                 rv = dtls_GatherData(ss, &ss->gs, flags);
 
                 /* If we got a would block error, that means that no data was
                  * available, so we check the timer to see if it's time to
                  * retransmit */
                 if (rv == SECFailure &&
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -8,20 +8,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __ssl3proto_h_
 #define __ssl3proto_h_
 
 typedef PRUint16 SSL3ProtocolVersion;
 /* version numbers are defined in sslproto.h */
 
-/* The TLS 1.3 draft version. Used to avoid negotiating
- * between incompatible pre-standard TLS 1.3 drafts.
- * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */
-#define TLS_1_3_DRAFT_VERSION 28
+/* DTLS 1.3 is still a draft. */
+#define DTLS_1_3_DRAFT_VERSION 28
 
 typedef PRUint16 ssl3CipherSuite;
 /* The cipher suites are defined in sslproto.h */
 
 #define MAX_CERT_TYPES 10
 #define MAX_MAC_LENGTH 64
 #define MAX_PADDING_LENGTH 64
 #define MAX_KEY_LENGTH 64
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -261,16 +261,18 @@ typedef struct sslOptionsStr {
     unsigned int enableFallbackSCSV : 1;
     unsigned int enableServerDhe : 1;
     unsigned int enableExtendedMS : 1;
     unsigned int enableSignedCertTimestamps : 1;
     unsigned int requireDHENamedGroups : 1;
     unsigned int enable0RttData : 1;
     unsigned int enableTls13CompatMode : 1;
     unsigned int enableDtlsShortHeader : 1;
+    unsigned int enableHelloDowngradeCheck : 1;
+    unsigned int enableV2CompatibleHello : 1;
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
                sslHandshakingAsClient,
                sslHandshakingAsServer
 } sslHandshakingType;
 
 #define SSL_LOCK_RANK_SPEC 255
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -77,17 +77,19 @@ static sslOptions ssl_defaults = {
     .reuseServerECDHEKey = PR_TRUE,
     .enableFallbackSCSV = PR_FALSE,
     .enableServerDhe = PR_TRUE,
     .enableExtendedMS = PR_FALSE,
     .enableSignedCertTimestamps = PR_FALSE,
     .requireDHENamedGroups = PR_FALSE,
     .enable0RttData = PR_FALSE,
     .enableTls13CompatMode = PR_FALSE,
-    .enableDtlsShortHeader = PR_FALSE
+    .enableDtlsShortHeader = PR_FALSE,
+    .enableHelloDowngradeCheck = PR_FALSE,
+    .enableV2CompatibleHello = PR_FALSE
 };
 
 /*
  * default range of enabled SSL/TLS protocols
  */
 static SSLVersionRange versions_defaults_stream = {
     SSL_LIBRARY_VERSION_TLS_1_0,
     SSL_LIBRARY_VERSION_TLS_1_2
@@ -816,16 +818,24 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             ss->opt.enableTls13CompatMode = val;
             break;
 
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             ss->opt.enableDtlsShortHeader = val;
             break;
 
+        case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+            ss->opt.enableHelloDowngradeCheck = val;
+            break;
+
+        case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+            ss->opt.enableV2CompatibleHello = val;
+            break;
+
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
     }
 
     /* We can't use the macros for releasing the locks here,
      * because ss->opt.noLocks might have changed just above.
      * We must release these locks (monitors) here, if we aquired them above,
@@ -958,16 +968,22 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
             val = ss->opt.recordSizeLimit;
             break;
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             val = ss->opt.enableTls13CompatMode;
             break;
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             val = ss->opt.enableDtlsShortHeader;
             break;
+        case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+            val = ss->opt.enableHelloDowngradeCheck;
+            break;
+        case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+            val = ss->opt.enableV2CompatibleHello;
+            break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
     }
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_Release1stHandshakeLock(ss);
 
@@ -1084,16 +1100,22 @@ SSL_OptionGetDefault(PRInt32 which, PRIn
             val = ssl_defaults.recordSizeLimit;
             break;
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             val = ssl_defaults.enableTls13CompatMode;
             break;
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             val = ssl_defaults.enableDtlsShortHeader;
             break;
+        case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+            val = ssl_defaults.enableHelloDowngradeCheck;
+            break;
+        case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+            val = ssl_defaults.enableV2CompatibleHello;
+            break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
     }
 
     *pVal = val;
     return rv;
 }
@@ -1279,16 +1301,24 @@ SSL_OptionSetDefault(PRInt32 which, PRIn
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             ssl_defaults.enableTls13CompatMode = val;
             break;
 
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             ssl_defaults.enableDtlsShortHeader = val;
             break;
 
+        case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+            ssl_defaults.enableHelloDowngradeCheck = val;
+            break;
+
+        case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+            ssl_defaults.enableV2CompatibleHello = val;
+            break;
+
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             return SECFailure;
     }
     return SECSuccess;
 }
 
 SECStatus
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -5268,31 +5268,31 @@ tls13_HandleEarlyApplicationData(sslSock
     PR_APPEND_LINK(&ed->link, &ss->ssl3.hs.bufferedEarlyData);
 
     origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
 
     return SECSuccess;
 }
 
 PRUint16
-tls13_EncodeDraftVersion(SSL3ProtocolVersion version)
+tls13_EncodeDraftVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant)
 {
-#ifdef TLS_1_3_DRAFT_VERSION
-    if (version == SSL_LIBRARY_VERSION_TLS_1_3) {
-        return 0x7f00 | TLS_1_3_DRAFT_VERSION;
+#ifdef DTLS_1_3_DRAFT_VERSION
+    if (version == SSL_LIBRARY_VERSION_TLS_1_3 &&
+        variant == ssl_variant_datagram) {
+        return 0x7f00 | DTLS_1_3_DRAFT_VERSION;
     }
 #endif
     return (PRUint16)version;
 }
 
 SECStatus
 tls13_ClientReadSupportedVersion(sslSocket *ss)
 {
     PRUint32 temp;
-    SSL3ProtocolVersion v;
     TLSExtension *versionExtension;
     SECItem it;
     SECStatus rv;
 
     /* Update the version based on the extension, as necessary. */
     versionExtension = ssl3_FindExtension(ss, ssl_tls13_supported_versions_xtn);
     if (!versionExtension) {
         return SECSuccess;
@@ -5304,39 +5304,25 @@ tls13_ClientReadSupportedVersion(sslSock
     rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &it.data, &it.len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
     if (it.len) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
         return SECFailure;
     }
-    v = (SSL3ProtocolVersion)temp;
-
-    /* You cannot negotiate < TLS 1.3 with supported_versions. */
-    if (v < SSL_LIBRARY_VERSION_TLS_1_3) {
+
+    if (temp != tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+                                         ss->protocolVariant)) {
+        /* You cannot negotiate < TLS 1.3 with supported_versions. */
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
         return SECFailure;
     }
 
-#ifdef TLS_1_3_DRAFT_VERSION
-    if (temp == SSL_LIBRARY_VERSION_TLS_1_3) {
-        FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
-        return SECFailure;
-    }
-    if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
-        v = SSL_LIBRARY_VERSION_TLS_1_3;
-    } else {
-        v = (SSL3ProtocolVersion)temp;
-    }
-#else
-    v = (SSL3ProtocolVersion)temp;
-#endif
-
-    ss->version = v;
+    ss->version = SSL_LIBRARY_VERSION_TLS_1_3;
     return SECSuccess;
 }
 
 /* Pick the highest version we support that is also advertised. */
 SECStatus
 tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)
 {
     PRUint16 version;
@@ -5350,17 +5336,17 @@ tls13_NegotiateVersion(sslSocket *ss, co
     if (rv != SECSuccess) {
         return SECFailure;
     }
     if (data.len || !versions.len || (versions.len & 1)) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
         return SECFailure;
     }
     for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
-        PRUint16 wire = tls13_EncodeDraftVersion(version);
+        PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant);
         unsigned long offset;
 
         for (offset = 0; offset < versions.len; offset += 2) {
             PRUint16 supported =
                 (versions.data[offset] << 8) | versions.data[offset + 1];
             if (supported == wire) {
                 ss->version = version;
                 return SECSuccess;
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -96,17 +96,18 @@ SECStatus tls13_ProtectRecord(sslSocket 
                               ssl3CipherSpec *cwSpec,
                               SSLContentType type,
                               const PRUint8 *pIn,
                               PRUint32 contentLen,
                               sslBuffer *wrBuf);
 PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
 SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
 PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
-PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
+PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version,
+                                  SSLProtocolVariant variant);
 SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss);
 SECStatus tls13_NegotiateVersion(sslSocket *ss,
                                  const TLSExtension *supported_versions);
 
 PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid);
 void tls13_AntiReplayRollover(PRTime now);
 
 SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k,
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -746,17 +746,19 @@ tls13_ClientSendSupportedVersionsXtn(con
                 SSL_GETPID(), ss->fd));
 
     rv = sslBuffer_Skip(buf, 1, &lengthOffset);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
-        rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2);
+        PRUint16 wire = tls13_EncodeDraftVersion(version,
+                                                 ss->protocolVariant);
+        rv = sslBuffer_AppendNumber(buf, wire, 2);
         if (rv != SECSuccess) {
             return SECFailure;
         }
     }
 
     rv = sslBuffer_InsertLength(buf, lengthOffset, 1);
     if (rv != SECSuccess) {
         return SECFailure;
@@ -774,18 +776,19 @@ tls13_ServerSendSupportedVersionsXtn(con
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension",
                 SSL_GETPID(), ss->fd));
 
-    rv = sslBuffer_AppendNumber(
-        buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2);
+    PRUint16 ver = tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+                                            ss->protocolVariant);
+    rv = sslBuffer_AppendNumber(buf, ver, 2);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     *added = PR_TRUE;
     return SECSuccess;
 }
 
--- a/security/nss/tests/all.sh
+++ b/security/nss/tests/all.sh
@@ -311,17 +311,17 @@ TESTS=${NSS_TESTS:-$tests}
 ALL_TESTS=${TESTS}
 
 nss_ssl_tests="crl iopr policy normal_normal"
 if [ $NO_INIT_SUPPORT -eq 0 ]; then
     nss_ssl_tests="$nss_ssl_tests fips_normal normal_fips"
 fi
 NSS_SSL_TESTS="${NSS_SSL_TESTS:-$nss_ssl_tests}"
 
-nss_ssl_run="cov auth stapling signed_cert_timestamps stress dtls scheme"
+nss_ssl_run="cov auth stapling signed_cert_timestamps stress scheme"
 NSS_SSL_RUN="${NSS_SSL_RUN:-$nss_ssl_run}"
 
 # NOTE:
 # Lists of enabled tests and other settings are stored to ${ENV_BACKUP}
 # file and are are restored after every test cycle.
 
 ENV_BACKUP=${HOSTDIR}/env.sh
 env_backup > ${ENV_BACKUP}
--- a/security/nss/tests/bogo/bogo.sh
+++ b/security/nss/tests/bogo/bogo.sh
@@ -20,33 +20,33 @@ bogo_init()
     . ./init.sh
   fi
 
   mkdir -p "${HOSTDIR}/bogo"
   cd "${HOSTDIR}/bogo"
   BORING=${BORING:=boringssl}
   if [ ! -d "$BORING" ]; then
     git clone -q https://boringssl.googlesource.com/boringssl "$BORING"
-    git -C "$BORING" checkout -q 9af1edbe2201e6c6d58e5e484bf56281d8c751d9
+    git -C "$BORING" checkout -q 7f4f41fa81c03e0f8ef1ab5b3d1d566b5968f107
   fi
 
   SCRIPTNAME="bogo.sh"
   html_head "bogo test"
 }
 
 bogo_cleanup()
 {
   html "</TABLE><BR>"
   cd ${QADIR}
   . common/cleanup.sh
 }
 
-cd ../
-cwd=$(cd $(dirname $0); pwd -P)
-SOURCE_DIR="$cwd"/..
+cd "$(dirname "$0")"
+cwd=$(pwd -P)
+SOURCE_DIR="$(cd "$cwd"/../..; pwd -P)"
 bogo_init
 (cd "$BORING"/ssl/test/runner;
  GOPATH="$cwd" go test -pipe -shim-path "${BINDIR}"/nss_bogo_shim \
 	 -loose-errors -allow-unimplemented \
 	 -shim-config "${SOURCE_DIR}/gtests/nss_bogo_shim/config.json") \
 	 2>bogo.errors | tee bogo.log
 html_msg "${PIPESTATUS[0]}" 0 "Bogo" "Run successfully"
 grep -i 'FAILED\|Assertion failure' bogo.errors
--- a/security/nss/tests/interop/interop.sh
+++ b/security/nss/tests/interop/interop.sh
@@ -28,17 +28,17 @@ interop_init()
     git -C "$INTEROP" checkout -q a4878c30db639053fc4f08573d3ae6cbd3cf1d6f
   fi
   INTEROP=$(cd "$INTEROP";pwd -P)
 
   # We use the BoringSSL keyfiles
   BORING=${BORING:=boringssl}
   if [ ! -d "$BORING" ]; then
     git clone -q https://boringssl.googlesource.com/boringssl "$BORING"
-    git -C "$BORING" checkout -q 9af1edbe2201e6c6d58e5e484bf56281d8c751d9
+    git -C "$BORING" checkout -q 7f4f41fa81c03e0f8ef1ab5b3d1d566b5968f107
   fi
   BORING=$(cd "$BORING";pwd -P)
   mkdir "$BORING/build"
   cd "$BORING/build"
   
   # Build boring explicitly with gcc because it fails on builds where 
   # CC=clang-5.0, for example on asan-builds.
   export CC=gcc
@@ -46,17 +46,17 @@ interop_init()
   make -j$(nproc)
 
   # Check out and build OpenSSL. 
   # Build with "enable-external-tests" to include the shim in the build. 
   cd "${HOSTDIR}"
   OSSL=${OSSL:=openssl}
   if [ ! -d "$OSSL" ]; then
     git clone -q https://github.com/openssl/openssl.git "$OSSL"
-    git -C "$OSSL" checkout -q 9e6a32025e6e69949ad3e53a29a0b85f61f30b85
+    git -C "$OSSL" checkout -q 7d38ca3f8bca58bf7b69e78c1f1ab69e5f429dff
   fi
   OSSL=$(cd "$OSSL";pwd -P)
   cd "$OSSL"
   ./config enable-external-tests
   make -j$(nproc)
 
   #Some filenames in the OpenSSL repository contain "core".
   #This prevents false positive "core file detected" errors.
@@ -87,16 +87,17 @@ interop_run()
   if [ $RESULT -ne 0 ]; then
     cat interop-${test_name}.errors
     cat interop-${test_name}.log
   fi
   grep -i 'FAILED\|Assertion failure' interop-${test_name}.errors
   html_msg $? 1 "Interop ${test_name}" "No failures"
 }
 
+cd "$(dirname "$0")"
 interop_init
 NSS_SHIM="$BINDIR"/nss_bogo_shim
 BORING_SHIM="$BORING"/build/ssl/test/bssl_shim
 OSSL_SHIM="$OSSL"/test/ossl_shim/ossl_shim
 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$OSSL"
 interop_run "nss_nss" ${NSS_SHIM} ${NSS_SHIM}
 interop_run "bssl_nss" ${BORING_SHIM} ${NSS_SHIM}
 interop_run "nss_bssl" ${NSS_SHIM} ${BORING_SHIM} "--client-writes-first"
--- a/servo/components/style/gecko_bindings/sugar/ownership.rs
+++ b/servo/components/style/gecko_bindings/sugar/ownership.rs
@@ -300,16 +300,25 @@ impl<GeckoType> DerefMut for Owned<Gecko
 ///
 /// Can be null, and just as `Owned` leaks on `Drop`.
 pub struct OwnedOrNull<GeckoType> {
     ptr: *mut GeckoType,
     _marker: PhantomData<GeckoType>,
 }
 
 impl<GeckoType> OwnedOrNull<GeckoType> {
+    /// Returns a null pointer.
+    #[inline]
+    pub fn null() -> Self {
+        Self {
+            ptr: ptr::null_mut(),
+            _marker: PhantomData,
+        }
+    }
+
     /// Returns whether this pointer is null.
     #[inline]
     pub fn is_null(&self) -> bool {
         self.ptr.is_null()
     }
 
     /// Returns an owned pointer if this is non-null, and `None` otherwise.
     pub fn into_box_opt<ServoType>(self) -> Option<Box<ServoType>>
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -152,16 +152,17 @@ pub mod style_adjuster;
 pub mod style_resolver;
 pub mod stylesheet_set;
 pub mod stylesheets;
 pub mod stylist;
 pub mod thread_state;
 pub mod timer;
 pub mod traversal;
 pub mod traversal_flags;
+pub mod use_counters;
 #[macro_use]
 #[allow(non_camel_case_types)]
 pub mod values;
 
 #[cfg(feature = "gecko")]
 pub use gecko_string_cache as string_cache;
 #[cfg(feature = "gecko")]
 pub use gecko_string_cache::Atom;
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -4,16 +4,17 @@
 
 //! The context within which CSS code is parsed.
 
 use context::QuirksMode;
 use cssparser::{Parser, SourceLocation, UnicodeRange};
 use error_reporting::{ContextualParseError, ParseErrorReporter};
 use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
 use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
+use use_counters::UseCounters;
 
 /// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
 #[cfg(feature = "gecko")]
 #[inline]
 pub fn assert_parsing_mode_match() {
     use gecko_bindings::structs;
 
     macro_rules! check_parsing_modes {
@@ -48,74 +49,82 @@ pub struct ParserContext<'a> {
     /// The mode to use when parsing.
     pub parsing_mode: ParsingMode,
     /// The quirks mode of this stylesheet.
     pub quirks_mode: QuirksMode,
     /// The active error reporter, or none if error reporting is disabled.
     error_reporter: Option<&'a ParseErrorReporter>,
     /// The currently active namespaces.
     pub namespaces: Option<&'a Namespaces>,
+    /// The use counters we want to record while parsing style rules, if any.
+    pub use_counters: Option<&'a UseCounters>,
 }
 
 impl<'a> ParserContext<'a> {
     /// Create a parser context.
     #[inline]
     pub fn new(
         stylesheet_origin: Origin,
         url_data: &'a UrlExtraData,
         rule_type: Option<CssRuleType>,
         parsing_mode: ParsingMode,
         quirks_mode: QuirksMode,
         error_reporter: Option<&'a ParseErrorReporter>,
+        use_counters: Option<&'a UseCounters>,
     ) -> Self {
-        ParserContext {
+        Self {
             stylesheet_origin,
             url_data,
             rule_type,
             parsing_mode,
             quirks_mode,
             error_reporter,
             namespaces: None,
+            use_counters,
         }
     }
 
     /// Create a parser context for on-the-fly parsing in CSSOM
     #[inline]
     pub fn new_for_cssom(
         url_data: &'a UrlExtraData,
         rule_type: Option<CssRuleType>,
         parsing_mode: ParsingMode,
         quirks_mode: QuirksMode,
         error_reporter: Option<&'a ParseErrorReporter>,
+        use_counters: Option<&'a UseCounters>,
     ) -> Self {
         Self::new(
             Origin::Author,
             url_data,
             rule_type,
             parsing_mode,
             quirks_mode,
             error_reporter,
+            use_counters,
         )
     }
 
-    /// Create a parser context based on a previous context, but with a modified rule type.
+    /// Create a parser context based on a previous context, but with a modified
+    /// rule type.
     #[inline]
     pub fn new_with_rule_type(
         context: &'a ParserContext,
         rule_type: CssRuleType,
         namespaces: &'a Namespaces,
     ) -> ParserContext<'a> {
-        ParserContext {
+        Self {
             stylesheet_origin: context.stylesheet_origin,
             url_data: context.url_data,
             rule_type: Some(rule_type),
             parsing_mode: context.parsing_mode,
             quirks_mode: context.quirks_mode,
             namespaces: Some(namespaces),
             error_reporter: context.error_reporter,
+            use_counters: context.use_counters,
         }
     }
 
     /// Whether we're in a @page rule.
     #[inline]
     pub fn in_page_rule(&self) -> bool {
         self.rule_type
             .map_or(false, |rule_type| rule_type == CssRuleType::Page)
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -1198,16 +1198,17 @@ pub fn parse_style_attribute(
 ) -> PropertyDeclarationBlock {
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         quirks_mode,
         error_reporter,
+        None,
     );
 
     let mut input = ParserInput::new(input);
     parse_property_declaration_list(&context, &mut Parser::new(&mut input))
 }
 
 /// Parse a given property declaration. Can result in multiple
 /// `PropertyDeclaration`s when expanding a shorthand, for example.
@@ -1225,16 +1226,17 @@ pub fn parse_one_declaration_into(
 ) -> Result<(), ()> {
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         parsing_mode,
         quirks_mode,
         error_reporter,
+        None,
     );
 
     let mut input = ParserInput::new(input);
     let mut parser = Parser::new(&mut input);
     let start_position = parser.position();
     parser.parse_entirely(|parser| {
         PropertyDeclaration::parse_into(declarations, id, &context, parser)
     }).map_err(|err| {
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -420,52 +420,61 @@ impl PropertyDeclaration {
 pub mod animated_properties {
     <%include file="/helpers/animated_properties.mako.rs" />
 }
 
 /// A longhand or shorthand property.
 #[derive(Clone, Copy, Debug)]
 pub struct NonCustomPropertyId(usize);
 
+/// The length of all the non-custom properties.
+pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize =
+    ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())};
+
 % if product == "gecko":
 #[allow(dead_code)]
 unsafe fn static_assert_nscsspropertyid() {
     % for i, property in enumerate(data.longhands + data.shorthands + data.all_aliases()):
     ::std::mem::transmute::<[u8; ${i}], [u8; ${property.nscsspropertyid()} as usize]>([0; ${i}]); // ${property.name}
     % endfor
 }
 % endif
 
 impl NonCustomPropertyId {
+    /// Returns the underlying index, used for use counter.
+    pub fn bit(self) -> usize {
+        self.0
+    }
+
     #[cfg(feature = "gecko")]
     #[inline]
     fn to_nscsspropertyid(self) -> nsCSSPropertyID {
         // unsafe: guaranteed by static_assert_nscsspropertyid above.
         unsafe { ::std::mem::transmute(self.0 as i32) }
     }
 
     /// Convert an `nsCSSPropertyID` into a `NonCustomPropertyId`.
     #[cfg(feature = "gecko")]
     #[inline]
     pub fn from_nscsspropertyid(prop: nsCSSPropertyID) -> Result<Self, ()> {
         let prop = prop as i32;
         if prop < 0 {
             return Err(());
         }
-        if prop >= ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} {
+        if prop >= NON_CUSTOM_PROPERTY_ID_COUNT as i32 {
             return Err(());
         }
         // unsafe: guaranteed by static_assert_nscsspropertyid above.
         Ok(unsafe { ::std::mem::transmute(prop as usize) })
     }
 
     /// Get the property name.
     #[inline]
     pub fn name(self) -> &'static str {
-        static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
+        static MAP: [&'static str; NON_CUSTOM_PROPERTY_ID_COUNT] = [
             % for property in data.longhands + data.shorthands + data.all_aliases():
             "${property.name}",
             % endfor
         ];
         MAP[self.0]
     }
 
     #[inline]
@@ -630,17 +639,17 @@ impl NonCustomPropertyId {
                 PropertyId::Longhand(transmute(self.0 as u16))
             }
         }
         if self.0 < ${len(data.longhands) + len(data.shorthands)} {
             return unsafe {
                 PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16))
             }
         }
-        assert!(self.0 < ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())});
+        assert!(self.0 < NON_CUSTOM_PROPERTY_ID_COUNT);
         let alias_id: AliasId = unsafe {
             transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16)
         };
 
         match alias_id.aliased_property() {
             AliasedPropertyId::Longhand(longhand) => PropertyId::LonghandAlias(longhand, alias_id),
             AliasedPropertyId::Shorthand(shorthand) => PropertyId::ShorthandAlias(shorthand, alias_id),
         }
@@ -666,17 +675,17 @@ impl From<AliasId> for NonCustomProperty
     fn from(id: AliasId) -> Self {
         NonCustomPropertyId(id as usize + ${len(data.longhands) + len(data.shorthands)})
     }
 }
 
 /// A set of all properties
 #[derive(Clone, PartialEq)]
 pub struct NonCustomPropertyIdSet {
-    storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32]
+    storage: [u32; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + 32) / 32]
 }
 
 impl NonCustomPropertyIdSet {
     /// Creates an empty `NonCustomPropertyIdSet`.
     pub fn new() -> Self {
         Self {
             storage: Default::default(),
         }
@@ -1549,16 +1558,17 @@ impl UnparsedValue {
             // FIXME(emilio): ParsingMode is slightly fishy...
             let context = ParserContext::new(
                 Origin::Author,
                 &self.url_data,
                 None,
                 ParsingMode::DEFAULT,
                 quirks_mode,
                 None,
+                None,
             );
 
             let mut input = ParserInput::new(&css);
             Parser::new(&mut input).parse_entirely(|input| {
                 match self.from_shorthand {
                     None => longhand_id.parse_value(&context, input),
                     Some(ShorthandId::All) => {
                         // No need to parse the 'all' shorthand as anything other than a CSS-wide
@@ -1848,17 +1858,18 @@ impl PropertyId {
             PropertyId::ShorthandAlias(id, _) |
             PropertyId::Shorthand(id) => Ok(id),
             PropertyId::LonghandAlias(id, _) |
             PropertyId::Longhand(id) => Err(PropertyDeclarationId::Longhand(id)),
             PropertyId::Custom(ref name) => Err(PropertyDeclarationId::Custom(name)),
         }
     }
 
-    fn non_custom_id(&self) -> Option<NonCustomPropertyId> {
+    /// Returns the `NonCustomPropertyId` corresponding to this property id.
+    pub fn non_custom_id(&self) -> Option<NonCustomPropertyId> {
         Some(match *self {
             PropertyId::Custom(_) => return None,
             PropertyId::Shorthand(shorthand_id) => shorthand_id.into(),
             PropertyId::Longhand(longhand_id) => longhand_id.into(),
             PropertyId::ShorthandAlias(_, alias_id) => alias_id.into(),
             PropertyId::LonghandAlias(_, alias_id) => alias_id.into(),
         })
     }
@@ -2193,36 +2204,36 @@ impl PropertyDeclaration {
 
         let non_custom_id = id.non_custom_id();
         let start = input.state();
         match id {
             PropertyId::Custom(property_name) => {
                 // FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
                 // before adding skip_whitespace here.
                 // This probably affects some test results.
-                let value = match input.try(|i| CSSWideKeyword::parse(i)) {
+                let value = match input.try(CSSWideKeyword::parse) {
                     Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
                     Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
                         Ok(value) => DeclaredValueOwned::Value(value),
                         Err(e) => return Err(StyleParseErrorKind::new_invalid(
                             format!("--{}", property_name),
                             e,
                         )),
                     }
                 };
                 declarations.push(PropertyDeclaration::Custom(CustomDeclaration {
                     name: property_name,
                     value,
                 }));
-                Ok(())
+                return Ok(());
             }
             PropertyId::LonghandAlias(id, _) |
             PropertyId::Longhand(id) => {
                 input.skip_whitespace();  // Unnecessary for correctness, but may help try() rewind less.
-                input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| {
+                input.try(CSSWideKeyword::parse).map(|keyword| {
                     PropertyDeclaration::CSSWideKeyword(
                         WideKeywordDeclaration { id, keyword },
                     )
                 }).or_else(|()| {
                     input.look_for_var_functions();
                     input.parse_entirely(|input| id.parse_value(context, input))
                     .or_else(|err| {
                         while let Ok(_) = input.next() {}  // Look for var() after the error.
@@ -2248,79 +2259,83 @@ impl PropertyDeclaration {
                             Err(StyleParseErrorKind::new_invalid(
                                 non_custom_id.unwrap().name(),
                                 err,
                             ))
                         }
                     })
                 }).map(|declaration| {
                     declarations.push(declaration)
-                })
+                })?;
             }
             PropertyId::ShorthandAlias(id, _) |
             PropertyId::Shorthand(id) => {
                 input.skip_whitespace();  // Unnecessary for correctness, but may help try() rewind less.
-                if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) {
+                if let Ok(keyword) = input.try(CSSWideKeyword::parse) {
                     if id == ShorthandId::All {
                         declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
                     } else {
                         for longhand in id.longhands() {
                             declarations.push(PropertyDeclaration::CSSWideKeyword(
                                 WideKeywordDeclaration {
                                     id: longhand,
                                     keyword,
                                 },
                             ))
                         }
                     }
-                    Ok(())
                 } else {
                     input.look_for_var_functions();
                     // Not using parse_entirely here: each ${shorthand.ident}::parse_into function
                     // needs to do so *before* pushing to `declarations`.
                     id.parse_into(declarations, context, input).or_else(|err| {
                         while let Ok(_) = input.next() {}  // Look for var() after the error.
-                        if input.seen_var_functions() {
-                            input.reset(&start);
-                            let (first_token_type, css) =
-                                ::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
-                                    StyleParseErrorKind::new_invalid(
-                                        non_custom_id.unwrap().name(),
-                                        e,
-                                    )
-                                })?;
-                            let unparsed = Arc::new(UnparsedValue {
-                                css: css.into_owned(),
-                                first_token_type: first_token_type,
-                                url_data: context.url_data.clone(),
-                                from_shorthand: Some(id),
-                            });
-                            if id == ShorthandId::All {
-                                declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
-                            } else {
-                                for id in id.longhands() {
-                                    declarations.push(
-                                        PropertyDeclaration::WithVariables(VariableDeclaration {
-                                            id,
-                                            value: unparsed.clone(),
-                                        })
-                                    )
-                                }
-                            }
-                            Ok(())
-                        } else {
-                            Err(StyleParseErrorKind::new_invalid(
+                        if !input.seen_var_functions() {
+                            return Err(StyleParseErrorKind::new_invalid(
                                 non_custom_id.unwrap().name(),
                                 err,
-                            ))
+                            ));
                         }
-                    })
+
+                        input.reset(&start);
+                        let (first_token_type, css) =
+                            ::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
+                                StyleParseErrorKind::new_invalid(
+                                    non_custom_id.unwrap().name(),
+                                    e,
+                                )
+                            })?;
+                        let unparsed = Arc::new(UnparsedValue {
+                            css: css.into_owned(),
+                            first_token_type: first_token_type,
+                            url_data: context.url_data.clone(),
+                            from_shorthand: Some(id),
+                        });
+                        if id == ShorthandId::All {
+                            declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
+                        } else {
+                            for id in id.longhands() {
+                                declarations.push(
+                                    PropertyDeclaration::WithVariables(VariableDeclaration {
+                                        id,
+                                        value: unparsed.clone(),
+                                    })
+                                )
+                            }
+                        }
+                        Ok(())
+                    })?;
                 }
             }
         }
+        debug_assert!(non_custom_id.is_some(), "Custom properties should've returned earlier");
+        if let Some(use_counters) = context.use_counters {
+            use_counters.non_custom_properties.record(non_custom_id.unwrap());
+        }
+        Ok(())
     }
 }
 
 type SubpropertiesArray<T> =
     [T; ${max(len(s.sub_properties) for s in data.shorthands_except_all())}];
 
 type SubpropertiesVec<T> = ArrayVec<SubpropertiesArray<T>>;
 
--- a/servo/components/style/stylesheets/keyframes_rule.rs
+++ b/servo/components/style/stylesheets/keyframes_rule.rs
@@ -214,16 +214,17 @@ impl Keyframe {
         let namespaces = parent_stylesheet_contents.namespaces.read();
         let mut context = ParserContext::new(
             parent_stylesheet_contents.origin,
             &url_data,
             Some(CssRuleType::Keyframe),
             ParsingMode::DEFAULT,
             parent_stylesheet_contents.quirks_mode,
             None,
+            None,
         );
         context.namespaces = Some(&*namespaces);
         let mut input = ParserInput::new(css);
         let mut input = Parser::new(&mut input);
 
         let mut declarations = SourcePropertyDeclaration::new();
         let mut rule_parser = KeyframeListParser {
             context: &context,
--- a/servo/components/style/stylesheets/mod.rs
+++ b/servo/components/style/stylesheets/mod.rs
@@ -259,16 +259,17 @@ impl CssRule {
         let url_data = parent_stylesheet_contents.url_data.read();
         let context = ParserContext::new(
             parent_stylesheet_contents.origin,
             &url_data,
             None,
             ParsingMode::DEFAULT,
             parent_stylesheet_contents.quirks_mode,
             None,
+            None,
         );
 
         let mut input = ParserInput::new(css);
         let mut input = Parser::new(&mut input);
 
         let mut guard = parent_stylesheet_contents.namespaces.write();
 
         // nested rules are in the body state
--- a/servo/components/style/stylesheets/stylesheet.rs
+++ b/servo/components/style/stylesheets/stylesheet.rs
@@ -19,16 +19,17 @@ use shared_lock::{DeepCloneParams, DeepC
 use std::mem;
 use std::sync::atomic::{AtomicBool, Ordering};
 use style_traits::ParsingMode;
 use stylesheets::{CssRule, CssRules, Origin, UrlExtraData};
 use stylesheets::loader::StylesheetLoader;
 use stylesheets::rule_parser::{State, TopLevelRuleParser};
 use stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator};
 use stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIterator};
+use use_counters::UseCounters;
 
 /// This structure holds the user-agent and user stylesheets.
 pub struct UserAgentStylesheets {
     /// The lock used for user-agent stylesheets.
     pub shared_lock: SharedRwLock,
     /// The user or user agent stylesheets.
     pub user_or_user_agent_stylesheets: Vec<DocumentStyleSheet>,
     /// The quirks mode stylesheet.
@@ -73,28 +74,30 @@ impl StylesheetContents {
         css: &str,
         url_data: UrlExtraData,
         origin: Origin,
         shared_lock: &SharedRwLock,
         stylesheet_loader: Option<&StylesheetLoader>,
         error_reporter: Option<&ParseErrorReporter>,
         quirks_mode: QuirksMode,
         line_number_offset: u32,
+        use_counters: Option<&UseCounters>,
     ) -> Self {
         let namespaces = RwLock::new(Namespaces::default());
         let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
             css,
             &url_data,
             origin,
             &mut *namespaces.write(),
             &shared_lock,
             stylesheet_loader,
             error_reporter,
             quirks_mode,
             line_number_offset,
+            use_counters,
         );
 
         Self {
             rules: CssRules::new(rules, &shared_lock),
             origin: origin,
             url_data: RwLock::new(url_data),
             namespaces: namespaces,
             quirks_mode: quirks_mode,
@@ -310,26 +313,29 @@ impl Stylesheet {
         existing: &Stylesheet,
         css: &str,
         url_data: UrlExtraData,
         stylesheet_loader: Option<&StylesheetLoader>,
         error_reporter: Option<&ParseErrorReporter>,
         line_number_offset: u32,
     ) {
         let namespaces = RwLock::new(Namespaces::default());
+
+        // FIXME: Consider adding use counters to Servo?
         let (rules, source_map_url, source_url) = Self::parse_rules(
             css,
             &url_data,
             existing.contents.origin,
             &mut *namespaces.write(),
             &existing.shared_lock,
             stylesheet_loader,
             error_reporter,
             existing.contents.quirks_mode,
             line_number_offset,
+            /* use_counters = */ None,
         );
 
         *existing.contents.url_data.write() = url_data;
         mem::swap(
             &mut *existing.contents.namespaces.write(),
             &mut *namespaces.write(),
         );
 
@@ -345,28 +351,30 @@ impl Stylesheet {
         url_data: &UrlExtraData,
         origin: Origin,
         namespaces: &mut Namespaces,
         shared_lock: &SharedRwLock,
         stylesheet_loader: Option<&StylesheetLoader>,
         error_reporter: Option<&ParseErrorReporter>,
         quirks_mode: QuirksMode,
         line_number_offset: u32,
+        use_counters: Option<&UseCounters>,
     ) -> (Vec<CssRule>, Option<String>, Option<String>) {
         let mut rules = Vec::new();
         let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset);
         let mut input = Parser::new(&mut input);
 
         let context = ParserContext::new(
             origin,
             url_data,
             None,
             ParsingMode::DEFAULT,
             quirks_mode,
             error_reporter,
+            use_counters,
         );
 
         let rule_parser = TopLevelRuleParser {
             stylesheet_origin: origin,
             shared_lock,
             loader: stylesheet_loader,
             context,
             state: State::Start,
@@ -416,25 +424,27 @@ impl Stylesheet {
         origin: Origin,
         media: Arc<Locked<MediaList>>,
         shared_lock: SharedRwLock,
         stylesheet_loader: Option<&StylesheetLoader>,
         error_reporter: Option<&ParseErrorReporter>,
         quirks_mode: QuirksMode,
         line_number_offset: u32,
     ) -> Self {
+        // FIXME: Consider adding use counters to Servo?
         let contents = StylesheetContents::from_str(
             css,
             url_data,
             origin,
             &shared_lock,
             stylesheet_loader,
             error_reporter,
             quirks_mode,
             line_number_offset,
+            /* use_counters = */ None,
         );
 
         Stylesheet {
             contents,
             shared_lock,
             media,
             disabled: AtomicBool::new(false),
         }
new file mode 100644
--- /dev/null
+++ b/servo/components/style/use_counters/mod.rs
@@ -0,0 +1,87 @@
+/* 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/. */
+
+//! Various stuff for CSS property use counters.
+
+#[cfg(feature = "gecko")]
+use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
+use properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT};
+use std::cell::Cell;
+
+#[cfg(target_pointer_width = "64")]
+const BITS_PER_ENTRY: usize = 64;
+
+#[cfg(target_pointer_width = "32")]
+const BITS_PER_ENTRY: usize = 32;
+
+/// One bit per each non-custom CSS property.
+#[derive(Default)]
+pub struct NonCustomPropertyUseCounters {
+    storage: [Cell<usize>; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY],
+}
+
+impl NonCustomPropertyUseCounters {
+    /// Returns the bucket a given property belongs in, and the bitmask for that
+    /// property.
+    #[inline(always)]
+    fn bucket_and_pattern(id: NonCustomPropertyId) -> (usize, usize) {
+        let bit = id.bit();
+        let bucket = bit / BITS_PER_ENTRY;
+        let bit_in_bucket = bit % BITS_PER_ENTRY;
+        (bucket, 1 << bit_in_bucket)
+    }
+
+    /// Record that a given non-custom property ID has been parsed.
+    #[inline]
+    pub fn record(&self, id: NonCustomPropertyId) {
+        let (bucket, pattern) = Self::bucket_and_pattern(id);
+        let bucket = &self.storage[bucket];
+        bucket.set(bucket.get() | pattern)
+    }
+
+    /// Returns whether a given non-custom property ID has been recorded
+    /// earlier.
+    #[inline]
+    pub fn recorded(&self, id: NonCustomPropertyId) -> bool {
+        let (bucket, pattern) = Self::bucket_and_pattern(id);
+        self.storage[bucket].get() & pattern != 0
+    }
+
+    /// Merge `other` into `self`.
+    #[inline]
+    fn merge(&self, other: &Self) {
+        for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) {
+            bucket.set(bucket.get() | other_bucket.get())
+        }
+    }
+}
+
+/// The use-counter data related to a given document we want to store.
+#[derive(Default)]
+pub struct UseCounters {
+    /// The counters for non-custom properties that have been parsed in the
+    /// document's stylesheets.
+    pub non_custom_properties: NonCustomPropertyUseCounters,
+}
+
+impl UseCounters {
+    /// Merge the use counters.
+    ///
+    /// Used for parallel parsing, where we parse off-main-thread.
+    #[inline]
+    pub fn merge(&self, other: &Self) {
+        self.non_custom_properties.merge(&other.non_custom_properties)
+    }
+}
+
+#[cfg(feature = "gecko")]
+unsafe impl HasFFI for UseCounters {
+    type FFIType = ::gecko_bindings::structs::StyleUseCounters;
+}
+
+#[cfg(feature = "gecko")]
+unsafe impl HasSimpleFFI for UseCounters {}
+
+#[cfg(feature = "gecko")]
+unsafe impl HasBoxFFI for UseCounters {}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -149,16 +149,17 @@ use style::stylesheets::import_rule::Imp
 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
 use style::stylesheets::supports_rule::parse_condition_or_declaration;
 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::DomTraversal;
 use style::traversal::resolve_style;
 use style::traversal_flags::{self, TraversalFlags};
+use style::use_counters::UseCounters;
 use style::values::{CustomIdent, KeyframesName};
 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
 use style::values::computed::{Context, ToComputedValue};
 use style::values::distance::ComputeSquaredDistance;
 use style::values::generics::rect::Rect;
 use style::values::specified;
 use style::values::specified::gecko::{IntersectionObserverRootMargin, PixelOrPercentage};
 use style::values::specified::source_size_list::SourceSizeList;
@@ -1190,17 +1191,18 @@ pub extern "C" fn Servo_StyleSheet_Empty
         StylesheetContents::from_str(
             "",
             unsafe { dummy_url_data() }.clone(),
             origin,
             shared_lock,
             /* loader = */ None,
             None,
             QuirksMode::NoQuirks,
-            0
+            0,
+            /* use_counters = */ None,
         )
     ).into_strong()
 }
 
 /// Note: The load_data corresponds to this sheet, and is passed as the parent
 /// load data for child sheet loads. It may be null for certain cases where we
 /// know we won't have child loads.
 #[no_mangle]
@@ -1209,16 +1211,17 @@ pub extern "C" fn Servo_StyleSheet_FromU
     stylesheet: *mut DomStyleSheet,
     load_data: *mut SheetLoadData,
     bytes: *const nsACString,
     mode: SheetParsingMode,
     extra_data: *mut URLExtraData,
     line_number_offset: u32,
     quirks_mode: nsCompatibility,
     reusable_sheets: *mut LoaderReusableStyleSheets,
+    use_counters: bindings::StyleUseCountersBorrowedOrNull,
 ) -> RawServoStyleSheetContentsStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let input: &str = unsafe { (*bytes).as_str_unchecked() };
 
     let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
     let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) };
     let loader = if loader.is_null() {
         None
@@ -1227,50 +1230,53 @@ pub extern "C" fn Servo_StyleSheet_FromU
     };
 
     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
     let loader: Option<&StyleStylesheetLoader> = match loader {
         None => None,
         Some(ref s) => Some(s),
     };
 
-
     Arc::new(StylesheetContents::from_str(
         input,
         url_data.clone(),
         mode_to_origin(mode),
         &global_style_data.shared_lock,
         loader,
         reporter.as_ref().map(|r| r as &ParseErrorReporter),
         quirks_mode.into(),
         line_number_offset,
+        use_counters.map(UseCounters::from_ffi),
     )).into_strong()
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
     load_data: *mut SheetLoadDataHolder,
     extra_data: *mut URLExtraData,
     bytes: *const nsACString,
     mode: SheetParsingMode,
     line_number_offset: u32,
     quirks_mode: nsCompatibility,
+    should_record_use_counters: bool,
 ) {
     let load_data = RefPtr::new(load_data);
     let extra_data = UrlExtraData(RefPtr::new(extra_data));
 
     let mut sheet_bytes = nsCString::new();
     sheet_bytes.assign(&*bytes);
+
     let async_parser = AsyncStylesheetParser::new(
         load_data,
         extra_data,
         sheet_bytes,
         mode_to_origin(mode),
         quirks_mode.into(),
-        line_number_offset
+        line_number_offset,
+        should_record_use_counters,
     );
 
     if let Some(thread_pool) = STYLE_THREAD_POOL.style_thread_pool.as_ref() {
         thread_pool.spawn(|| {
             async_parser.parse();
         });
     } else {
         async_parser.parse();
@@ -2554,16 +2560,17 @@ pub unsafe extern "C" fn Servo_FontFaceR
     let url_data = UrlExtraData::from_ptr_ref(&data);
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::FontFace),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
 
     write_locked_arc(rule, |rule: &mut FontFaceRule| {
         macro_rules! to_css_text {
             (
                 valid: [$($v_enum_name:ident => $field:ident,)*]
                 invalid: [$($i_enum_name:ident,)*]
             ) => {
@@ -2764,16 +2771,17 @@ macro_rules! counter_style_descriptors {
             let url_data = dummy_url_data();
             let context = ParserContext::new(
                 Origin::Author,
                 url_data,
                 Some(CssRuleType::CounterStyle),
                 ParsingMode::DEFAULT,
                 QuirksMode::NoQuirks,
                 None,
+                None,
             );
 
             write_locked_arc(rule, |rule: &mut CounterStyleRule| {
                 match desc {
                     $(nsCSSCounterDesc::$desc => {
                         match parser.parse_entirely(|i| Parse::parse(&context, i)) {
                             Ok(value) => rule.$setter(value),
                             Err(_) => false,
@@ -3324,16 +3332,17 @@ pub extern "C" fn Servo_ParseEasing(
     let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
     let easing = unsafe { (*easing).to_string() };
     let mut input = ParserInput::new(&easing);
     let mut parser = Parser::new(&mut input);
     let result =
         parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
     match result {
         Ok(parsed_easing) => {
@@ -3400,26 +3409,26 @@ pub extern "C" fn Servo_MatrixTransform_
     } else if progress < 0.5 {
         *output = from.clone().into();
     } else {
         *output = to.clone().into();
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ParseStyleAttribute(
+pub unsafe extern "C" fn Servo_ParseStyleAttribute(
     data: *const nsACString,
     raw_extra_data: *mut URLExtraData,
     quirks_mode: nsCompatibility,
     loader: *mut Loader,
 ) -> RawServoDeclarationBlockStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
-    let value = unsafe { data.as_ref().unwrap().as_str_unchecked() };
+    let value = (*data).as_str_unchecked();
     let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
-    let url_data = unsafe { UrlExtraData::from_ptr_ref(&raw_extra_data) };
+    let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
     Arc::new(global_style_data.shared_lock.wrap(
         parse_style_attribute(
             value,
             url_data,
             reporter.as_ref().map(|r| r as &ParseErrorReporter),
             quirks_mode.into(),
         )
     )).into_strong()
@@ -3808,16 +3817,17 @@ pub unsafe extern "C" fn Servo_MediaList
     let context = ParserContext::new(
         origin,
         url_data,
         Some(CssRuleType::Media),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         // TODO(emilio): Looks like error reporting could be useful here?
         None,
+        None,
     );
 
     write_locked_arc(list, |list: &mut MediaList| {
         *list = MediaList::parse(&context, &mut parser);
     })
 }
 
 #[no_mangle]
@@ -3849,16 +3859,17 @@ pub extern "C" fn Servo_MediaList_Append
     let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { dummy_url_data() };
     let context = ParserContext::new_for_cssom(
         url_data,
         Some(CssRuleType::Media),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
     write_locked_arc(list, |list: &mut MediaList| {
         list.append_medium(&context, new_medium);
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_DeleteMedium(
@@ -3868,16 +3879,17 @@ pub extern "C" fn Servo_MediaList_Delete
     let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { dummy_url_data() };
     let context = ParserContext::new_for_cssom(
         url_data,
         Some(CssRuleType::Media),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
     write_locked_arc(list, |list: &mut MediaList| list.delete_medium(&context, old_medium))
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
     malloc_size_of: GeckoMallocSizeOf,
     malloc_enclosing_size_of: GeckoMallocSizeOf,
@@ -4310,16 +4322,17 @@ pub extern "C" fn Servo_DeclarationBlock
     let string = unsafe { (*value).to_string() };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
     let url = SpecifiedImageUrl::parse_from_string(string.into(), &context);
     let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
         vec![Either::Second(Image::Url(url))]
     ));
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(decl, Importance::Normal);
     });
@@ -4363,23 +4376,24 @@ pub unsafe extern "C" fn Servo_CSSSuppor
 pub extern "C" fn Servo_CSSSupports(cond: *const nsACString) -> bool {
     let condition = unsafe { cond.as_ref().unwrap().as_str_unchecked() };
     let mut input = ParserInput::new(&condition);
     let mut input = Parser::new(&mut input);
     let cond = input.parse_entirely(|i| parse_condition_or_declaration(i));
     if let Ok(cond) = cond {
         let url_data = unsafe { dummy_url_data() };
         // NOTE(emilio): The supports API is not associated to any stylesheet,
-        // so the fact that there are no namespace map here is fine.
+        // so the fact that there is no namespace map here is fine.
         let context = ParserContext::new_for_cssom(
             url_data,
             Some(CssRuleType::Style),
             ParsingMode::DEFAULT,
             QuirksMode::NoQuirks,
             None,
+            None,
         );
 
         cond.eval(&context)
     } else {
         false
     }
 }
 
@@ -5459,16 +5473,17 @@ fn parse_color(
     let url_data = unsafe { dummy_url_data() };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         error_reporter,
+        None,
     );
 
     let start_position = parser.position();
     parser.parse_entirely(|i| specified::Color::parse(&context, i)).map_err(|err| {
         if error_reporter.is_some() {
             match err.kind {
                 ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => {
                     let location = err.location.clone();
@@ -5563,16 +5578,17 @@ pub unsafe extern "C" fn Servo_Intersect
     let url_data = dummy_url_data();
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
 
     let margin = parser.parse_entirely(|p| {
         IntersectionObserverRootMargin::parse(&context, p)
     });
     match margin {
         Ok(margin) => {
             margin.0.to_gecko_rect(result);
@@ -5607,16 +5623,17 @@ pub extern "C" fn Servo_ParseTransformIn
     let mut parser = Parser::new(&mut input);
     let context = ParserContext::new(
         Origin::Author,
         unsafe { dummy_url_data() },
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
 
     let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
         Ok(t) => t,
         Err(..) => return false,
     };
 
     let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
@@ -5650,16 +5667,17 @@ pub extern "C" fn Servo_ParseFontShortha
     let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::FontFace),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
 
     let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
         Ok(f) => f,
         Err(..) => return false,
     };
 
     // The system font is not acceptable, so we return false.
@@ -5708,16 +5726,17 @@ pub unsafe extern "C" fn Servo_SourceSiz
 
     let context = ParserContext::new(
         Origin::Author,
         dummy_url_data(),
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
+        None,
     );
 
     // NB: Intentionally not calling parse_entirely.
     let list = SourceSizeList::parse(&context, &mut parser);
     Box::into_raw(Box::new(list)) as *mut _
 }
 
 #[no_mangle]
@@ -5791,8 +5810,41 @@ pub unsafe extern "C" fn Servo_PseudoCla
     let name = name.as_ref().unwrap().as_str_unchecked();
     match NonTSPseudoClass::parse_non_functional(name) {
         None => 0,
         // Ignore :any-link since it contains both visited and unvisited state.
         Some(NonTSPseudoClass::AnyLink) => 0,
         Some(pseudo_class) => pseudo_class.state_flag().bits(),
     }
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_UseCounters_Create() -> *mut structs::StyleUseCounters {
+    Box::into_raw(Box::<UseCounters>::default()) as *mut _
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_UseCounters_Drop(c: bindings::StyleUseCountersOwned) {
+    let _ = c.into_box::<UseCounters>();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_UseCounters_Merge(
+    doc_counters: bindings::StyleUseCountersBorrowed,
+    sheet_counters: bindings::StyleUseCountersBorrowed,
+) {
+    UseCounters::from_ffi(doc_counters).merge(UseCounters::from_ffi(sheet_counters))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
+    use_counters: bindings::StyleUseCountersBorrowed,
+    property: *const nsACString,
+    known_prop: *mut bool,
+) -> bool {
+    let prop_id = parse_enabled_property_name!(property, known_prop, false);
+    let non_custom_id = match prop_id.non_custom_id() {
+        Some(id) => id,
+        None => return false,
+    };
+
+    UseCounters::from_ffi(use_counters).non_custom_properties.recorded(non_custom_id)
+}
--- a/servo/ports/geckolib/stylesheet_loader.rs
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -7,24 +7,25 @@ use nsstring::nsCString;
 use servo_arc::Arc;
 use style::context::QuirksMode;
 use style::gecko::data::GeckoStyleSheet;
 use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
 use style::gecko_bindings::bindings;
 use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
 use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
 use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder};
-use style::gecko_bindings::sugar::ownership::FFIArcHelpers;
+use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasBoxFFI, OwnedOrNull};
 use style::gecko_bindings::sugar::refptr::RefPtr;
 use style::media_queries::MediaList;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, SharedRwLock};
 use style::stylesheets::{ImportRule, Origin, StylesheetLoader as StyleStylesheetLoader};
 use style::stylesheets::{StylesheetContents, UrlExtraData};
 use style::stylesheets::import_rule::ImportSheet;
+use style::use_counters::UseCounters;
 use style::values::CssUrl;
 
 pub struct StylesheetLoader(*mut Loader, *mut DomStyleSheet, *mut SheetLoadData, *mut LoaderReusableStyleSheets);
 
 impl StylesheetLoader {
     pub fn new(
         loader: *mut Loader,
         parent: *mut DomStyleSheet,
@@ -68,57 +69,75 @@ impl StyleStylesheetLoader for Styleshee
 
 pub struct AsyncStylesheetParser {
     load_data: RefPtr<SheetLoadDataHolder>,
     extra_data: UrlExtraData,
     bytes: nsCString,
     origin: Origin,
     quirks_mode: QuirksMode,
     line_number_offset: u32,
+    should_record_use_counters: bool,
 }
 
 impl AsyncStylesheetParser {
     pub fn new(
         load_data: RefPtr<SheetLoadDataHolder>,
         extra_data: UrlExtraData,
         bytes: nsCString,
         origin: Origin,
         quirks_mode: QuirksMode,
         line_number_offset: u32,
+        should_record_use_counters: bool,
     ) -> Self {
         AsyncStylesheetParser {
             load_data,
             extra_data,
             bytes,
             origin,
             quirks_mode,
             line_number_offset,
+            should_record_use_counters,
         }
     }
 
     pub fn parse(self) {
         let global_style_data = &*GLOBAL_STYLE_DATA;
         let input: &str = unsafe { (*self.bytes).as_str_unchecked() };
 
-        // Note: Parallel CSS parsing doesn't report CSS errors. When errors
-        // are being logged, Gecko prevents the parallel parsing path from
-        // running.
+        let use_counters = if self.should_record_use_counters {
+            Some(Box::new(UseCounters::default()))
+         } else {
+             None
+         };
+
+        // Note: Parallel CSS parsing doesn't report CSS errors. When errors are
+        // being logged, Gecko prevents the parallel parsing path from running.
         let sheet = Arc::new(StylesheetContents::from_str(
             input,
             self.extra_data.clone(),
             self.origin,
             &global_style_data.shared_lock,
             Some(&self),
             None,
             self.quirks_mode.into(),
             self.line_number_offset,
+            use_counters.as_ref().map(|c| &**c),
         ));
 
+        let use_counters = match use_counters {
+            Some(c) => c.into_ffi().maybe(),
+            None => OwnedOrNull::null(),
+        };
+
         unsafe {
-            bindings::Gecko_StyleSheet_FinishAsyncParse(self.load_data.get(), sheet.into_strong());
+            bindings::Gecko_StyleSheet_FinishAsyncParse(
+                self.load_data.get(),
+                sheet.into_strong(),
+                use_counters,
+            );
         }
     }
 }
 
 impl StyleStylesheetLoader for AsyncStylesheetParser {
     fn request_stylesheet(
         &self,
         url: CssUrl,
--- a/taskcluster/ci/test/marionette.yml
+++ b/taskcluster/ci/test/marionette.yml
@@ -17,20 +17,16 @@ job-defaults:
                     - marionette/windows_taskcluster_config.py
                 default:
                     - marionette/prod_config.py
                     - remove_executables.py
 
 marionette:
     description: "Marionette unittest run"
     treeherder-symbol: Mn
-    run-on-projects:
-        by-test-platform:
-            android-em.*: ["trunk", "try"]
-            default: built-projects
     max-run-time:
         by-test-platform:
             android-em.*: 3600
             default: 5400
     instance-size:
         by-test-platform:
             android-em.*: xlarge
             default: default
--- a/testing/geckodriver/src/capabilities.rs
+++ b/testing/geckodriver/src/capabilities.rs
@@ -1,11 +1,11 @@
 use base64;
+use command::LogOptions;
 use logging::Level;
-use marionette::LogOptions;
 use mozprofile::preferences::Pref;
 use mozprofile::profile::Profile;
 use mozrunner::runner::platform::firefox_default_path;
 use mozversion::{self, firefox_version, Version};
 use regex::bytes::Regex;
 use serde_json::{Map, Value};
 use std::collections::BTreeMap;
 use std::default::Default;
new file mode 100644
--- /dev/null
+++ b/testing/geckodriver/src/command.rs
@@ -0,0 +1,459 @@
+use base64;
+use hyper::Method;
+use logging;
+use regex::Captures;
+use serde::de::{self, Deserialize, Deserializer};
+use serde_json::{self, Value};
+use std::env;
+use std::fs::File;
+use std::io::prelude::*;
+use uuid::Uuid;
+use webdriver::command::{WebDriverCommand, WebDriverExtensionCommand};
+use webdriver::common::WebElement;
+use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
+use webdriver::httpapi::WebDriverExtensionRoute;
+
+pub const CHROME_ELEMENT_KEY: &'static str = "chromeelement-9fc5-4b51-a3c8-01716eedeb04";
+pub const LEGACY_ELEMENT_KEY: &'static str = "ELEMENT";
+
+pub fn extension_routes() -> Vec<(Method, &'static str, GeckoExtensionRoute)> {
+    return vec![
+        (
+            Method::GET,
+            "/session/{sessionId}/moz/context",
+            GeckoExtensionRoute::GetContext,
+        ),
+        (
+            Method::POST,
+            "/session/{sessionId}/moz/context",
+            GeckoExtensionRoute::SetContext,
+        ),
+        (
+            Method::POST,
+            "/session/{sessionId}/moz/xbl/{elementId}/anonymous_children",
+            GeckoExtensionRoute::XblAnonymousChildren,
+        ),
+        (
+            Method::POST,
+            "/session/{sessionId}/moz/xbl/{elementId}/anonymous_by_attribute",
+            GeckoExtensionRoute::XblAnonymousByAttribute,
+        ),
+        (
+            Method::POST,
+            "/session/{sessionId}/moz/addon/install",
+            GeckoExtensionRoute::InstallAddon,
+        ),
+        (
+            Method::POST,
+            "/session/{sessionId}/moz/addon/uninstall",
+            GeckoExtensionRoute::UninstallAddon,
+        ),
+    ];
+}
+
+#[derive(Clone, PartialEq)]
+pub enum GeckoExtensionRoute {
+    GetContext,
+    SetContext,
+    XblAnonymousChildren,
+    XblAnonymousByAttribute,
+    InstallAddon,
+    UninstallAddon,
+}
+
+impl WebDriverExtensionRoute for GeckoExtensionRoute {
+    type Command = GeckoExtensionCommand;
+
+    fn command(
+        &self,
+        params: &Captures,
+        body_data: &Value,
+    ) -> WebDriverResult<WebDriverCommand<GeckoExtensionCommand>> {
+        let command = match self {
+            &GeckoExtensionRoute::GetContext => GeckoExtensionCommand::GetContext,
+            &GeckoExtensionRoute::SetContext => {
+                GeckoExtensionCommand::SetContext(serde_json::from_value(body_data.clone())?)
+            }
+            &GeckoExtensionRoute::XblAnonymousChildren => {
+                let element_id = try_opt!(
+                    params.name("elementId"),
+                    ErrorStatus::InvalidArgument,
+                    "Missing elementId parameter"
+                );
+                let element = WebElement::new(element_id.as_str().to_string());
+                GeckoExtensionCommand::XblAnonymousChildren(element)
+            }
+            &GeckoExtensionRoute::XblAnonymousByAttribute => {
+                let element_id = try_opt!(
+                    params.name("elementId"),
+                    ErrorStatus::InvalidArgument,
+                    "Missing elementId parameter"
+                );
+                GeckoExtensionCommand::XblAnonymousByAttribute(
+                    WebElement::new(element_id.as_str().into()),
+                    serde_json::from_value(body_data.clone())?,
+                )
+            }
+            &GeckoExtensionRoute::InstallAddon => {
+                GeckoExtensionCommand::InstallAddon(serde_json::from_value(body_data.clone())?)
+            }
+            &GeckoExtensionRoute::UninstallAddon => {
+                GeckoExtensionCommand::UninstallAddon(serde_json::from_value(body_data.clone())?)
+            }
+        };
+        Ok(WebDriverCommand::Extension(command))
+    }
+}
+
+#[derive(Clone, PartialEq)]
+pub enum GeckoExtensionCommand {
+    GetContext,
+    SetContext(GeckoContextParameters),
+    XblAnonymousChildren(WebElement),
+    XblAnonymousByAttribute(WebElement, XblLocatorParameters),
+    InstallAddon(AddonInstallParameters),
+    UninstallAddon(AddonUninstallParameters),
+}
+
+impl WebDriverExtensionCommand for GeckoExtensionCommand {
+    fn parameters_json(&self) -> Option<Value> {
+        match self {
+            &GeckoExtensionCommand::GetContext => None,
+            &GeckoExtensionCommand::InstallAddon(ref x) => {
+                Some(serde_json::to_value(x.clone()).unwrap())
+            }
+            &GeckoExtensionCommand::SetContext(ref x) => {
+                Some(serde_json::to_value(x.clone()).unwrap())
+            }
+            &GeckoExtensionCommand::UninstallAddon(ref x) => {
+                Some(serde_json::to_value(x.clone()).unwrap())
+            }
+            &GeckoExtensionCommand::XblAnonymousByAttribute(_, ref x) => {
+                Some(serde_json::to_value(x.clone()).unwrap())
+            }
+            &GeckoExtensionCommand::XblAnonymousChildren(_) => None,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize)]
+pub struct AddonInstallParameters {
+    pub path: String,
+    pub temporary: bool,
+}
+
+impl<'de> Deserialize<'de> for AddonInstallParameters {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        #[derive(Debug, Deserialize)]
+        #[serde(deny_unknown_fields)]
+        struct Base64 {
+            addon: String,
+            temporary: bool,
+        };
+
+        #[derive(Debug, Deserialize)]
+        #[serde(deny_unknown_fields)]
+        struct Path {
+            path: String,
+            temporary: bool,
+        };
+
+        #[derive(Debug, Deserialize)]
+        #[serde(untagged)]
+        enum Helper {
+            Base64(Base64),
+            Path(Path),
+        };
+
+        let params = match Helper::deserialize(deserializer)? {
+            Helper::Path(ref mut data) => AddonInstallParameters {
+                path: data.path.clone(),
+                temporary: data.temporary,
+            },
+            Helper::Base64(ref mut data) => {
+                let content = base64::decode(&data.addon).map_err(de::Error::custom)?;
+
+                let path = env::temp_dir()
+                    .as_path()
+                    .join(format!("addon-{}.xpi", Uuid::new_v4()));
+                let mut xpi_file = File::create(&path).map_err(de::Error::custom)?;
+                xpi_file
+                    .write(content.as_slice())
+                    .map_err(de::Error::custom)?;
+
+                let path = match path.to_str() {
+                    Some(path) => path.to_string(),
+                    None => return Err(de::Error::custom("could not write addon to file")),
+                };
+
+                AddonInstallParameters {
+                    path: path,
+                    temporary: data.temporary,
+                }
+            }
+        };
+
+        Ok(params)
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct AddonUninstallParameters {
+    pub id: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum GeckoContext {
+    Content,
+    Chrome,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct GeckoContextParameters {
+    pub context: GeckoContext,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct XblLocatorParameters {
+    pub name: String,
+    pub value: String,
+}
+
+#[derive(Default, Debug)]
+pub struct LogOptions {
+    pub level: Option<logging::Level>,
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::fs::File;
+    use std::io::Read;
+    use test::check_deserialize;
+
+    #[test]
+    fn test_json_addon_install_parameters_null() {
+        let json = r#""#;
+
+        assert!(serde_json::from_str::<AddonInstallParameters>(&json).is_err());
+    }
+
+    #[test]
+    fn test_json_addon_install_parameters_empty() {
+        let json = r#"{}"#;
+
+        assert!(serde_json::from_str::<AddonInstallParameters>(&json).is_err());
+    }
+
+    #[test]
+    fn test_json_addon_install_parameters_with_path() {
+        let json = r#"{"path": "/path/to.xpi", "temporary": true}"#;
+        let data = AddonInstallParameters {
+            path: "/path/to.xpi".to_string(),
+            temporary: true,
+        };
+
+        check_deserialize(&json, &data);
+    }
+
+    #[test]
+    fn test_json_addon_install_parameters_with_path_invalid_type() {
+        let json = r#"{"path": true, "temporary": true}"#;
+
+        assert!(serde_json::from_str::<AddonInstallParameters>(&json).is_err());
+    }
+
+    #[test]
+    fn test_json_addon_install_parameters_with_path_and_temporary_invalid_type() {
+        let json = r#"{"path": "/path/to.xpi", "temporary": "foo"}"#;
+
+        assert!(serde_json::from_str::<AddonInstallParameters>(&json).is_err());
+    }
+
+    #[test]
+    fn test_json_addon_install_parameters_with_path_only() {
+        let json = r#"{"path": "/path/to.xpi"}"#;
+
+        assert!(serde_json::from_str::<AddonInstallParameters>(&json).is_err());
+    }
+
+    #[test]
+    fn test_json_addon_install_parameters_with_addon() {
+        let json = r#"{"addon": "aGVsbG8=", "temporary": true}"#;
<