Merge inbound to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Thu, 08 Feb 2018 12:04:26 +0200
changeset 402914 0ac953fcddf10132eaecdb753d72b2ba5a43c32a
parent 402913 06b5d7476ebd6dd611f1d22c15f3be2d812fa51b (current diff)
parent 402839 19b24b952a6ee7ed9ab63418570300b57e40d483 (diff)
child 402915 fdab702b72fd058c47dc776d8735e62b44bff202
child 402980 960e8b8c31477eb53ad5182464f5d1a5b41e6fe1
push id99674
push usershindli@mozilla.com
push dateThu, 08 Feb 2018 10:14:33 +0000
treeherdermozilla-inbound@fdab702b72fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly win32
0ac953fcddf1 / 60.0a1 / 20180208103049 / files
nightly win64
0ac953fcddf1 / 60.0a1 / 20180208103049 / files
nightly linux32
nightly linux64
nightly mac
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
browser/components/search/content/search.xml
build/sanitizers/ubsan_blacklist_int.txt
devtools/client/inspector/grids/utils/l10n.js
dom/webauthn/WebAuthnManager.cpp
testing/web-platform/meta/content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html.ini
testing/web-platform/meta/content-security-policy/blob/blob-urls-do-not-match-self.sub.html.ini
testing/web-platform/meta/content-security-policy/connect-src/connect-src-beacon-redirect-to-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/connect-src/connect-src-eventsource-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-redirect-to-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/connect-src/worker-from-guid.sub.html.ini
testing/web-platform/meta/content-security-policy/font-src/font-stylesheet-font-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/generic/generic-0_10_1.sub.html.ini
testing/web-platform/meta/content-security-policy/generic/generic-0_2_2.sub.html.ini
testing/web-platform/meta/content-security-policy/generic/generic-0_2_3.html.ini
testing/web-platform/meta/content-security-policy/generic/generic-0_8_1.sub.html.ini
testing/web-platform/meta/content-security-policy/img-src/report-blocked-data-uri.sub.html.ini
testing/web-platform/meta/content-security-policy/object-src/object-src-url-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/script-src/injected-inline-script-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/script-src/script-src-1_1.html.ini
testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_discard_whitelist.html.ini
testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce.html.ini
testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only.html.ini
testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri.html.ini
testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce.html.ini
testing/web-platform/meta/content-security-policy/script-src/scripthash-unicode-normalization.sub.html.ini
testing/web-platform/meta/content-security-policy/script-src/scriptnonce-and-scripthash.sub.html.ini
testing/web-platform/meta/content-security-policy/script-src/scriptnonce-ignore-unsafeinline.sub.html.ini
testing/web-platform/meta/content-security-policy/securitypolicyviolation/idl.html.ini
testing/web-platform/meta/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.ini
testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html.ini
testing/web-platform/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini
testing/web-platform/meta/content-security-policy/style-src/injected-inline-style-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/inline-style-allowed-while-cloning-objects.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/inline-style-attribute-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-hash-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-imported-style-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-injected-inline-style-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-injected-stylesheet-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-attribute-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-none-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/style-src-stylesheet-nonce-blocked.html.ini
testing/web-platform/meta/content-security-policy/style-src/stylehash-basic-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/stylenonce-allowed.sub.html.ini
testing/web-platform/meta/content-security-policy/style-src/stylenonce-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini
testing/web-platform/meta/content-security-policy/svg/svg-inline.sub.html.ini
testing/web-platform/meta/content-security-policy/unsafe-eval/eval-blocked-and-sends-report.sub.html.ini
testing/web-platform/meta/content-security-policy/unsafe-eval/eval-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/unsafe-eval/eval-scripts-setInterval-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/unsafe-eval/eval-scripts-setTimeout-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/unsafe-eval/function-constructor-blocked.sub.html.ini
new file mode 100644
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,1 @@
+Nika Layzell <nika@thelayzells.com> Michael Layzell <michael@thelayzells.com>
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -573,17 +573,17 @@ static const nsRoleMapEntry sWAIRoleMaps
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eLandmark,
     kNoReqStates
   },
   { // document
     &nsGkAtoms::document,
-    roles::DOCUMENT,
+    roles::NON_NATIVE_DOCUMENT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eReadonlyUntilEditable
   },
@@ -614,17 +614,17 @@ static const nsRoleMapEntry sWAIRoleMaps
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eLandmark,
     kNoReqStates
   },
   { // graphics-document
     &nsGkAtoms::graphicsDocument,
-    roles::DOCUMENT,
+    roles::NON_NATIVE_DOCUMENT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eReadonlyUntilEditable
   },
--- a/accessible/base/Role.h
+++ b/accessible/base/Role.h
@@ -106,17 +106,17 @@ enum Role {
   /**
    * Represents a main window for an application. It is used for
    * role="application". Also refer to APP_ROOT
    */
   APPLICATION = 14,
 
   /**
    * Represents a document window. A document window is always contained within
-   * an application window. It is used for role="document".
+   * an application window. For role="document", see NON_NATIVE_DOCUMENT.
    */
   DOCUMENT = 15,
 
   /**
    * Represents a pane within a frame or document window. Users can navigate
    * between panes and within the contents of the current pane, but cannot
    * navigate between items in different panes. Thus, panes represent a level
    * of grouping lower than frame windows or documents, but above individual
@@ -638,23 +638,22 @@ enum Role {
   ENTRY = 102,
 
   /**
    * A caption describing another object.
    */
   CAPTION = 103,
 
   /**
-   * A visual frame or container which contains a view of document content.
-   * Document frames may occur within another Document instance, in which case
-   * the second document may be said to be embedded in the containing instance.
-   * HTML frames are often DOCUMENT_FRAME. Either this object, or a
-   * singleton descendant, should implement the Document interface.
+   * An element containing content that assistive technology users may want to
+   * browse in a reading mode, rather than a focus/interactive/application mode.
+   * This role is used for role="document". For the container which holds the
+   * content of a web page, see DOCUMENT.
    */
-  DOCUMENT_FRAME = 104,
+  NON_NATIVE_DOCUMENT = 104,
 
   /**
    * Heading.
    */
   HEADING = 105,
 
   /**
    * An object representing a page of document content.  It is used in documents
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -124,17 +124,17 @@ ROLE(APPLICATION,
      ATK_ROLE_EMBEDDED,
      NSAccessibilityGroupRole,  //Unused on OS X. the system will take care of this.
      ROLE_SYSTEM_APPLICATION,
      ROLE_SYSTEM_APPLICATION,
      eNoNameRule)
 
 ROLE(DOCUMENT,
      "document",
-     ATK_ROLE_DOCUMENT_FRAME,
+     ATK_ROLE_DOCUMENT_WEB,
      @"AXWebArea",
      ROLE_SYSTEM_DOCUMENT,
      ROLE_SYSTEM_DOCUMENT,
      eNoNameRule)
 
 /**
  *  msaa comment:
  *   We used to map to ROLE_SYSTEM_PANE, but JAWS would
@@ -844,22 +844,22 @@ ROLE(ENTRY,
 ROLE(CAPTION,
      "caption",
      ATK_ROLE_CAPTION,
      NSAccessibilityStaticTextRole,
      USE_ROLE_STRING,
      IA2_ROLE_CAPTION,
      eNameFromSubtreeIfReqRule)
 
-ROLE(DOCUMENT_FRAME,
-     "document frame",
+ROLE(NON_NATIVE_DOCUMENT,
+     "non-native document",
      ATK_ROLE_DOCUMENT_FRAME,
-     NSAccessibilityScrollAreaRole,
+     NSAccessibilityGroupRole,
      USE_ROLE_STRING,
-     IA2_ROLE_UNKNOWN,
+     ROLE_SYSTEM_DOCUMENT,
      eNoNameRule)
 
 ROLE(HEADING,
      "heading",
      ATK_ROLE_HEADING,
      @"AXHeading",
      USE_ROLE_STRING,
      IA2_ROLE_HEADING,
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -2346,17 +2346,17 @@ DocAccessible::CacheChildrenInSubtree(Ac
   // Fire events for ARIA elements.
   if (!aRoot->HasARIARole()) {
     return;
   }
 
   // XXX: we should delay document load complete event if the ARIA document
   // has aria-busy.
   roles::Role role = aRoot->ARIARole();
-  if (!aRoot->IsDoc() && (role == roles::DIALOG || role == roles::DOCUMENT)) {
+  if (!aRoot->IsDoc() && (role == roles::DIALOG || role == roles::NON_NATIVE_DOCUMENT)) {
     FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
   }
 }
 
 void
 DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
 {
   aRoot->mStateFlags |= eIsNotInDocument;
--- a/accessible/interfaces/nsIAccessibleRole.idl
+++ b/accessible/interfaces/nsIAccessibleRole.idl
@@ -99,17 +99,17 @@ interface nsIAccessibleRole : nsISupport
   /**
    * Represents a main window for an application. It is used for
    * role="application". Also refer to ROLE_APP_ROOT
    */
   const unsigned long ROLE_APPLICATION = 14;
 
   /**
    * Represents a document window. A document window is always contained within
-   * an application window. It is used for role="document".
+   * an application window. For role="document", see NON_NATIVE_DOCUMENT.
    */
   const unsigned long ROLE_DOCUMENT = 15;
 
   /**
    * Represents a pane within a frame or document window. Users can navigate
    * between panes and within the contents of the current pane, but cannot
    * navigate between items in different panes. Thus, panes represent a level
    * of grouping lower than frame windows or documents, but above individual
@@ -632,23 +632,22 @@ interface nsIAccessibleRole : nsISupport
   const unsigned long ROLE_ENTRY = 102;
 
   /**
    * A caption describing another object.
    */
   const unsigned long ROLE_CAPTION = 103;
 
   /**
-   * A visual frame or container which contains a view of document content.
-   * Document frames may occur within another Document instance, in which case
-   * the second document may be said to be embedded in the containing instance.
-   * HTML frames are often ROLE_DOCUMENT_FRAME. Either this object, or a
-   * singleton descendant, should implement the Document interface.
+   * An element containing content that assistive technology users may want to
+   * browse in a reading mode, rather than a focus/interactive/application mode.
+   * This role is used for role="document". For the container which holds the
+   * content of a web page, see ROLE_DOCUMENT.
    */
-  const unsigned long ROLE_DOCUMENT_FRAME = 104;
+  const unsigned long ROLE_NON_NATIVE_DOCUMENT = 104;
 
   /**
    * Heading.
    */
   const unsigned long ROLE_HEADING = 105;
 
   /**
    * An object representing a page of document content.  It is used in documents
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -912,16 +912,19 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
       return @"AXDocumentNote";
 
     case roles::OUTLINEITEM:
       return @"AXOutlineRow";
 
     case roles::ARTICLE:
       return @"AXDocumentArticle";
 
+    case roles::NON_NATIVE_DOCUMENT:
+      return @"AXDocument";
+
     // macOS added an AXSubrole value to distinguish generic AXGroup objects
     // from those which are AXGroups as a result of an explicit ARIA role,
     // such as the non-landmark, non-listitem text containers in DPub ARIA.
     case roles::FOOTNOTE:
     case roles::SECTION:
       if (roleAtom)
         return @"AXApplicationGroup";
       break;
--- a/accessible/tests/mochitest/role.js
+++ b/accessible/tests/mochitest/role.js
@@ -80,16 +80,17 @@ const ROLE_MATHML_STACK_GROUP = nsIAcces
 const ROLE_MATHML_STACK_ROW = nsIAccessibleRole.ROLE_MATHML_STACK_ROW;
 const ROLE_MATHML_STACK_CARRIES = nsIAccessibleRole.ROLE_MATHML_STACK_CARRIES;
 const ROLE_MATHML_STACK_CARRY = nsIAccessibleRole.ROLE_MATHML_STACK_CARRY;
 const ROLE_MATHML_STACK_LINE = nsIAccessibleRole.ROLE_MATHML_STACK_LINE;
 const ROLE_MENUBAR = nsIAccessibleRole.ROLE_MENUBAR;
 const ROLE_MENUITEM = nsIAccessibleRole.ROLE_MENUITEM;
 const ROLE_MENUPOPUP = nsIAccessibleRole.ROLE_MENUPOPUP;
 const ROLE_NAVIGATION = nsIAccessibleRole.ROLE_NAVIGATION;
+const ROLE_NON_NATIVE_DOCUMENT = nsIAccessibleRole.ROLE_NON_NATIVE_DOCUMENT;
 const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
 const ROLE_NOTE = nsIAccessibleRole.ROLE_NOTE;
 const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
 const ROLE_OUTLINE = nsIAccessibleRole.ROLE_OUTLINE;
 const ROLE_OUTLINEITEM = nsIAccessibleRole.ROLE_OUTLINEITEM;
 const ROLE_PAGETAB = nsIAccessibleRole.ROLE_PAGETAB;
 const ROLE_PAGETABLIST = nsIAccessibleRole.ROLE_PAGETABLIST;
 const ROLE_PANE = nsIAccessibleRole.ROLE_PANE;
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -22,17 +22,17 @@
       testRole("aria_application", ROLE_APPLICATION);
       testRole("aria_article", ROLE_ARTICLE);
       testRole("aria_button", ROLE_PUSHBUTTON);
       testRole("aria_checkbox", ROLE_CHECKBUTTON);
       testRole("aria_columnheader", ROLE_COLUMNHEADER);
       testRole("aria_combobox", ROLE_EDITCOMBOBOX);
       testRole("aria_dialog", ROLE_DIALOG);
       testRole("aria_directory", ROLE_LIST);
-      testRole("aria_document", ROLE_DOCUMENT);
+      testRole("aria_document", ROLE_NON_NATIVE_DOCUMENT);
       testRole("aria_form", ROLE_FORM);
       testRole("aria_feed", ROLE_GROUPING);
       testRole("aria_figure", ROLE_FIGURE);
       testRole("aria_grid", ROLE_TABLE);
       testRole("aria_gridcell", ROLE_GRID_CELL);
       testRole("aria_group", ROLE_GROUPING);
       testRole("aria_heading", ROLE_HEADING);
       testRole("aria_img", ROLE_GRAPHIC);
--- a/accessible/tests/mochitest/role/test_graphics_aria.html
+++ b/accessible/tests/mochitest/role/test_graphics_aria.html
@@ -12,17 +12,17 @@
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
 
   <script type="application/javascript">
 
     function doTest() {
       // Graphics ARIA role map.
-      testRole("graphics-document", ROLE_DOCUMENT);
+      testRole("graphics-document", ROLE_NON_NATIVE_DOCUMENT);
       testRole("graphics-object", ROLE_GROUPING);
       testRole("graphics-symbol", ROLE_GRAPHIC);
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
--- a/accessible/tests/mochitest/tree/test_txtctrl.xul
+++ b/accessible/tests/mochitest/tree/test_txtctrl.xul
@@ -111,49 +111,35 @@
                 children: []
               }
             ]
           },
           {
             // xul:menupopup
             role: ROLE_COMBOBOX_LIST,
             children: []
+          },
+          {
+            // xul:richlistbox
+            role: ROLE_COMBOBOX_LIST,
+            children: []
           }
         ]
       };
 
-      function test_AutocompleteControl() {
-        testAccessibleTree("txc_autocomplete", accTree);
-        SimpleTest.finish();
-      }
-
       var txc = document.getElementById("txc_autocomplete");
       SimpleTest.ok(txc, "Testing (New) Toolkit autocomplete widget.");
 
       // Dumb access to trigger popup lazy creation.
       dump("Trigget popup lazy creation");
-      waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
+      waitForEvent(EVENT_REORDER, txc, () => {
+        testAccessibleTree("txc_autocomplete", accTree);
+        SimpleTest.finish();
+      });
       txc.popup;
-
-      accTree.children.push(
-        {
-          role: ROLE_LIST,
-          children: [
-            {
-              role: ROLE_LIST,
-              children: [
-                {
-                  role: ROLE_COLUMNHEADER,
-                  children: []
-                }
-              ]
-            }
-          ]
-        }
-      );
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <hbox flex="1" style="overflow: auto;">
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -774,18 +774,16 @@
                      placeholder="&urlbar.placeholder2;"
                      type="autocomplete"
                      autocompletesearch="unifiedcomplete"
                      autocompletesearchparam="enable-actions"
                      autocompletepopup="PopupAutoCompleteRichResult"
                      completeselectedindex="true"
                      shrinkdelay="250"
                      tabscrolling="true"
-                     showcommentcolumn="true"
-                     showimagecolumn="true"
                      newlines="stripsurroundingwhitespace"
                      ontextentered="this.handleCommand(param);"
                      ontextreverted="return this.handleRevert();"
                      pageproxystate="invalid">
               <!-- Use onclick instead of normal popup= syntax since the popup
                    code fires onmousedown, and hence eats our favicon drag events. -->
               <box id="identity-box" role="button"
                    align="center"
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -90,16 +90,24 @@ this.Policies = {
   "DisableFirefoxStudies": {
     onBeforeAddons(manager, param) {
       if (param == true) {
         manager.disallowFeature("Shield");
       }
     }
   },
 
+  "DisableFormHistory": {
+    onBeforeUIStartup(manager, param) {
+      if (param == true) {
+        setAndLockPref("browser.formfill.enable", false);
+      }
+    }
+  },
+
   "dont_check_default_browser": {
     onBeforeUIStartup(manager, param) {
       setAndLockPref("browser.shell.checkDefaultBrowser", false);
     }
   },
 
   "flash_plugin": {
     onBeforeUIStartup(manager, param) {
--- a/browser/components/enterprisepolicies/PoliciesValidator.jsm
+++ b/browser/components/enterprisepolicies/PoliciesValidator.jsm
@@ -38,20 +38,29 @@ function validateAndParseParamRecursive(
 
   log.debug(`checking @${param}@ for type ${properties.type}`);
   switch (properties.type) {
     case "boolean":
     case "number":
     case "integer":
     case "string":
     case "URL":
+    case "URLorEmpty":
     case "origin":
       return validateAndParseSimpleParam(param, properties.type);
 
     case "array":
+      if (param === undefined) {
+        // Accept a missing array as valid. Policies that use
+        // arrays should still check before iterating through
+        // the array, unless it is marked as "required" in the
+        // schema (but "required" is not implemented yet).
+        return [true, undefined];
+      }
+
       if (!Array.isArray(param)) {
         log.error("Array expected but not received");
         return [false, null];
       }
 
       let parsedArray = [];
       for (let item of param) {
         log.debug(`in array, checking @${item}@ for type ${properties.items.type}`);
@@ -90,16 +99,25 @@ function validateAndParseParamRecursive(
 }
 
 function validateAndParseSimpleParam(param, type) {
   let valid = false;
   let parsedParam = param;
 
   switch (type) {
     case "boolean":
+      if (typeof(param) == "boolean") {
+        valid = true;
+      } else if (typeof(param) == "number" &&
+                 (param == 0 || param == 1)) {
+        valid = true;
+        parsedParam = !!param;
+      }
+      break;
+
     case "number":
     case "string":
       valid = (typeof(param) == type);
       break;
 
     // integer is an alias to "number" that some JSON schema tools use
     case "integer":
       valid = (typeof(param) == "number");
@@ -121,20 +139,26 @@ function validateAndParseSimpleParam(par
           valid = true;
         }
       } catch (ex) {
         valid = false;
       }
       break;
 
     case "URL":
+    case "URLorEmpty":
       if (typeof(param) != "string") {
         break;
       }
 
+      if (type == "URLorEmpty" && param === "") {
+        valid = true;
+        break;
+      }
+
       try {
         parsedParam = Services.io.newURI(param);
         valid = true;
       } catch (ex) {
         valid = false;
       }
       break;
   }
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -45,16 +45,24 @@
     "DisableFirefoxStudies": {
       "description": "Prevents Firefox from running studies.",
       "first_available": "60.0",
 
       "type": "boolean",
       "enum": [true]
     },
 
+    "DisableFormHistory": {
+      "description": "Don't remember search and form history.",
+      "first_available": "60.0",
+
+      "type": "boolean",
+      "enum": [true]
+    },
+
     "dont_check_default_browser": {
       "description": "Don't check for the default browser on startup.",
       "first_available": "60.0",
 
       "type": "boolean",
       "enum": [true]
     },
 
--- a/browser/components/enterprisepolicies/tests/browser/browser.ini
+++ b/browser/components/enterprisepolicies/tests/browser/browser.ini
@@ -10,11 +10,12 @@ support-files =
 [browser_policies_popups_cookies_addons_flash.js]
 [browser_policies_setAndLockPref_API.js]
 [browser_policies_simple_policies.js]
 [browser_policies_validate_and_parse_API.js]
 [browser_policy_block_set_desktop_background.js]
 [browser_policy_default_browser_check.js]
 [browser_policy_disable_fxscreenshots.js]
 [browser_policy_display_bookmarks.js]
+[browser_policy_disable_formhistory.js]
 [browser_policy_display_menu.js]
 [browser_policy_disable_shield.js]
 
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_broken_json.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_broken_json.js
@@ -1,14 +1,10 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-add_task(async function test_clean_slate() {
-  await startWithCleanSlate();
-});
-
 add_task(async function test_broken_json() {
   await setupPolicyEngineWithJson("config_broken_json.json");
 
   is(Services.policies.status, Ci.nsIEnterprisePolicies.FAILED, "Engine was correctly set to the error state");
 });
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_popups_cookies_addons_flash.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_popups_cookies_addons_flash.js
@@ -2,20 +2,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function URI(str) {
   return Services.io.newURI(str);
 }
 
-add_task(async function test_start_with_disabled_engine() {
-  await startWithCleanSlate();
-});
-
 add_task(async function test_setup_preexisting_permissions() {
   // Pre-existing ALLOW permissions that should be overriden
   // with DENY.
   Services.perms.add(URI("https://www.pre-existing-allow.com"),
                      "popup",
                      Ci.nsIPermissionManager.ALLOW_ACTION,
                      Ci.nsIPermissionManager.EXPIRE_SESSION);
 
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js
@@ -1,17 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-add_task(async function test_clean_slate() {
-  await startWithCleanSlate();
-});
-
 let { Policies, setAndLockPref } = ChromeUtils.import("resource:///modules/policies/Policies.jsm", {});
 
 function checkPref(prefName, expectedValue) {
   let prefType, prefValue;
   switch (typeof(expectedValue)) {
     case "boolean":
       prefType = Services.prefs.PREF_BOOL;
       prefValue = Services.prefs.getBoolPref(prefName);
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_simple_policies.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_simple_policies.js
@@ -1,17 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-add_task(async function test_clean_slate() {
-  await startWithCleanSlate();
-});
-
 add_task(async function test_simple_policies() {
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
     // Initialize the service in the content process, in case it hasn't
     // already started.
     Services.policies;
   });
 
   let { Policies } = ChromeUtils.import("resource:///modules/policies/Policies.jsm", {});
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_validate_and_parse_API.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_validate_and_parse_API.js
@@ -16,19 +16,26 @@ add_task(async function test_boolean_val
 
   let valid, parsed;
   [valid, parsed] = PoliciesValidator.validateAndParseParameters(true, schema);
   ok(valid && parsed === true, "Parsed boolean value correctly");
 
   [valid, parsed] = PoliciesValidator.validateAndParseParameters(false, schema);
   ok(valid && parsed === false, "Parsed boolean value correctly");
 
+  [valid, parsed] = PoliciesValidator.validateAndParseParameters(0, schema);
+  ok(valid && parsed === false, "0 parsed as false correctly");
+
+  [valid, parsed] = PoliciesValidator.validateAndParseParameters(1, schema);
+  ok(valid && parsed === true, "1 parsed as true correctly");
+
   // Invalid values:
   ok(!PoliciesValidator.validateAndParseParameters("0", schema)[0], "No type coercion");
   ok(!PoliciesValidator.validateAndParseParameters("true", schema)[0], "No type coercion");
+  ok(!PoliciesValidator.validateAndParseParameters(2, schema)[0], "Other number values are not valid");
   ok(!PoliciesValidator.validateAndParseParameters(undefined, schema)[0], "Invalid value");
   ok(!PoliciesValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
   ok(!PoliciesValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
 });
 
 add_task(async function test_number_values() {
   let schema = {
     type: "number"
@@ -87,21 +94,49 @@ add_task(async function test_URL_values(
   let valid, parsed;
   [valid, parsed] = PoliciesValidator.validateAndParseParameters("https://www.example.com/foo#bar", schema);
   ok(valid, "URL is valid");
   ok(parsed instanceof Ci.nsIURI, "parsed is a nsIURI");
   is(parsed.prePath, "https://www.example.com", "prePath is correct");
   is(parsed.pathQueryRef, "/foo#bar", "pathQueryRef is correct");
 
   // Invalid values:
+  ok(!PoliciesValidator.validateAndParseParameters("", schema)[0], "Empty string is not accepted for URL");
   ok(!PoliciesValidator.validateAndParseParameters("www.example.com", schema)[0], "Scheme is required for URL");
   ok(!PoliciesValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid URL");
   ok(!PoliciesValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
 });
 
+add_task(async function test_URLorEmpty_values() {
+  let schema = {
+    type: "URLorEmpty"
+  };
+
+  let valid, parsed;
+  [valid, parsed] = PoliciesValidator.validateAndParseParameters("https://www.example.com/foo#bar", schema);
+  ok(valid, "URL is valid");
+  ok(parsed instanceof Ci.nsIURI, "parsed is a nsIURI");
+  is(parsed.prePath, "https://www.example.com", "prePath is correct");
+  is(parsed.pathQueryRef, "/foo#bar", "pathQueryRef is correct");
+
+  // Test that this type also accept empty strings
+  [valid, parsed] = PoliciesValidator.validateAndParseParameters("", schema);
+  ok(valid, "URLorEmpty is valid");
+  ok(!parsed, "parsed value is falsy");
+  is(typeof(parsed), "string", "parsed is a string");
+  is(parsed, "", "parsed is an empty string");
+
+  // Invalid values:
+  ok(!PoliciesValidator.validateAndParseParameters(" ", schema)[0], "Non-empty string is not accepted");
+  ok(!PoliciesValidator.validateAndParseParameters("www.example.com", schema)[0], "Scheme is required for URL");
+  ok(!PoliciesValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid URL");
+  ok(!PoliciesValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
+});
+
+
 add_task(async function test_origin_values() {
   // Origin is a URL that doesn't contain a path/query string (i.e., it's only scheme + host + port)
   let schema = {
     type: "origin"
   };
 
   let valid, parsed;
   [valid, parsed] = PoliciesValidator.validateAndParseParameters("https://www.example.com", schema);
@@ -223,8 +258,39 @@ add_task(async function test_array_of_ob
   ok(typeof(parsed[0]) == "object" && typeof(parsed[1]) == "object", "Correct objects inside array");
 
   is(parsed[0].url.spec, "https://www.example.com/bookmark1", "Correct URL for bookmark 1");
   is(parsed[1].url.spec, "https://www.example.com/bookmark2", "Correct URL for bookmark 2");
 
   is(parsed[0].title, "Foo", "Correct title for bookmark 1");
   is(parsed[1].title, "Bar", "Correct title for bookmark 2");
 });
+
+add_task(async function test_missing_arrays_inside_objects() {
+  let schema = {
+    type: "object",
+    properties: {
+      allow: {
+        type: "array",
+        items: {
+          type: "boolean"
+        }
+      },
+      block: {
+        type: "array",
+        items: {
+          type: "boolean"
+        }
+      }
+
+    }
+  };
+
+  let valid, parsed;
+  [valid, parsed] = PoliciesValidator.validateAndParseParameters({
+    allow: [true, true, true]
+  }, schema);
+
+  ok(valid, "Object is valid");
+  is(parsed.allow.length, 3, "Allow array is correct.");
+  is(parsed.block, undefined, "Block array is undefined, as expected.");
+});
+
new file mode 100644
--- /dev/null
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_formhistory.js
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_policy_disable_formhistory() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "DisableFormHistory": true
+    }
+  });
+
+  is(Services.prefs.getBoolPref("browser.formfill.enable"), false, "FormHistory has been disabled");
+  is(Services.prefs.prefIsLocked("browser.formfill.enable"), true, "FormHistory pref has been locked");
+});
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_fxscreenshots.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_fxscreenshots.js
@@ -8,19 +8,16 @@ const PREF_DISABLE_FX_SCREENSHOTS = "ext
 async function checkScreenshots(shouldBeEnabled) {
   return BrowserTestUtils.waitForCondition(() => {
     return !!PageActions.actionForID("screenshots") == shouldBeEnabled;
   }, "Expecting screenshots to be " + shouldBeEnabled);
 }
 
 add_task(async function test_disable_firefox_screenshots() {
   await BrowserTestUtils.withNewTab("data:text/html,Test", async function() {
-    await setupPolicyEngineWithJson("");
-    is(Services.policies.status, Services.policies.INACTIVE, "Start with no policies");
-
     // Firefox Screenshots are disabled in tests, so make sure we enable
     // it first to ensure that the test is valid.
     Services.prefs.setBoolPref(PREF_DISABLE_FX_SCREENSHOTS, false);
     await checkScreenshots(true);
 
     await setupPolicyEngineWithJson({
       "policies": {
         "DisableFirefoxScreenshots": true
--- a/browser/components/enterprisepolicies/tests/browser/head.js
+++ b/browser/components/enterprisepolicies/tests/browser/head.js
@@ -38,12 +38,21 @@ async function setupPolicyEngineWithJson
     let schemaModule = ChromeUtils.import("resource:///modules/policies/schema.jsm", {});
     schemaModule.schema = customSchema;
   }
 
   Services.obs.notifyObservers(null, "EnterprisePolicies:Restart");
   return promise;
 }
 
-async function startWithCleanSlate() {
-  await setupPolicyEngineWithJson("");
-  is(Services.policies.status, Ci.nsIEnterprisePolicies.INACTIVE, "Engine is inactive");
-}
+add_task(async function policies_headjs_startWithCleanSlate() {
+  if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) {
+    await setupPolicyEngineWithJson("");
+  }
+  is(Services.policies.status, Ci.nsIEnterprisePolicies.INACTIVE, "Engine is inactive at the start of the test");
+});
+
+registerCleanupFunction(async function policies_headjs_finishWithCleanSlate() {
+  if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) {
+    await setupPolicyEngineWithJson("");
+  }
+  is(Services.policies.status, Ci.nsIEnterprisePolicies.INACTIVE, "Engine is inactive at the end of the test");
+});
--- a/browser/components/places/content/editBookmarkOverlay.xul
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -117,20 +117,20 @@
           <label value="&editBookmarkOverlay.tags.label;"
                  class="editBMPanel_rowLabel"
                  accesskey="&editBookmarkOverlay.tags.accesskey;"
                  control="editBMPanel_tagsField"/>
           <hbox flex="1" align="center">
             <textbox id="editBMPanel_tagsField"
                      type="autocomplete"
                      flex="1"
-                     autocompletesearch="places-tag-autocomplete" 
+                     autocompletesearch="places-tag-autocomplete"
+                     autocompletepopup="PopupAutoComplete"
                      completedefaultindex="true"
                      tabscrolling="true"
-                     showcommentcolumn="true"
                      placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"
                      onchange="gEditItemOverlay.onTagsFieldChange();"/>
             <button id="editBMPanel_tagsSelectorExpander"
                     class="expander-down"
                     tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                     tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                     tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
                     oncommand="gEditItemOverlay.toggleTagsSelector();"/>
--- a/browser/components/places/tests/browser/browser_bookmarksProperties.js
+++ b/browser/components/places/tests/browser/browser_bookmarksProperties.js
@@ -99,31 +99,28 @@ gTests.push({
       handleEvent(aEvent) {
         switch (aEvent.type) {
           case "popuphidden":
             // Everything worked fine, we can stop observing the window.
             self._cleanShutdown = true;
             self.window.document.documentElement.cancelDialog();
             break;
           case "popupshown":
-            (async function() {
-              tagsField.popup.removeEventListener("popupshown", this, true);
-              // In case this test fails the window will close, the test will fail
-              // since we didn't set _cleanShutdown.
-              var tree = tagsField.popup.tree;
-              // Focus and select first result.
-              Assert.notEqual(tree, null, "Autocomplete results tree exists");
-              Assert.equal(tree.view.rowCount, 1, "We have 1 autocomplete result");
-              tagsField.popup.selectedIndex = 0;
-              Assert.equal(tree.view.selection.count, 1,
-                 "We have selected a tag from the autocomplete popup");
-              info("About to focus the autocomplete results tree");
-              tree.focus();
-              EventUtils.synthesizeKey("VK_RETURN", {}, self.window);
-            })();
+            tagsField.popup.removeEventListener("popupshown", this, true);
+            // In case this test fails the window will close, the test will fail
+            // since we didn't set _cleanShutdown.
+            let richlistbox = tagsField.popup.richlistbox;
+            // Focus and select first result.
+            Assert.equal(richlistbox.itemCount, 1, "We have 1 autocomplete result");
+            tagsField.popup.selectedIndex = 0;
+            Assert.equal(richlistbox.selectedItems.length, 1,
+               "We have selected a tag from the autocomplete popup");
+            info("About to focus the autocomplete results");
+            richlistbox.focus();
+            EventUtils.synthesizeKey("VK_RETURN", {}, self.window);
             break;
           default:
             Assert.ok(false, "unknown event: " + aEvent.type);
         }
       }
     };
     tagsField.popup.addEventListener("popupshown", popupListener, true);
     tagsField.popup.addEventListener("popuphidden", popupListener, true);
@@ -209,25 +206,24 @@ gTests.push({
             // Everything worked fine.
             self._cleanShutdown = true;
             self.window.document.documentElement.cancelDialog();
             break;
           case "popupshown":
             tagsField.popup.removeEventListener("popupshown", this, true);
             // In case this test fails the window will close, the test will fail
             // since we didn't set _cleanShutdown.
-            var tree = tagsField.popup.tree;
+            let richlistbox = tagsField.popup.richlistbox;
             // Focus and select first result.
-            Assert.notEqual(tree, null, "Autocomplete results tree exists");
-            Assert.ok(tree.view.rowCount, 1, "We have 1 autocomplete result");
+            Assert.ok(richlistbox.itemCount, 1, "We have 1 autocomplete result");
             tagsField.popup.selectedIndex = 0;
-            Assert.ok(tree.view.selection.count, 1,
+            Assert.ok(richlistbox.selectedItems.length, 1,
                "We have selected a tag from the autocomplete popup");
-            info("About to focus the autocomplete results tree");
-            tree.focus();
+            info("About to focus the autocomplete results");
+            richlistbox.focus();
             EventUtils.synthesizeKey("VK_ESCAPE", {}, self.window);
             break;
           default:
             Assert.ok(false, "unknown event: " + aEvent.type);
         }
       }
     };
     tagsField.popup.addEventListener("popupshown", popupListener, true);
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -737,19 +737,16 @@
             if (popup.id == "PopupSearchAutoComplete") {
               popup.setAttribute("norolluponanchor", "true");
             }
 
             popup.mInput = this;
             // clear any previous selection, see bugs 400671 and 488357
             popup.selectedIndex = -1;
 
-            popup.showCommentColumn = this.showCommentColumn;
-            popup.showImageColumn = this.showImageColumn;
-
             document.popupNode = null;
 
             const isRTL = getComputedStyle(this, "").direction == "rtl";
 
             var outerRect = this.getBoundingClientRect();
             var innerRect = this.inputField.getBoundingClientRect();
             let width = isRTL ?
                         innerRect.right - outerRect.left :
--- a/build/autoconf/sanitize.m4
+++ b/build/autoconf/sanitize.m4
@@ -75,53 +75,54 @@ if test -n "$MOZ_TSAN"; then
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
 AC_SUBST(MOZ_TSAN)
 
 dnl ========================================================
 dnl = Use UndefinedBehavior Sanitizer to find integer overflows
 dnl ========================================================
 
-MOZ_ARG_ENABLE_BOOL(ubsan-int-overflow,
-[  --enable-ubsan-int-overflow       Enable UndefinedBehavior Sanitizer (Signed Integer Overflow Parts, default=no)],
-   MOZ_UBSAN_INT_OVERFLOW=1,
-   MOZ_UBSAN_INT_OVERFLOW= )
-MOZ_ARG_ENABLE_BOOL(ubsan-uint-overflow,
-[  --enable-ubsan-uint-overflow       Enable UndefinedBehavior Sanitizer (Unsigned Integer Overflow Parts, default=no)],
-   MOZ_UBSAN_UINT_OVERFLOW=1,
-   MOZ_UBSAN_UINT_OVERFLOW= )
+MOZ_ARG_ENABLE_BOOL(signed-overflow-sanitizer,
+[  --enable-signed-overflow-sanitizer       Enable UndefinedBehavior Sanitizer (Signed Integer Overflow Parts, default=no)],
+   MOZ_SIGNED_OVERFLOW_SANITIZE=1,
+   MOZ_SIGNED_OVERFLOW_SANITIZE= )
+MOZ_ARG_ENABLE_BOOL(unsigned-overflow-sanitizer,
+[  --enable-unsigned-overflow-sanitizer       Enable UndefinedBehavior Sanitizer (Unsigned Integer Overflow Parts, default=no)],
+   MOZ_UNSIGNED_OVERFLOW_SANITIZE=1,
+   MOZ_UNSIGNED_OVERFLOW_SANITIZE= )
 
-if test -n "$MOZ_UBSAN_INT_OVERFLOW$MOZ_UBSAN_UINT_OVERFLOW"; then
+if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then
     MOZ_LLVM_HACKS=1
     MOZ_UBSAN=1
-    # The blacklist really should be split into separate signed/unsigned
-    # blacklists, but we leave that task for another day.
-    CFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_blacklist_int.txt $CFLAGS"
-    CXXFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_blacklist_int.txt $CXXFLAGS"
-    if test -n "$MOZ_UBSAN_INT_OVERFLOW"; then
+    SANITIZER_BLACKLISTS=""
+    if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE"; then
+        SANITIZER_BLACKLISTS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_signed_overflow_blacklist.txt $SANITIZER_BLACKLISTS"
         CFLAGS="-fsanitize=signed-integer-overflow $CFLAGS"
         CXXFLAGS="-fsanitize=signed-integer-overflow $CXXFLAGS"
         if test -z "$CLANG_CL"; then
             LDFLAGS="-fsanitize=signed-integer-overflow $LDFLAGS"
         fi
-        AC_DEFINE(MOZ_UBSAN_INT_OVERFLOW)
+        AC_DEFINE(MOZ_SIGNED_OVERFLOW_SANITIZE)
     fi
-    if test -n "$MOZ_UBSAN_UINT_OVERFLOW"; then
+    if test -n "$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then
+        SANITIZER_BLACKLISTS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt $SANITIZER_BLACKLISTS"
         CFLAGS="-fsanitize=unsigned-integer-overflow $CFLAGS"
         CXXFLAGS="-fsanitize=unsigned-integer-overflow $CXXFLAGS"
         if test -z "$CLANG_CL"; then
             LDFLAGS="-fsanitize=unsigned-integer-overflow $LDFLAGS"
         fi
-        AC_DEFINE(MOZ_UBSAN_UINT_OVERFLOW)
+        AC_DEFINE(MOZ_UNSIGNED_OVERFLOW_SANITIZE)
     fi
+    CFLAGS="$SANITIZER_BLACKLISTS $CFLAGS"
+    CXXFLAGS="$SANITIZER_BLACKLISTS $CXXFLAGS"
     AC_DEFINE(MOZ_UBSAN)
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
-AC_SUBST(MOZ_UBSAN_INT_OVERFLOW)
-AC_SUBST(MOZ_UBSAN_UINT_OVERFLOW)
+AC_SUBST(MOZ_SIGNED_OVERFLOW_SANITIZE)
+AC_SUBST(MOZ_UNSIGNED_OVERFLOW_SANITIZE)
 AC_SUBST(MOZ_UBSAN)
 
 # The LLVM symbolizer is used by all sanitizers
 AC_SUBST(LLVM_SYMBOLIZER)
 
 dnl ========================================================
 dnl = Enable hacks required for LLVM instrumentations
 dnl ========================================================
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -273,24 +273,30 @@ class RemoteAutomation(Automation):
         return self.RProcess(self._devicemanager, cmd, stdout, stderr, env, cwd, self._appName,
                              **self._processArgs)
 
     # be careful here as this inner class doesn't have access to outer class members
     class RProcess(object):
         # device manager process
         dm = None
         def __init__(self, dm, cmd, stdout=None, stderr=None, env=None, cwd=None, app=None,
-                     messageLogger=None):
+                     messageLogger=None, counts=None):
             self.dm = dm
             self.stdoutlen = 0
             self.lastTestSeen = "remoteautomation.py"
             self.proc = dm.launchProcess(cmd, stdout, cwd, env, True)
             self.messageLogger = messageLogger
             self.utilityPath = None
 
+            self.counts = counts
+            if self.counts is not None:
+                self.counts['pass'] = 0
+                self.counts['fail'] = 0
+                self.counts['todo'] = 0
+
             if (self.proc is None):
                 if cmd[0] == 'am':
                     self.proc = stdout
                 else:
                     raise Exception("unable to launch process")
             self.procName = cmd[0].split('/')[-1]
             if cmd[0] == 'am' and cmd[1] in RemoteAutomation._specialAmCommands:
                 self.procName = app
@@ -355,16 +361,32 @@ class RemoteAutomation(Automation):
                 return False
 
             for line in lines:
                 # This passes the line to the logger (to be logged or buffered)
                 parsed_messages = self.messageLogger.write(line)
                 for message in parsed_messages:
                     if isinstance(message, dict) and message.get('action') == 'test_start':
                         self.lastTestSeen = message['test']
+                    if isinstance(message, dict) and message.get('action') == 'log':
+                        line = message['message'].strip()
+                        if self.counts:
+                            m = re.match(".*:\s*(\d*)", line)
+                            if m:
+                                try:
+                                    val = int(m.group(1))
+                                    if "Passed:" in line:
+                                        self.counts['pass'] += val
+                                    elif "Failed:" in line:
+                                        self.counts['fail'] += val
+                                    elif "Todo:" in line:
+                                        self.counts['todo'] += val
+                                except:
+                                    pass
+
             return True
 
         @property
         def getLastTestSeen(self):
             return self.lastTestSeen
 
         # Wait for the remote process to end (or for its activity to go to background).
         # While waiting, periodically retrieve the process output and print it.
@@ -388,16 +410,18 @@ class RemoteAutomation(Automation):
                 hasOutput = False
                 if (not slowLog) or (timer % 60 == 0):
                     startRead = datetime.datetime.now()
                     hasOutput = self.read_stdout()
                     if (datetime.datetime.now() - startRead) > datetime.timedelta(seconds=5):
                         slowLog = True
                     if hasOutput:
                         noOutputTimer = 0
+                    if self.counts and 'pass' in self.counts and self.counts['pass'] > 0:
+                        interval = 0.5
                 time.sleep(interval)
                 timer += interval
                 noOutputTimer += interval
                 if datetime.datetime.now() > endTime:
                     status = 1
                     break
                 if (noOutputTimeout and noOutputTimer > noOutputTimeout):
                     status = 2
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -217,19 +217,19 @@ def old_configure_options(*options):
     '--enable-strip',
     '--enable-synth-pico',
     '--enable-system-cairo',
     '--enable-system-extension-dirs',
     '--enable-system-pixman',
     '--enable-system-sqlite',
     '--enable-tasktracer',
     '--enable-thread-sanitizer',
-    '--enable-ubsan-int-overflow',
-    '--enable-ubsan-uint-overflow',
+    '--enable-signed-overflow-sanitizer',
     '--enable-universalchardet',
+    '--enable-unsigned-overflow-sanitizer',
     '--enable-updater',
     '--enable-valgrind',
     '--enable-verify-mar',
     '--enable-xul',
     '--enable-zipwriter',
     '--includedir',
     '--libdir',
     '--no-create',
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -424,17 +424,17 @@ def valid_mt(path):
     except subprocess.CalledProcessError:
         pass
     raise FatalCheckError('%s is not Microsoft Manifest Tool')
 
 
 set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x)))
 
 
-link = check_prog('LINKER', ('link.exe',), paths=vc_compiler_path)
+link = check_prog('LINKER', ('link.exe',), paths=toolchain_search_path)
 
 add_old_configure_assignment('LINKER', link)
 
 
 # Normally, we'd just have CC, etc. set to absolute paths, but the build system
 # doesn't currently handle properly the case where the paths contain spaces.
 # Additionally, there's the issue described in toolchain.configure, in
 # valid_compiler().
rename from build/sanitizers/ubsan_blacklist_int.txt
rename to build/sanitizers/ubsan_signed_overflow_blacklist.txt
--- a/build/sanitizers/ubsan_blacklist_int.txt
+++ b/build/sanitizers/ubsan_signed_overflow_blacklist.txt
@@ -1,30 +1,52 @@
 # This file contains an extensive compile-time blacklist for silencing highly
-# frequent signed and unsigned integer overflows in our codebase, found by the
-# use of -fsanitize=integer. All of the overflows that caused an entry in this
-# list are highly frequent in our test suites (> 500 times per run) and therefore
-# unlikely to be bugs. Nevertheless, the slow down this test mode significantly
-# if left active. Without this list, the -fsanitize=integer test mode is unusable
-# both because of performance and the large number of results to check.
+# frequent signed integer overflows in our codebase, found by the use of
+# -fsanitize=signed-integer-overflow.  C/C++ say signed integer overflow is
+# undefined behavior, so instances of this need to be fixed.  But not all code
+# has been properly written to not overflow, and overflow-checking can have
+# significant compile time and runtime costs, so we will sometimes  disable
+# signed overflow checking.
+#
+# The rules in this file are applied at compile time; changes to this list
+# usually require a full rebuild to apply. If you can modify the source in
+# question to exempt individual functions using MOZ_NO_SANITIZE_SINT_OVERFLOW,
+# do that instead.
+#
+# The extensive number of entries below is for two reasons.
 #
-# Some of the entries on this list are more aggressive to get the build into a
-# state that allows any testing to happen at all. This is not an optimal solution
-# and it would be good if we could refine the tool and shorten this list over
-# the time. Source code annotations can also help with this.
+# First, compiler instrumentation for signed integer overflows has a cost, at
+# compile time and at runtime.  In performance-critical code proven to have no
+# signed overflow, it makes sense to turn off overflow detection to avoid both
+# costs.  (Indeed, -fsanitize=signed-integer-overflow is unusably slow without
+# this.)
+#
+# Second, many entries here are overly aggressive to get the build into a state
+# that allows any testing to happen at all.  Some of the entries here are for
+# issues that are highly frequent in our test suites -- over 500 times per run.
+# Aggressive entries now let us start using this mode, without having to first
+# fix wide swaths of existing code.
 #
-# The rules in this file are only applied at compile time. If you can modify the
-# source in question, consider function attributes to disable instrumentation.
+# Entries should be removed 1) as issues are fixed; and 2) as blacklist entries
+# can be moved out of this centralized file, into source-level blacklist
+# attributes on individual functions.
 
-# Ignore common overflows in the C++ std headers
+# All entries in this file are to suppress signed-integer-overflow problems.
+# Blacklists for other reasons should go in separate blacklist files.
+[signed-integer-overflow]
+
+# Overflows in the C++ std headers aren't necessarily bugs, because code inside
+# a language implementation can depend on compiler-specific behavior where C/C++
+# leave the behavior undefined.
 src:*bits/basic_string.h
 
-# Assume everything running through CheckedInt.h is ok. The CheckedInt class
-# casts signed integers to unsigned first and then does a post-overflow
-# check causing lots of unsigned integer overflow messages.
+# Assume everything running through CheckedInt.h is ok.  Signed overflows here
+# should generally have been guarded by safe overflow checks, so it's likely
+# safe to exempt it from overflow checking.  (This should eventually be verified
+# and functions individually tagged safe so this entry can be removed.)
 src:*/CheckedInt.h
 
 # Exclude bignum
 src:*/mfbt/double-conversion/source/bignum.cc
 
 # Exclude anything within gtests
 src:*/gtest/*
 
copy from build/sanitizers/ubsan_blacklist_int.txt
copy to build/sanitizers/ubsan_unsigned_overflow_blacklist.txt
--- a/build/sanitizers/ubsan_blacklist_int.txt
+++ b/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt
@@ -1,25 +1,45 @@
 # This file contains an extensive compile-time blacklist for silencing highly
-# frequent signed and unsigned integer overflows in our codebase, found by the
-# use of -fsanitize=integer. All of the overflows that caused an entry in this
-# list are highly frequent in our test suites (> 500 times per run) and therefore
-# unlikely to be bugs. Nevertheless, the slow down this test mode significantly
-# if left active. Without this list, the -fsanitize=integer test mode is unusable
-# both because of performance and the large number of results to check.
+# frequent *un*signed integer overflows in our codebase, found by the use of
+# -fsanitize=unsigned-integer-overflow.  Such overflows are not necessarily
+# bugs -- unsigned integer overflow has well-defined semantics in C/C++.  But
+# overflow may still be *unexpected* and incorrectly handled, so we try to
+# annotate those places where unsigned overflow is correct and desired.
+#
+# The rules in this file are applied at compile time; changes to this list
+# usually require a full rebuild to apply. If you can modify the source in
+# question to exempt individual functions using MOZ_NO_SANITIZE_UINT_OVERFLOW,
+# do that instead.
+#
+# The extensive number of entries below is for two reasons.
 #
-# Some of the entries on this list are more aggressive to get the build into a
-# state that allows any testing to happen at all. This is not an optimal solution
-# and it would be good if we could refine the tool and shorten this list over
-# the time. Source code annotations can also help with this.
+# First, compiler instrumentation for unsigned integer overflows has a cost, at
+# compile time and at runtime.  In places where code expects and depends upon
+# overflow behavior -- and especially in performance-critical code -- it makes
+# sense to turn off overflow detection to avoid both costs.  (Indeed,
+# -fsanitize=signed-integer-overflow is unusably slow without this.)
+#
+# Second, many entries here are overly aggressive to get the build into a state
+# that allows any testing to happen at all.  Some of the entries here are for
+# issues that are highly frequent in our test suites -- over 500 times per run.
+# Aggressive entries now let us start using this mode, without having to first
+# fix wide swaths of existing code.
 #
-# The rules in this file are only applied at compile time. If you can modify the
-# source in question, consider function attributes to disable instrumentation.
+# Entries should be removed 1) as issues are fixed; and 2) as blacklist entries
+# can be moved out of this centralized file, into source-level blacklist
+# attributes on individual functions.
 
-# Ignore common overflows in the C++ std headers
+# All entries in this file are to suppress unsigned-integer-overflow problems.
+# Blacklists for other reasons should go in separate blacklist files.
+[unsigned-integer-overflow]
+
+# Overflows in the C++ std headers aren't necessarily bugs, because code inside
+# a language implementation can depend on compiler-specific behavior where C/C++
+# leave the behavior undefined.
 src:*bits/basic_string.h
 
 # Assume everything running through CheckedInt.h is ok. The CheckedInt class
 # casts signed integers to unsigned first and then does a post-overflow
 # check causing lots of unsigned integer overflow messages.
 src:*/CheckedInt.h
 
 # Exclude bignum
new file mode 100644
--- /dev/null
+++ b/build/sparse-profiles/update-verify
@@ -0,0 +1,5 @@
+%include build/sparse-profiles/mach
+
+[include]
+path:build/mozrelease
+path:testing/mozharness
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -1010,19 +1010,16 @@ MarkupView.prototype = {
 
       let container = this.getContainer(target);
       if (!container) {
         // Container might not exist if this came from a load event for a node
         // we're not viewing.
         continue;
       }
 
-      if (type === "attributes" && mutation.attributeName === "class") {
-        container.updateIsDisplayed();
-      }
       if (type === "attributes" || type === "characterData"
         || type === "events" || type === "pseudoClassLock") {
         container.update();
       } else if (type === "childList" || type === "nativeAnonymousChildList") {
         container.childrenDirty = true;
         // Update the children to take care of changes in the markup view DOM
         // and update container (and its subtree) DOM tree depth level for
         // accessibility where necessary.
@@ -1057,17 +1054,17 @@ MarkupView.prototype = {
    *
    * @param  {Array} nodes
    *         An array of nodeFronts
    */
   _onDisplayChange: function (nodes) {
     for (let node of nodes) {
       let container = this.getContainer(node);
       if (container) {
-        container.updateIsDisplayed();
+        container.update();
       }
     }
   },
 
   /**
    * Given a list of mutations returned by the mutation observer, flash the
    * corresponding containers to attract attention.
    */
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -90,16 +90,18 @@ skip-if = e10s # scratchpad.xul is not l
 skip-if = stylo # Stylo doesn't support shadow DOM yet, bug 1293844
 [browser_markup_anonymous_04.js]
 [browser_markup_copy_image_data.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_markup_css_completion_style_attribute_01.js]
 [browser_markup_css_completion_style_attribute_02.js]
 [browser_markup_css_completion_style_attribute_03.js]
+[browser_markup_display_node_01.js]
+[browser_markup_display_node_02.js]
 [browser_markup_dragdrop_autoscroll_01.js]
 [browser_markup_dragdrop_autoscroll_02.js]
 [browser_markup_dragdrop_distance.js]
 [browser_markup_dragdrop_draggable.js]
 [browser_markup_dragdrop_dragRootNode.js]
 [browser_markup_dragdrop_escapeKeyPress.js]
 [browser_markup_dragdrop_invalidNodes.js]
 [browser_markup_dragdrop_reorder.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_display_node_01.js
@@ -0,0 +1,58 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that markup display node shows for only for grid and flex containers.
+
+const TEST_URI = `
+  <style type="text/css">
+    #grid {
+      display: grid;
+    }
+    #flex {
+      display: flex;
+    }
+    #block {
+      display: block;
+    }
+  </style>
+  <div id="grid">Grid</div>
+  <div id="flex">Flex</div>
+  <div id="block">Block</div>
+  <span>HELLO WORLD</span>
+`;
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL("data:text/html;charset=utf-8," +
+    encodeURIComponent(TEST_URI));
+
+  info("Check the display node is shown and the value of #grid.");
+  yield selectNode("#grid", inspector);
+  let gridContainer = yield getContainerForSelector("#grid", inspector);
+  let gridDisplayNode = gridContainer.elt.querySelector(".markupview-display");
+  is(gridDisplayNode.textContent, "grid", "Got the correct display type for #grid.");
+  is(gridDisplayNode.style.display, "inline-block", "#grid display node is shown.");
+
+  info("Check the display node is shown and the value of #flex.");
+  yield selectNode("#flex", inspector);
+  let flexContainer = yield getContainerForSelector("#flex", inspector);
+  let flexDisplayNode = flexContainer.elt.querySelector(".markupview-display");
+  is(flexDisplayNode.textContent, "flex", "Got the correct display type for #flex");
+  is(flexDisplayNode.style.display, "inline-block", "#flex display node is shown.");
+
+  info("Check the display node is shown and the value of #block.");
+  yield selectNode("#block", inspector);
+  let blockContainer = yield getContainerForSelector("#block", inspector);
+  let blockDisplayNode = blockContainer.elt.querySelector(".markupview-display");
+  is(blockDisplayNode.textContent, "block", "Got the correct display type for #block");
+  is(blockDisplayNode.style.display, "none", "#block display node is hidden.");
+
+  info("Check the display node is shown and the value of span.");
+  yield selectNode("span", inspector);
+  let spanContainer = yield getContainerForSelector("span", inspector);
+  let spanDisplayNode = spanContainer.elt.querySelector(".markupview-display");
+  is(spanDisplayNode.textContent, "inline", "Got the correct display type for #span");
+  is(spanDisplayNode.style.display, "none", "span display node is hidden.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_display_node_02.js
@@ -0,0 +1,129 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that markup display node are updated when their display changes.
+
+const TEST_URI = `
+  <style type="text/css">
+    #grid {
+      display: grid;
+    }
+    #flex {
+      display: flex;
+    }
+    #flex[hidden] {
+      display: none;
+    }
+    #block {
+      display: block;
+    }
+    #flex
+  </style>
+  <div id="grid">Grid</div>
+  <div id="flex" hidden="">Flex</div>
+  <div id="block">Block</div>
+`;
+
+const TEST_DATA = [
+  {
+    desc: "Hiding the #grid display node by changing its style property",
+    selector: "#grid",
+    before: {
+      textContent: "grid",
+      display: "inline-block"
+    },
+    changeStyle: function* (testActor) {
+      yield testActor.eval(`
+        let node = document.getElementById("grid");
+        node.style.display = "block";
+      `);
+    },
+    after: {
+      textContent: "block",
+      display: "none"
+    }
+  },
+  {
+    desc: "Showing a 'grid' node by changing its style property",
+    selector: "#block",
+    before: {
+      textContent: "block",
+      display: "none"
+    },
+    changeStyle: function* (testActor) {
+      yield testActor.eval(`
+        let node = document.getElementById("block");
+        node.style.display = "grid";
+      `);
+    },
+    after: {
+      textContent: "grid",
+      display: "inline-block"
+    }
+  },
+  {
+    desc: "Showing a 'flex' node by removing its hidden attribute",
+    selector: "#flex",
+    before: {
+      textContent: "none",
+      display: "none"
+    },
+    changeStyle: function* (testActor) {
+      yield testActor.eval(`
+        document.getElementById("flex").removeAttribute("hidden");
+      `);
+    },
+    after: {
+      textContent: "flex",
+      display: "inline-block"
+    }
+  }
+];
+
+add_task(function* () {
+  let {inspector, testActor} = yield openInspectorForURL("data:text/html;charset=utf-8," +
+    encodeURIComponent(TEST_URI));
+
+  for (let data of TEST_DATA) {
+    info("Running test case: " + data.desc);
+    yield runTestData(inspector, testActor, data);
+  }
+});
+
+function* runTestData(inspector, testActor,
+                      {selector, before, changeStyle, after}) {
+  yield selectNode(selector, inspector);
+  let container = yield getContainerForSelector(selector, inspector);
+  let displayNode = container.elt.querySelector(".markupview-display");
+
+  is(displayNode.textContent, before.textContent,
+    `Got the correct before display type for ${selector}: ${displayNode.textContent}`);
+  is(displayNode.style.display, before.display,
+    `Got the correct before display style for ${selector}: ${displayNode.style.display}`);
+
+  info("Listening for the display-change event");
+  let onDisplayChanged = inspector.markup.walker.once("display-change");
+  info("Making style changes");
+  yield changeStyle(testActor);
+  let nodes = yield onDisplayChanged;
+
+  info("Verifying that the list of changed nodes include our container");
+  ok(nodes.length, "The display-change event was received with a nodes");
+  let foundContainer = false;
+  for (let node of nodes) {
+    if (getContainerForNodeFront(node, inspector) === container) {
+      foundContainer = true;
+      break;
+    }
+  }
+  ok(foundContainer, "Container is part of the list of changed nodes");
+
+  is(displayNode.textContent, after.textContent,
+    `Got the correct after display type for ${selector}: ${displayNode.textContent}`);
+  is(displayNode.style.display, after.display,
+    `Got the correct after display style for ${selector}: ${displayNode.style.display}`);
+}
+
--- a/devtools/client/inspector/markup/views/element-editor.js
+++ b/devtools/client/inspector/markup/views/element-editor.js
@@ -14,30 +14,42 @@ const {
   truncateString,
 } = require("devtools/client/inspector/markup/utils");
 const {editableField, InplaceEditor} =
       require("devtools/client/shared/inplace-editor");
 const {parseAttribute} =
       require("devtools/client/shared/node-attribute-parser");
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
 
+// Global tooltip inspector
+const {LocalizationHelper} = require("devtools/shared/l10n");
+const INSPECTOR_L10N =
+  new LocalizationHelper("devtools/client/locales/inspector.properties");
+
 // Page size for pageup/pagedown
 const COLLAPSE_DATA_URL_REGEX = /^data.+base64/;
 const COLLAPSE_DATA_URL_LENGTH = 60;
 
 // Contains only void (without end tag) HTML elements
 const HTML_VOID_ELEMENTS = [
   "area", "base", "br", "col", "command", "embed",
   "hr", "img", "input", "keygen", "link", "meta", "param", "source",
-  "track", "wbr" ];
+  "track", "wbr"
+];
 
-// Global tooltip inspector
-const {LocalizationHelper} = require("devtools/shared/l10n");
-const INSPECTOR_L10N =
-  new LocalizationHelper("devtools/client/locales/inspector.properties");
+// Contains only valid computed display property types of the node to display in the
+// element markup and their respective title tooltip text.
+const DISPLAY_TYPES = {
+  "flex": INSPECTOR_L10N.getStr("markupView.display.flex.tooltiptext"),
+  "inline-flex": INSPECTOR_L10N.getStr("markupView.display.flex.tooltiptext"),
+  "grid": INSPECTOR_L10N.getStr("markupView.display.grid.tooltiptext"),
+  "inline-grid": INSPECTOR_L10N.getStr("markupView.display.inlineGrid.tooltiptext"),
+  "flow-root": INSPECTOR_L10N.getStr("markupView.display.flowRoot.tooltiptext"),
+  "contents": INSPECTOR_L10N.getStr("markupView.display.contents.tooltiptext"),
+};
 
 /**
  * Creates an editor for an Element node.
  *
  * @param  {MarkupContainer} container
  *         The container owning this editor.
  * @param  {Element} node
  *         The node being edited.
@@ -157,16 +169,20 @@ ElementEditor.prototype = {
     close.appendChild(this.doc.createTextNode(">"));
 
     this.eventNode = this.doc.createElement("div");
     this.eventNode.classList.add("markupview-events");
     this.eventNode.dataset.event = "true";
     this.eventNode.textContent = "ev";
     this.eventNode.title = INSPECTOR_L10N.getStr("markupView.event.tooltiptext");
     this.elt.appendChild(this.eventNode);
+
+    this.displayNode = this.doc.createElement("div");
+    this.displayNode.classList.add("markupview-display");
+    this.elt.appendChild(this.displayNode);
   },
 
   set selected(value) {
     if (this.textEditor) {
       this.textEditor.selected = value;
     }
   },
 
@@ -248,18 +264,24 @@ ElementEditor.prototype = {
         // been created.
         if (this.initialized) {
           this.flashAttribute(attr.name);
         }
       }
     }
 
     // Update the event bubble display
-    this.eventNode.style.display = this.node.hasEventListeners ?
-      "inline-block" : "none";
+    this.eventNode.style.display = this.node.hasEventListeners ? "inline-block" : "none";
+
+    // Update the display type node
+    let showDisplayNode = this.node.displayType in DISPLAY_TYPES;
+    this.displayNode.textContent = this.node.displayType;
+    this.displayNode.dataset.display = showDisplayNode ? this.node.displayType : "";
+    this.displayNode.style.display = showDisplayNode ? "inline-block" : "none";
+    this.displayNode.title = showDisplayNode ? DISPLAY_TYPES[this.node.displayType] : "";
 
     this.updateTextEditor();
   },
 
   /**
    * Update the inline text editor in case of a single text child node.
    */
   updateTextEditor: function () {
--- a/devtools/client/inspector/markup/views/markup-container.js
+++ b/devtools/client/inspector/markup/views/markup-container.js
@@ -713,16 +713,18 @@ MarkupContainer.prototype = {
    */
   update: function () {
     if (this.node.pseudoClassLocks.length) {
       this.elt.classList.add("pseudoclass-locked");
     } else {
       this.elt.classList.remove("pseudoclass-locked");
     }
 
+    this.updateIsDisplayed();
+
     if (this.editor.update) {
       this.editor.update();
     }
   },
 
   /**
    * Try to put keyboard focus on the current editor.
    */
@@ -730,18 +732,19 @@ MarkupContainer.prototype = {
     // Elements with tabindex of -1 are not focusable.
     let focusable = this.editor.elt.querySelector("[tabindex='0']");
     if (focusable) {
       focusable.focus();
     }
   },
 
   _onToggle: function (event) {
-    // Prevent the html tree from expanding when an event bubble is clicked.
-    if (event.target.dataset.event) {
+    // Prevent the html tree from expanding when an event bubble or display node is
+    // clicked.
+    if (event.target.dataset.event || event.target.dataset.display) {
       event.stopPropagation();
       return;
     }
 
     this.markup.navigate(this);
     if (this.hasChildren) {
       this.markup.setNodeExpanded(this.node, !this.expanded, event.altKey);
     }
--- a/devtools/client/locales/en-US/inspector.properties
+++ b/devtools/client/locales/en-US/inspector.properties
@@ -33,19 +33,49 @@ markupView.more.showing=Some nodes were 
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 markupView.more.showAll2=Show one more node;Show all #1 nodes
 
 # LOCALIZATION NOTE (markupView.whitespaceOnly)
 # Used in a tooltip that appears when the user hovers over whitespace-only text nodes in
 # the inspector.
 markupView.whitespaceOnly=Whitespace-only text node: %S
 
+# LOCALIZATION NOTE (markupView.display.flex.tooltiptext)
+# Used in a tooltip that appears when the user hovers over the display type button in
+# the markup view.
+markupView.display.flex.tooltiptext=This element behaves like a block element and lays out its content according to the flexbox model.
+
+# LOCALIZATION NOTE (markupView.display.inlineFlex.tooltiptext)
+# Used in a tooltip that appears when the user hovers over the display type button in
+# the markup view.
+markupView.display.inlineFlex.tooltiptext=This element behaves like an inline element and lays out its content according to the flexbox model.
+
+# LOCALIZATION NOTE (markupView.display.grid.tooltiptext)
+# Used in a tooltip that appears when the user hovers over the display type button in
+# the markup view.
+markupView.display.grid.tooltiptext=This element behaves like a block element and lays out its content according to the grid model.
+
+# LOCALIZATION NOTE (markupView.display.flex.tooltiptext)
+# Used in a tooltip that appears when the user hovers over the display type button in
+# the markup view.
+markupView.display.inlineGrid.tooltiptext=This element behaves like an inline element and lays out its content according to the grid model.
+
+# LOCALIZATION NOTE (markupView.display.flowRoot.tooltiptext)
+# Used in a tooltip that appears when the user hovers over the display type button in
+# the markup view.
+markupView.display.flowRoot.tooltiptext=This element generates a block element box that establishes a new block formatting context.
+
+# LOCALIZATION NOTE (markupView.display.contents.tooltiptext)
+# Used in a tooltip that appears when the user hovers over the display type button in
+# the markup view.
+markupView.display.contents.tooltiptext=This element doesn’t produce a specific box by themselves, but renders its contents.
+
 # LOCALIZATION NOTE (markupView.event.tooltiptext)
 # Used in a tooltip that appears when the user hovers over 'ev' button in
-# the inspector.
+# the markup view.
 markupView.event.tooltiptext=Event listener
 
 #LOCALIZATION NOTE: Used in the image preview tooltip when the image could not be loaded
 previewTooltip.image.brokenImage=Could not load the image
 
 # LOCALIZATION NOTE: Used in color picker tooltip when the eyedropper is disabled for
 # non-HTML documents
 eyedropper.disabled.title=Unavailable in non-HTML documents
--- a/devtools/client/themes/markup.css
+++ b/devtools/client/themes/markup.css
@@ -258,21 +258,16 @@ ul.children + .tag-line::before {
 .newattr:focus {
   margin-right: 0;
 }
 
 .flash-out {
   transition: background .5s;
 }
 
-.markupview-events {
-  display: none;
-  cursor: pointer;
-}
-
 .editor {
   /* Make sure the editor still appears above the tag-state */
   position: relative;
   z-index: 1;
 }
 
 .editor.comment:not(.doctype) {
   color: var(--theme-highlight-green);
@@ -368,16 +363,17 @@ ul.children + .tag-line::before {
 .theme-firebug .attr-name.theme-fg-color2 {
   color: var(--theme-highlight-purple);
 }
 
 .theme-firebug .attr-value.theme-fg-color6 {
   color: var(--theme-highlight-red);
 }
 
+.theme-firebug .markupview-display,
 .theme-firebug .markupview-events {
   font-size: var(--theme-toolbar-font-size);
 }
 
 /* In case a node isn't displayed in the page, we fade the syntax highlighting */
 .theme-firebug .not-displayed .open,
 .theme-firebug .not-displayed .close {
   opacity: .5;
@@ -409,23 +405,26 @@ ul.children + .tag-line::before {
 .doctype {
   font-style: italic;
 }
 
 .theme-firebug .doctype {
   color: #787878;
 }
 
-/* Events */
+/* Display and Events Bubble */
+.markupview-display,
 .markupview-events {
+  display: none;
   font-size: 8px;
   font-weight: bold;
   line-height: 10px;
   border-radius: 3px;
   padding: 0px 2px;
   margin-inline-start: 5px;
   -moz-user-select: none;
+  background-color: var(--theme-body-color-alt);
+  color: var(--theme-body-background);
 }
 
 .markupview-events {
-  background-color: var(--theme-body-color-alt);
-  color: var(--theme-body-background);
+  cursor: pointer;
 }
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -363,16 +363,17 @@
   height: 11px;
 }
 
 .ruleview-ruleopen {
   padding-inline-end: 5px;
 }
 
 .ruleview-ruleclose {
+  clear: both;
   cursor: text;
   padding-right: 20px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
@@ -552,17 +553,17 @@
 
 .theme-firebug .styleinspector-propertyeditor {
   border: 1px solid var(--theme-splitter-color);
   box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
 }
 
 .ruleview-property {
   border-left: 3px solid transparent;
-  clear: right;
+  clear: both;
   padding-left: 28px;
 }
 
 .ruleview-propertycontainer  > * {
   vertical-align: middle;
 }
 
 .ruleview-property[dirty] {
--- a/devtools/server/actors/inspector/node-actor.js
+++ b/devtools/server/actors/inspector/node-actor.js
@@ -39,18 +39,19 @@ const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20
  */
 const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
   initialize: function (walker, node) {
     protocol.Actor.prototype.initialize.call(this, null);
     this.walker = walker;
     this.rawNode = node;
     this._eventParsers = new EventParsers().parsers;
 
-    // Storing the original display of the node, to track changes when reflows
-    // occur
+    // Store the original display type and whether or not the node is displayed to
+    // track changes when reflows occur.
+    this.currentDisplayType = this.displayType;
     this.wasDisplayed = this.isDisplayed;
   },
 
   toString: function () {
     return "[NodeActor " + this.actorID + " for " +
       this.rawNode.toString() + "]";
   },
 
@@ -95,16 +96,17 @@ const NodeActor = protocol.ActorClassWit
       parent: parentNode ? parentNode.actorID : undefined,
       nodeType: this.rawNode.nodeType,
       namespaceURI: this.rawNode.namespaceURI,
       nodeName: this.rawNode.nodeName,
       nodeValue: this.rawNode.nodeValue,
       displayName: InspectorActorUtils.getNodeDisplayName(this.rawNode),
       numChildren: this.numChildren,
       inlineTextChild: inlineTextChild ? inlineTextChild.form() : undefined,
+      displayType: this.displayType,
 
       // doctype attributes
       name: this.rawNode.name,
       publicId: this.rawNode.publicId,
       systemId: this.rawNode.systemId,
 
       attrs: this.writeAttrs(),
       isBeforePseudoElement: this.isBeforePseudoElement,
@@ -199,28 +201,49 @@ const NodeActor = protocol.ActorClassWit
     if (numChildren === 0 || hasAnonChildren) {
       numChildren = this.walker.children(this).nodes.length;
     }
 
     return numChildren;
   },
 
   get computedStyle() {
-    return CssLogic.getComputedStyle(this.rawNode);
+    if (!this._computedStyle) {
+      this._computedStyle = CssLogic.getComputedStyle(this.rawNode);
+    }
+    return this._computedStyle;
+  },
+
+  /**
+   * Returns the computed display style property value of the node.
+   */
+  get displayType() {
+    // Consider all non-element nodes as displayed.
+    if (InspectorActorUtils.isNodeDead(this) ||
+        this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE ||
+        this.isAfterPseudoElement ||
+        this.isBeforePseudoElement) {
+      return null;
+    }
+
+    let style = this.computedStyle;
+    if (!style) {
+      return null;
+    }
+
+    return style.display;
   },
 
   /**
    * Is the node's display computed style value other than "none"
    */
   get isDisplayed() {
     // Consider all non-element nodes as displayed.
     if (InspectorActorUtils.isNodeDead(this) ||
-        this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE ||
-        this.isAfterPseudoElement ||
-        this.isBeforePseudoElement) {
+        this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
       return true;
     }
 
     let style = this.computedStyle;
     if (!style) {
       return true;
     }
 
--- a/devtools/server/actors/inspector/walker-actor.js
+++ b/devtools/server/actors/inspector/walker-actor.js
@@ -306,20 +306,25 @@ var WalkerActor = protocol.ActorClassWit
     // Going through the nodes the walker knows about, see which ones have
     // had their display changed and send a display-change event if any
     let changes = [];
     for (let [node, actor] of this._refMap) {
       if (Cu.isDeadWrapper(node)) {
         continue;
       }
 
+      let displayType = actor.displayType;
       let isDisplayed = actor.isDisplayed;
-      if (isDisplayed !== actor.wasDisplayed) {
+
+      if (displayType !== actor.currentDisplayType ||
+          isDisplayed !== actor.wasDisplayed) {
         changes.push(actor);
+
         // Updating the original value
+        actor.currentDisplayType = displayType;
         actor.wasDisplayed = isDisplayed;
       }
     }
 
     if (changes.length) {
       this.emit("display-change", changes);
     }
   },
--- a/devtools/server/tests/mochitest/chrome.ini
+++ b/devtools/server/tests/mochitest/chrome.ini
@@ -6,16 +6,17 @@ support-files =
   doc_Debugger.Source.prototype.introductionType.xul
   Debugger.Source.prototype.element.js
   Debugger.Source.prototype.element-2.js
   Debugger.Source.prototype.element.html
   hello-actor.js
   iframe1_makeGlobalObjectReference.html
   iframe2_makeGlobalObjectReference.html
   inspector_css-properties.html
+  inspector_display-type.html
   inspector_getImageData.html
   inspector_getOffsetParent.html
   inspector-delay-image-response.sjs
   inspector-eyedropper.html
   inspector-helpers.js
   inspector-search-data.html
   inspector-styles-data.css
   inspector-styles-data.html
@@ -48,16 +49,17 @@ support-files =
 [test_framerate_05.html]
 [test_framerate_06.html]
 [test_getProcess.html]
 [test_highlighter_paused_debugger.html]
 [test_inspector-anonymous.html]
 [test_inspector-changeattrs.html]
 [test_inspector-changevalue.html]
 [test_inspector-dead-nodes.html]
+[test_inspector-display-type.html]
 [test_inspector-duplicate-node.html]
 [test_inspector_getImageData.html]
 [test_inspector_getImageDataFromURL.html]
 [test_inspector_getImageData-wait-for-load.html]
 [test_inspector_getNodeFromActor.html]
 [test_inspector_getOffsetParent.html]
 [test_inspector-hide.html]
 [test_inspector-insert.html]
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/inspector_display-type.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<body>
+    <div id="inline-block" style="display: inline-block">
+      HELLO WORLD
+    </div>
+    <div id="grid" style="display: grid"></div>
+    <div id="block" style="position: fixed"></div>
+    <script>
+       "use strict";
+
+       window.onload = () => {
+         window.opener.postMessage("ready", "*");
+       };
+     </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/test_inspector-display-type.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1431900
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1431900</title>
+
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  <script type="application/javascript" src="inspector-helpers.js"></script>
+  <script type="application/javascript">
+"use strict";
+
+window.onload = function () {
+  SimpleTest.waitForExplicitFinish();
+  runNextTest();
+};
+
+var gWalker;
+
+addTest(function setup() {
+  let url = document.getElementById("inspectorContent").href;
+  attachURL(url, function (err, client, tab, doc) {
+    let {InspectorFront} = require("devtools/shared/fronts/inspector");
+    let inspector = InspectorFront(client, tab);
+
+    promiseDone(inspector.getWalker().then(walker => {
+      gWalker = walker;
+    }).then(runNextTest));
+  });
+});
+
+addAsyncTest(function* testInlineBlockDisplayType() {
+  info("Test getting the display type of an inline block element.");
+  let node = yield gWalker.querySelector(gWalker.rootNode, "#inline-block");
+  let displayType = node.displayType;
+  is(displayType, "inline-block", "The node has a display type of 'inline-block'.");
+  runNextTest();
+});
+
+addAsyncTest(function* testInlineTextChildDisplayType() {
+  info("Test getting the display type of an inline text child.");
+  let node = yield gWalker.querySelector(gWalker.rootNode, "#inline-block");
+  let children = yield gWalker.children(node);
+  let inlineTextChild = children.nodes[0];
+  let displayType = inlineTextChild.displayType;
+  ok(!displayType, "No display type for inline text child.");
+  runNextTest();
+});
+
+addAsyncTest(function* testGridDisplayType() {
+  info("Test getting the display type of an grid container.");
+  let node = yield gWalker.querySelector(gWalker.rootNode, "#grid");
+  let displayType = node.displayType;
+  is(displayType, "grid", "The node has a display type of 'grid'.");
+  runNextTest();
+});
+
+addAsyncTest(function* testBlockDisplayType() {
+  info("Test getting the display type of a block element.");
+  let node = yield gWalker.querySelector(gWalker.rootNode, "#block");
+  let displayType = yield node.displayType;
+  is(displayType, "block", "The node has a display type of 'block'.");
+  runNextTest();
+});
+
+addTest(function () {
+  gWalker = null;
+  runNextTest();
+});
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1431900">Mozilla Bug 1431900</a>
+<a id="inspectorContent" target="_blank" href="inspector_display-type.html">Test Document</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/devtools/shared/fronts/node.js
+++ b/devtools/shared/fronts/node.js
@@ -326,16 +326,20 @@ const NodeFront = FrontClassWithSpec(nod
 
   get pseudoClassLocks() {
     return this._form.pseudoClassLocks || [];
   },
   hasPseudoClassLock: function (pseudo) {
     return this.pseudoClassLocks.some(locked => locked === pseudo);
   },
 
+  get displayType() {
+    return this._form.displayType;
+  },
+
   get isDisplayed() {
     // The NodeActor's form contains the isDisplayed information as a boolean
     // starting from FF32. Before that, the property is missing
     return "isDisplayed" in this._form ? this._form.isDisplayed : true;
   },
 
   get isTreeDisplayed() {
     let parent = this;
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -693,17 +693,17 @@ nsPlainTextSerializer::DoOpenContainer(n
       else {
         mInIndentString.Append(char16_t('#'));
       }
 
       mInIndentString.Append(char16_t('.'));
 
     }
     else {
-      static char bulletCharArray[] = "*o+#";
+      static const char bulletCharArray[] = "*o+#";
       uint32_t index = mULCount > 0 ? (mULCount - 1) : 3;
       char bulletChar = bulletCharArray[index % 4];
       mInIndentString.Append(char16_t(bulletChar));
     }
 
     mInIndentString.Append(char16_t(' '));
   }
   else if (aTag == nsGkAtoms::dl) {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -139,21 +139,16 @@ DOMInterfaces = {
     'nativeType': 'mozilla::extensions::ChannelWrapper',
 },
 
 'CharacterData': {
     'nativeType': 'nsGenericDOMDataNode',
     'concrete': False
 },
 
-'ChromeWorker': {
-    'headerFile': 'mozilla/dom/WorkerPrivate.h',
-    'nativeType': 'mozilla::dom::ChromeWorkerPrivate',
-},
-
 'console': {
     'nativeType': 'mozilla::dom::Console',
 },
 
 'ConsoleInstance': {
     'implicitJSContext': ['clear', 'count', 'groupEnd', 'time', 'timeEnd'],
 },
 
@@ -1346,21 +1341,16 @@ DOMInterfaces = {
     'headerFile': 'nsPIDOMWindow.h',
     'concrete': False
 },
 
 'WindowRoot': {
     'nativeType': 'nsWindowRoot'
 },
 
-'Worker': {
-    'headerFile': 'mozilla/dom/WorkerPrivate.h',
-    'nativeType': 'mozilla::dom::WorkerPrivate',
-},
-
 'WorkerDebuggerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'implicitJSContext': [
         'dump', 'global', 'reportError', 'setConsoleEventHandler',
     ],
 },
 
 'WorkerGlobalScope': {
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1382,30 +1382,31 @@ nsTextEditorState::PrepareEditor(const n
 
   if (!mEditorInitialized) {
     // Now initialize the editor.
     //
     // NOTE: Conversion of '\n' to <BR> happens inside the
     //       editor's Init() call.
 
     // Get the DOM document
-    nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(shell->GetDocument());
-    if (!domdoc)
+    nsCOMPtr<nsIDocument> doc = shell->GetDocument();
+    if (NS_WARN_IF(!doc)) {
       return NS_ERROR_FAILURE;
+    }
 
     // What follows is a bit of a hack.  The editor uses the public DOM APIs
     // for its content manipulations, and it causes it to fail some security
     // checks deep inside when initializing. So we explictly make it clear that
     // we're native code.
     // Note that any script that's directly trying to access our value
     // has to be going through some scriptable object to do that and that
     // already does the relevant security checks.
     AutoNoJSAPI nojsapi;
 
-    rv = newTextEditor->Init(domdoc, GetRootNode(), mSelCon, editorFlags,
+    rv = newTextEditor->Init(*doc, GetRootNode(), mSelCon, editorFlags,
                              defaultValue);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Initialize the controller for the editor
 
   if (!SuppressEventHandlers(presContext)) {
     nsCOMPtr<nsIControllers> controllers;
--- a/dom/plugins/ipc/FunctionBroker.h
+++ b/dom/plugins/ipc/FunctionBroker.h
@@ -1259,28 +1259,34 @@ protected:
     return BrokerCallServer(aClientId, aInTuple, aOutTuple,
                              typename IndexSequenceFor<ParamTypes...>::Type());
   }
 
   bool BrokerCallClient(uint32_t& aWinError, ResultType& aResult, ParamTypes&... aParameters) const;
   bool PostToDispatchThread(uint32_t& aWinError, ResultType& aRet, ParamTypes&... aParameters) const;
 
   static void
-  PostToDispatchHelper(const SelfType* bmhi, Monitor* monitor, bool* ok, uint32_t* winErr, ResultType* r, ParamTypes*... p)
+  PostToDispatchHelper(const SelfType* bmhi, Monitor* monitor, bool* notified,
+                       bool* ok, uint32_t* winErr, ResultType* r, ParamTypes*... p)
   {
     // Note: p is also non-null... its just hard to assert that.
-    MOZ_ASSERT(bmhi && monitor && ok && winErr && r);
+    MOZ_ASSERT(bmhi && monitor && notified && ok && winErr && r);
+    MOZ_ASSERT(*notified == false);
     *ok = bmhi->BrokerCallClient(*winErr, *r, *p...);
-    {
-      // By grabbing (and freeing) the lock, we make sure that Wait() has been
-      // called in PostToDispatchThread.  We need that since we wake it with
-      // Notify().
-      MonitorAutoLock lock(*monitor);
-    }
-    *ok &= NS_SUCCEEDED(monitor->Notify());
+
+    // We need to grab the lock to make sure that Wait() has been
+    // called in PostToDispatchThread.  We need that since we wake it with
+    // Notify().
+    // We also need to keep the lock until _after_ Notify() has been called
+    // since, after we set notified to true, a spurious wakeup could lead
+    // the other thread to wake and proceed -- and one of its first acts would
+    // be to destroy the Monitor.
+    MonitorAutoLock lock(*monitor);
+    *notified = true;
+    monitor->Notify();
   };
 
   template<typename ... VarParams>
   ResultType
   RunFunction(FunctionType* aFunction, base::ProcessId aClientId,
                 VarParams&... aParams) const
   {
     return aFunction(aParams...);
@@ -1441,21 +1447,27 @@ PostToDispatchThread(uint32_t& aWinError
   HOOK_LOG(LogLevel::Debug,
            ("Posting broker task '%s' to dispatch thread", FunctionHookInfoType::mFunctionName.Data()));
 
   // Run PostToDispatchHelper on the dispatch thread.  It will notify our
   // waiting monitor when it is done.
   Monitor monitor("FunctionDispatchThread Lock");
   MonitorAutoLock lock(monitor);
   bool success = false;
+  bool notified = false;
   FunctionBrokerChild::GetInstance()->PostToDispatchThread(
     NewRunnableFunction("FunctionDispatchThreadRunnable", &PostToDispatchHelper,
-                        this, &monitor, &success, &aWinError, &aRet,
+                        this, &monitor, &notified, &success, &aWinError, &aRet,
                         &aParameters...));
-  monitor.Wait();
+
+  // We wait to be notified, testing that notified was actually set to make
+  // sure this isn't a spurious wakeup.
+  while (!notified) {
+    monitor.Wait();
+  }
   return success;
 }
 
 void AddBrokeredFunctionHooks(FunctionHookArray& aHooks);
 
 } // namespace plugins
 } // namespace mozilla
 
--- a/dom/webidl/Worker.webidl
+++ b/dom/webidl/Worker.webidl
@@ -1,15 +1,15 @@
 /* -*- 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/.
  *
  * The origin of this IDL file is
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html
+ * https://html.spec.whatwg.org/multipage/workers.html
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera
  * Software ASA.
  * You are granted a license to use, reproduce and create derivative works of
  * this document.
  */
 
 [Constructor(USVString scriptURL, optional WorkerOptions options),
@@ -28,12 +28,12 @@ Worker implements AbstractWorker;
 
 dictionary WorkerOptions {
   // WorkerType type = "classic"; TODO: Bug 1247687
   // RequestCredentials credentials = "omit"; // credentials is only used if type is "module" TODO: Bug 1247687
   DOMString name = "";
 };
 
 [Constructor(USVString scriptURL),
- Func="mozilla::dom::ChromeWorkerPrivate::WorkerAvailable",
+ Func="mozilla::dom::ChromeWorker::WorkerAvailable",
  Exposed=(Window,DedicatedWorker,SharedWorker,System)]
 interface ChromeWorker : Worker {
 };
new file mode 100644
--- /dev/null
+++ b/dom/workers/ChromeWorker.cpp
@@ -0,0 +1,78 @@
+/* -*- 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 "ChromeWorker.h"
+
+#include "mozilla/dom/WorkerBinding.h"
+#include "nsContentUtils.h"
+#include "WorkerPrivate.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ already_AddRefed<ChromeWorker>
+ChromeWorker::Constructor(const GlobalObject& aGlobal,
+                          const nsAString& aScriptURL,
+                          ErrorResult& aRv)
+{
+  JSContext* cx = aGlobal.Context();
+
+  RefPtr<WorkerPrivate> workerPrivate =
+    WorkerPrivate::Constructor(cx, aScriptURL, true /* aIsChromeWorker */,
+                               WorkerTypeDedicated, EmptyString(),
+                               VoidCString(), nullptr /*aLoadInfo */, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIGlobalObject> globalObject =
+    do_QueryInterface(aGlobal.GetAsSupports());
+
+  RefPtr<ChromeWorker> worker =
+    new ChromeWorker(globalObject, workerPrivate.forget());
+  return worker.forget();
+}
+
+/* static */ bool
+ChromeWorker::WorkerAvailable(JSContext* aCx, JSObject* /* unused */)
+{
+  // Chrome is always allowed to use workers, and content is never
+  // allowed to use ChromeWorker, so all we have to check is the
+  // caller.  However, chrome workers apparently might not have a
+  // system principal, so we have to check for them manually.
+  if (NS_IsMainThread()) {
+    return nsContentUtils::IsSystemCaller(aCx);
+  }
+
+  return GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
+}
+
+ChromeWorker::ChromeWorker(nsIGlobalObject* aGlobalObject,
+                           already_AddRefed<WorkerPrivate> aWorkerPrivate)
+  : Worker(aGlobalObject, Move(aWorkerPrivate))
+{}
+
+ChromeWorker::~ChromeWorker() = default;
+
+JSObject*
+ChromeWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  JS::Rooted<JSObject*> wrapper(aCx,
+    ChromeWorkerBinding::Wrap(aCx, this, aGivenProto));
+  if (wrapper) {
+    // Most DOM objects don't assume they have a reflector. If they don't have
+    // one and need one, they create it. But in workers code, we assume that the
+    // reflector is always present.  In order to guarantee that it's always
+    // present, we have to preserve it. Otherwise the GC will happily collect it
+    // as needed.
+    MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
+  }
+
+  return wrapper;
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/ChromeWorker.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ChromeWorker_h
+#define mozilla_dom_ChromeWorker_h
+
+#include "mozilla/dom/Worker.h"
+
+namespace mozilla {
+namespace dom {
+
+class ChromeWorker final : public Worker
+{
+public:
+  static already_AddRefed<ChromeWorker>
+  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
+              ErrorResult& aRv);
+
+  static bool
+  WorkerAvailable(JSContext* aCx, JSObject* /* unused */);
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+private:
+  ChromeWorker(nsIGlobalObject* aGlobalObject,
+               already_AddRefed<WorkerPrivate> aWorkerPrivate);
+  ~ChromeWorker();
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif /* mozilla_dom_ChromeWorker_h */
--- a/dom/workers/MessageEventRunnable.cpp
+++ b/dom/workers/MessageEventRunnable.cpp
@@ -121,17 +121,18 @@ MessageEventRunnable::WorkerRun(JSContex
         aWorkerPrivate->IsParentWindowPaused()) {
       MOZ_ASSERT(!IsDebuggerRunnable());
       aWorkerPrivate->QueueRunnable(this);
       return true;
     }
 
     aWorkerPrivate->AssertInnerWindowIsCorrect();
 
-    return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate,
+    return DispatchDOMEvent(aCx, aWorkerPrivate,
+                            aWorkerPrivate->ParentEventTargetRef(),
                             !aWorkerPrivate->GetParent());
   }
 
   MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
 
   return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
                           false);
 }
new file mode 100644
--- /dev/null
+++ b/dom/workers/Worker.cpp
@@ -0,0 +1,160 @@
+/* -*- 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 "Worker.h"
+
+#include "MessageEventRunnable.h"
+#include "mozilla/dom/WorkerBinding.h"
+#include "mozilla/TimelineConsumers.h"
+#include "mozilla/WorkerTimelineMarker.h"
+#include "nsContentUtils.h"
+#include "WorkerPrivate.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ already_AddRefed<Worker>
+Worker::Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
+                    const WorkerOptions& aOptions, ErrorResult& aRv)
+{
+  JSContext* cx = aGlobal.Context();
+
+  RefPtr<WorkerPrivate> workerPrivate =
+    WorkerPrivate::Constructor(cx, aScriptURL, false /* aIsChromeWorker */,
+                               WorkerTypeDedicated, aOptions.mName,
+                               VoidCString(), nullptr /*aLoadInfo */, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIGlobalObject> globalObject =
+    do_QueryInterface(aGlobal.GetAsSupports());
+
+  RefPtr<Worker> worker = new Worker(globalObject, workerPrivate.forget());
+  return worker.forget();
+}
+
+Worker::Worker(nsIGlobalObject* aGlobalObject,
+               already_AddRefed<WorkerPrivate> aWorkerPrivate)
+  : DOMEventTargetHelper(aGlobalObject)
+  , mWorkerPrivate(Move(aWorkerPrivate))
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->SetParentEventTargetRef(this);
+}
+
+Worker::~Worker()
+{
+  Terminate();
+}
+
+JSObject*
+Worker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  JS::Rooted<JSObject*> wrapper(aCx,
+    WorkerBinding::Wrap(aCx, this, aGivenProto));
+  if (wrapper) {
+    // Most DOM objects don't assume they have a reflector. If they don't have
+    // one and need one, they create it. But in workers code, we assume that the
+    // reflector is always present.  In order to guarantee that it's always
+    // present, we have to preserve it. Otherwise the GC will happily collect it
+    // as needed.
+    MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
+  }
+
+  return wrapper;
+}
+
+void
+Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+                    const Sequence<JSObject*>& aTransferable,
+                    ErrorResult& aRv)
+{
+  NS_ASSERT_OWNINGTHREAD(Worker);
+
+  if (!mWorkerPrivate ||
+      mWorkerPrivate->ParentStatusProtected() > Running) {
+    return;
+  }
+
+  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
+
+  aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
+                                                          &transferable);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  RefPtr<MessageEventRunnable> runnable =
+    new MessageEventRunnable(mWorkerPrivate,
+                             WorkerRunnable::WorkerThreadModifyBusyCount);
+
+  UniquePtr<AbstractTimelineMarker> start;
+  UniquePtr<AbstractTimelineMarker> end;
+  RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
+  bool isTimelineRecording = timelines && !timelines->IsEmpty();
+
+  if (isTimelineRecording) {
+    start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
+      ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
+      : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
+      MarkerTracingType::START);
+  }
+
+  runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv);
+
+  if (isTimelineRecording) {
+    end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
+      ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
+      : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
+      MarkerTracingType::END);
+    timelines->AddMarkerForAllObservedDocShells(start);
+    timelines->AddMarkerForAllObservedDocShells(end);
+  }
+
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  if (!runnable->Dispatch()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+}
+
+void
+Worker::Terminate()
+{
+  NS_ASSERT_OWNINGTHREAD(Worker);
+
+  if (mWorkerPrivate) {
+    mWorkerPrivate->Terminate();
+    mWorkerPrivate = nullptr;
+  }
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Worker)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
+  if (tmp->mWorkerPrivate) {
+    tmp->mWorkerPrivate->Traverse(cb);
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
+  tmp->Terminate();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(Worker, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(Worker, DOMEventTargetHelper)
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/workers/Worker.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_Worker_h
+#define mozilla_dom_Worker_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/WeakPtr.h"
+
+#ifdef XP_WIN
+#undef PostMessage
+#endif
+
+namespace mozilla {
+namespace dom {
+
+struct WorkerOptions;
+class WorkerPrivate;
+
+class Worker : public DOMEventTargetHelper
+             , public SupportsWeakPtr<Worker>
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Worker,
+                                                         DOMEventTargetHelper)
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Worker)
+
+  static already_AddRefed<Worker>
+  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
+              const WorkerOptions& aOptions, ErrorResult& aRv);
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  void
+  PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+              const Sequence<JSObject*>& aTransferable,
+              ErrorResult& aRv);
+
+  void
+  Terminate();
+
+  IMPL_EVENT_HANDLER(error)
+  IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(messageerror)
+
+protected:
+  Worker(nsIGlobalObject* aGlobalObject,
+         already_AddRefed<WorkerPrivate> aWorkerPrivate);
+  ~Worker();
+
+  RefPtr<WorkerPrivate> mWorkerPrivate;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif /* mozilla_dom_Worker_h */
--- a/dom/workers/WorkerError.cpp
+++ b/dom/workers/WorkerError.cpp
@@ -30,17 +30,17 @@ class ReportErrorRunnable final : public
   WorkerErrorReport mReport;
 
 public:
   // aWorkerPrivate is the worker thread we're on (or the main thread, if null)
   // aTarget is the worker object that we are going to fire an error at
   // (if any).
   static void
   ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-              bool aFireAtScope, WorkerPrivate* aTarget,
+              bool aFireAtScope, DOMEventTargetHelper* aTarget,
               const WorkerErrorReport& aReport, uint64_t aInnerWindowId,
               JS::Handle<JS::Value> aException = JS::NullHandleValue)
   {
     if (aWorkerPrivate) {
       aWorkerPrivate->AssertIsOnWorkerThread();
     } else {
       AssertIsOnMainThread();
     }
@@ -172,18 +172,16 @@ private:
 
     // Dispatch may fail if the worker was canceled, no need to report that as
     // an error, so don't call base class PostDispatch.
   }
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
-    JS::Rooted<JSObject*> target(aCx, aWorkerPrivate->GetWrapper());
-
     uint64_t innerWindowId;
     bool fireAtScope = true;
 
     bool workerIsAcceptingEvents = aWorkerPrivate->IsAcceptingEvents();
 
     WorkerPrivate* parent = aWorkerPrivate->GetParent();
     if (parent) {
       innerWindowId = 0;
@@ -231,18 +229,19 @@ private:
     }
 
     // Don't fire this event if the JS object has been disconnected from the
     // private object.
     if (!workerIsAcceptingEvents) {
       return true;
     }
 
-    ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport,
-                innerWindowId);
+    ReportError(aCx, parent, fireAtScope,
+                aWorkerPrivate->ParentEventTargetRef(),
+                mReport, innerWindowId);
     return true;
   }
 };
 
 } // anonymous
 
 void
 WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport)
--- a/dom/workers/WorkerHolder.h
+++ b/dom/workers/WorkerHolder.h
@@ -13,67 +13,64 @@ namespace mozilla {
 namespace dom {
 
 class WorkerPrivate;
 
 /**
  * Use this chart to help figure out behavior during each of the closing
  * statuses. Details below.
  *
- * +==============================================================+
- * |                       Closing Statuses                       |
- * +=============+=============+=================+================+
- * |    status   | clear queue | abort execution |  close handler |
- * +=============+=============+=================+================+
- * |   Closing   |     yes     |       no        |   no timeout   |
- * +-------------+-------------+-----------------+----------------+
- * | Terminating |     yes     |       yes       |   no timeout   |
- * +-------------+-------------+-----------------+----------------+
- * |  Canceling  |     yes     |       yes       | short duration |
- * +-------------+-------------+-----------------+----------------+
- * |   Killing   |     yes     |       yes       |   doesn't run  |
- * +-------------+-------------+-----------------+----------------+
+ * +=============================================+
+ * |             Closing Statuses                |
+ * +=============+=============+=================+
+ * |    status   | clear queue | abort execution |
+ * +=============+=============+=================+
+ * |   Closing   |     yes     |       no        |
+ * +-------------+-------------+-----------------+
+ * | Terminating |     yes     |       yes       |
+ * +-------------+-------------+-----------------+
+ * |  Canceling  |     yes     |       yes       |
+ * +-------------+-------------+-----------------+
+ * |   Killing   |     yes     |       yes       |
+ * +-------------+-------------+-----------------+
  */
 
 #ifdef Status
 /* Xlib headers insist on this for some reason... Nuke it because
    it'll override our member name */
 #undef Status
 #endif
 enum WorkerStatus
 {
   // Not yet scheduled.
   Pending = 0,
 
-  // This status means that the close handler has not yet been scheduled.
+  // This status means that the worker is active.
   Running,
 
   // Inner script called close() on the worker global scope. Setting this
   // status causes the worker to clear its queue of events but does not abort
-  // the currently running script. The close handler is also scheduled with
-  // no expiration time.
+  // the currently running script.
   Closing,
 
   // Outer script called terminate() on the worker or the worker object was
   // garbage collected in its outer script. Setting this status causes the
-  // worker to abort immediately, clear its queue of events, and schedules the
-  // close handler with no expiration time.
+  // worker to abort immediately and clear its queue of events.
   Terminating,
 
   // Either the user navigated away from the owning page or the owning page fell
-  // out of bfcache. Setting this status causes the worker to abort immediately
-  // and schedules the close handler with a short expiration time. Since the
-  // page has gone away the worker may not post any messages.
+  // out of bfcache. Setting this status causes the worker to abort immediately.
+  // Since the page has gone away the worker may not post any messages.
   Canceling,
 
   // The application is shutting down. Setting this status causes the worker to
-  // abort immediately and the close handler is never scheduled.
+  // abort immediately.
   Killing,
 
-  // The close handler has run and the worker is effectively dead.
+  // The worker is effectively dead.
   Dead
 };
 
 class WorkerHolder
 {
 public:
   enum Behavior {
     AllowIdleShutdownStart,
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -23,16 +23,18 @@
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
 #include "mozilla/dom/Navigator.h"
 
 namespace mozilla {
 namespace dom {
 
+using namespace workerinternals;
+
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WorkerNavigator, mStorageManager,
                                       mConnection);
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
 
 WorkerNavigator::WorkerNavigator(const NavigatorProperties& aProperties,
                                  bool aOnline)
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -244,17 +244,17 @@ private:
 
     RuntimeService* runtime = RuntimeService::GetService();
     NS_ASSERTION(runtime, "This should never be null!");
 
     mFinishedWorker->DisableDebugger();
 
     runtime->UnregisterWorker(mFinishedWorker);
 
-    mFinishedWorker->ClearSelfRef();
+    mFinishedWorker->ClearSelfAndParentEventTargetRef();
     return true;
   }
 };
 
 class TopLevelWorkerFinishedRunnable final : public Runnable
 {
   WorkerPrivate* mFinishedWorker;
 
@@ -282,17 +282,17 @@ private:
     mFinishedWorker->DisableDebugger();
 
     runtime->UnregisterWorker(mFinishedWorker);
 
     if (!mFinishedWorker->ProxyReleaseMainThreadObjects()) {
       NS_WARNING("Failed to dispatch, going to leak!");
     }
 
-    mFinishedWorker->ClearSelfRef();
+    mFinishedWorker->ClearSelfAndParentEventTargetRef();
     return NS_OK;
   }
 };
 
 class ModifyBusyCountRunnable final : public WorkerControlRunnable
 {
   bool mIncrease;
 
@@ -379,23 +379,25 @@ private:
       }
       return true;
     }
 
     if (!aWorkerPrivate->IsAcceptingEvents()) {
       return true;
     }
 
+    RefPtr<mozilla::dom::EventTarget> parentEventTarget =
+      aWorkerPrivate->ParentEventTargetRef();
     RefPtr<Event> event =
-      Event::Constructor(aWorkerPrivate, NS_LITERAL_STRING("error"),
+      Event::Constructor(parentEventTarget, NS_LITERAL_STRING("error"),
                          EventInit());
     event->SetTrusted(true);
 
     bool dummy;
-    aWorkerPrivate->DispatchEvent(event, &dummy);
+    parentEventTarget->DispatchEvent(event, &dummy);
     return true;
   }
 };
 
 class CompileScriptRunnable final : public WorkerRunnable
 {
   nsString mScriptURL;
 
@@ -1541,24 +1543,16 @@ WorkerPrivateParent<Derived>::SetReferre
     nsContentUtils::GetReferrerPolicyFromHeader(headerValue);
   if (policy == net::RP_Unset) {
     return;
   }
 
   SetReferrerPolicy(policy);
 }
 
-
-// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the
-// templates.
-template <class Derived>
-typename WorkerPrivateParent<Derived>::cycleCollection
-  WorkerPrivateParent<Derived>::_cycleCollectorGlobal =
-    WorkerPrivateParent<Derived>::cycleCollection();
-
 template <class Derived>
 WorkerPrivateParent<Derived>::WorkerPrivateParent(
                                            WorkerPrivate* aParent,
                                            const nsAString& aScriptURL,
                                            bool aIsChromeWorker,
                                            WorkerType aWorkerType,
                                            const nsAString& aWorkerName,
                                            const nsACString& aServiceWorkerScope,
@@ -1571,21 +1565,16 @@ WorkerPrivateParent<Derived>::WorkerPriv
   mParentStatus(Pending), mParentFrozen(false),
   mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
   mIsSecureContext(false), mWorkerType(aWorkerType),
   mCreationTimeStamp(TimeStamp::Now()),
   mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
 {
   MOZ_ASSERT_IF(!IsDedicatedWorker(), NS_IsMainThread());
 
-  if (aLoadInfo.mWindow) {
-    AssertIsOnMainThread();
-    BindToOwner(aLoadInfo.mWindow);
-  }
-
   mLoadInfo.StealFrom(aLoadInfo);
 
   if (aParent) {
     aParent->AssertIsOnWorkerThread();
 
     // Note that this copies our parent's secure context state into mJSSettings.
     aParent->CopyJSSettings(mJSSettings);
 
@@ -1639,33 +1628,33 @@ WorkerPrivateParent<Derived>::WorkerPriv
 
 template <class Derived>
 WorkerPrivateParent<Derived>::~WorkerPrivateParent()
 {
   DropJSObjects(this);
 }
 
 template <class Derived>
-JSObject*
-WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+void
+WorkerPrivateParent<Derived>::Traverse(nsCycleCollectionTraversalCallback& aCb)
 {
-  MOZ_ASSERT(!IsSharedWorker(),
-             "We should never wrap a WorkerPrivate for a SharedWorker");
-
   AssertIsOnParentThread();
 
-  // XXXkhuey this should not need to be rooted, the analysis is dumb.
-  // See bug 980181.
-  JS::Rooted<JSObject*> wrapper(aCx,
-    WorkerBinding::Wrap(aCx, ParentAsWorkerPrivate(), aGivenProto));
-  if (wrapper) {
-    MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
-  }
-
-  return wrapper;
+  // The WorkerPrivate::mParentEventTargetRef has a reference to the exposed
+  // Worker object, which is really held by the worker thread.  We traverse this
+  // reference if and only if our busy count is zero and we have not released
+  // the main thread reference.  We do not unlink it.  This allows the CC to
+  // break cycles involving the Worker and begin shutting it down (which does
+  // happen in unlink) but ensures that the WorkerPrivate won't be deleted
+  // before we're done shutting down the thread.
+  if (!mBusyCount && !mMainThreadObjectsForgotten) {
+    nsCycleCollectionTraversalCallback& cb = aCb;
+    WorkerPrivateParent<Derived>* tmp = this;
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentEventTargetRef);
+  }
 }
 
 template <class Derived>
 nsresult
 WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable> aRunnable,
                                               nsIEventTarget* aSyncLoopTarget)
 {
   // May be called on any thread!
@@ -2142,86 +2131,16 @@ WorkerPrivateParent<Derived>::ProxyRelea
 
   mMainThreadObjectsForgotten = true;
 
   return result;
 }
 
 template <class Derived>
 void
-WorkerPrivateParent<Derived>::PostMessageInternal(JSContext* aCx,
-                                                  JS::Handle<JS::Value> aMessage,
-                                                  const Sequence<JSObject*>& aTransferable,
-                                                  ErrorResult& aRv)
-{
-  AssertIsOnParentThread();
-
-  {
-    MutexAutoLock lock(mMutex);
-    if (mParentStatus > Running) {
-      return;
-    }
-  }
-
-  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
-
-  aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
-                                                          &transferable);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  RefPtr<MessageEventRunnable> runnable =
-    new MessageEventRunnable(ParentAsWorkerPrivate(),
-                             WorkerRunnable::WorkerThreadModifyBusyCount);
-
-  UniquePtr<AbstractTimelineMarker> start;
-  UniquePtr<AbstractTimelineMarker> end;
-  RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
-  bool isTimelineRecording = timelines && !timelines->IsEmpty();
-
-  if (isTimelineRecording) {
-    start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
-      ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
-      : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
-      MarkerTracingType::START);
-  }
-
-  runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv);
-
-  if (isTimelineRecording) {
-    end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
-      ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
-      : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
-      MarkerTracingType::END);
-    timelines->AddMarkerForAllObservedDocShells(start);
-    timelines->AddMarkerForAllObservedDocShells(end);
-  }
-
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  if (!runnable->Dispatch()) {
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
-}
-
-template <class Derived>
-void
-WorkerPrivateParent<Derived>::PostMessage(
-                             JSContext* aCx, JS::Handle<JS::Value> aMessage,
-                             const Sequence<JSObject*>& aTransferable,
-                             ErrorResult& aRv)
-{
-  PostMessageInternal(aCx, aMessage, aTransferable, aRv);
-}
-
-template <class Derived>
-void
 WorkerPrivateParent<Derived>::UpdateContextOptions(
                                     const JS::ContextOptions& aContextOptions)
 {
   AssertIsOnParentThread();
 
   {
     MutexAutoLock lock(mMutex);
     mJSSettings.contextOptions = aContextOptions;
@@ -2775,58 +2694,16 @@ WorkerPrivateParent<Derived>::FlushRepor
   if (reportErrorToBrowserConsole) {
     aReporter->FlushReportsToConsole(0);
     return;
   }
 
   aReporter->ClearConsoleReports();
 }
 
-template <class Derived>
-NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
-
-template <class Derived>
-NS_IMPL_RELEASE_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
-
-template <class Derived>
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPrivateParent<Derived>)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-template <class Derived>
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
-                                                  DOMEventTargetHelper)
-  tmp->AssertIsOnParentThread();
-
-  // The WorkerPrivate::mSelfRef has a reference to itself, which is really
-  // held by the worker thread.  We traverse this reference if and only if our
-  // busy count is zero and we have not released the main thread reference.
-  // We do not unlink it.  This allows the CC to break cycles involving the
-  // WorkerPrivate and begin shutting it down (which does happen in unlink) but
-  // ensures that the WorkerPrivate won't be deleted before we're done shutting
-  // down the thread.
-
-  if (!tmp->mBusyCount && !tmp->mMainThreadObjectsForgotten) {
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelfRef)
-  }
-
-  // The various strong references in LoadInfo are managed manually and cannot
-  // be cycle collected.
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-template <class Derived>
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
-                                                DOMEventTargetHelper)
-  tmp->Terminate();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-template <class Derived>
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
-                                               DOMEventTargetHelper)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 #ifdef DEBUG
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::AssertIsOnParentThread() const
 {
   if (GetParent()) {
     GetParent()->AssertIsOnWorkerThread();
@@ -2951,68 +2828,16 @@ WorkerPrivate::~WorkerPrivate()
   // enter the Killing state, but we do it again here to be safe.
   // Its possible that we may be created and destroyed without progressing
   // to Killing via some obscure code path.
   mWorkerHybridEventTarget->ForgetWorkerPrivate(this);
 }
 
 // static
 already_AddRefed<WorkerPrivate>
-WorkerPrivate::Constructor(const GlobalObject& aGlobal,
-                           const nsAString& aScriptURL,
-                           const WorkerOptions& aOptions,
-                           ErrorResult& aRv)
-{
-  return WorkerPrivate::Constructor(aGlobal, aScriptURL, false,
-                                    WorkerTypeDedicated,
-                                    aOptions.mName, nullptr, aRv);
-}
-
-// static
-already_AddRefed<ChromeWorkerPrivate>
-ChromeWorkerPrivate::Constructor(const GlobalObject& aGlobal,
-                                 const nsAString& aScriptURL,
-                                 ErrorResult& aRv)
-{
-  return WorkerPrivate::Constructor(aGlobal, aScriptURL, true,
-                                    WorkerTypeDedicated, EmptyString(),
-                                    nullptr, aRv)
-                                    .downcast<ChromeWorkerPrivate>();
-}
-
-// static
-bool
-ChromeWorkerPrivate::WorkerAvailable(JSContext* aCx, JSObject* /* unused */)
-{
-  // Chrome is always allowed to use workers, and content is never
-  // allowed to use ChromeWorker, so all we have to check is the
-  // caller.  However, chrome workers apparently might not have a
-  // system principal, so we have to check for them manually.
-  if (NS_IsMainThread()) {
-    return nsContentUtils::IsSystemCaller(aCx);
-  }
-
-  return GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
-}
-
-// static
-already_AddRefed<WorkerPrivate>
-WorkerPrivate::Constructor(const GlobalObject& aGlobal,
-                           const nsAString& aScriptURL,
-                           bool aIsChromeWorker, WorkerType aWorkerType,
-                           const nsAString& aWorkerName,
-                           WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
-{
-  JSContext* cx = aGlobal.Context();
-  return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType,
-                     aWorkerName, VoidCString(), aLoadInfo, aRv);
-}
-
-// static
-already_AddRefed<WorkerPrivate>
 WorkerPrivate::Constructor(JSContext* aCx,
                            const nsAString& aScriptURL,
                            bool aIsChromeWorker, WorkerType aWorkerType,
                            const nsAString& aWorkerName,
                            const nsACString& aServiceWorkerScope,
                            WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
 {
   // If this is a sub-worker, we need to keep the parent worker alive until this
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -9,25 +9,22 @@
 
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIEventTarget.h"
 #include "nsTObserverArray.h"
 
+#include "mozilla/dom/Worker.h"
 #include "mozilla/dom/WorkerHolder.h"
 #include "mozilla/dom/WorkerLoadInfo.h"
 #include "mozilla/dom/workerinternals/JSSettings.h"
 #include "mozilla/dom/workerinternals/Queue.h"
 
-#ifdef XP_WIN
-#undef PostMessage
-#endif
-
 class nsIConsoleReportCollector;
 class nsIThreadInternal;
 
 namespace mozilla {
 namespace dom {
 
 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
 // to be updated too.
@@ -46,17 +43,16 @@ class MessagePortIdentifier;
 class PerformanceStorage;
 class SharedWorker;
 class WorkerControlRunnable;
 class WorkerDebugger;
 class WorkerDebuggerGlobalScope;
 class WorkerErrorReport;
 class WorkerEventTarget;
 class WorkerGlobalScope;
-struct WorkerOptions;
 class WorkerRunnable;
 class WorkerThread;
 
 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
 // object. It exists to avoid changing a lot of code to use Mutex* instead of
 // Mutex&.
 class SharedMutex
 {
@@ -100,17 +96,17 @@ public:
   void
   AssertCurrentThreadOwns() const
   {
     mMutex->AssertCurrentThreadOwns();
   }
 };
 
 template <class Derived>
-class WorkerPrivateParent : public DOMEventTargetHelper
+class WorkerPrivateParent
 {
 protected:
   class EventTarget;
   friend class EventTarget;
 
   typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
 
 public:
@@ -179,28 +175,39 @@ private:
   // use our global object's secure state there.
   bool mIsSecureContext;
   WorkerType mWorkerType;
   TimeStamp mCreationTimeStamp;
   DOMHighResTimeStamp mCreationTimeHighRes;
 
 protected:
   // The worker is owned by its thread, which is represented here.  This is set
-  // in Construct() and emptied by WorkerFinishedRunnable, and conditionally
+  // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
   // traversed by the cycle collector if the busy count is zero.
+  //
+  // There are 4 ways a worker can be terminated:
+  // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
+  //    traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
+  //    Worker webidl object. Doing this, CC will be able to detect a cycle and
+  //    Unlink is called. In Unlink, Worker calls Terminate().
+  // 2. Worker::Terminate() is called - the shutdown procedure starts
+  //    immediately.
+  // 3. WorkerScope::Close() is called - Similar to point 2.
+  // 4. xpcom-shutdown notification - We call Kill().
+  RefPtr<Worker> mParentEventTargetRef;
   RefPtr<WorkerPrivate> mSelfRef;
 
   WorkerPrivateParent(WorkerPrivate* aParent,
                       const nsAString& aScriptURL, bool aIsChromeWorker,
                       WorkerType aWorkerType,
                       const nsAString& aWorkerName,
                       const nsACString& aServiceWorkerScope,
                       WorkerLoadInfo& aLoadInfo);
 
-  ~WorkerPrivateParent();
+  virtual ~WorkerPrivateParent();
 
 private:
   Derived*
   ParentAsWorkerPrivate() const
   {
     return static_cast<Derived*>(const_cast<WorkerPrivateParent*>(this));
   }
 
@@ -208,43 +215,37 @@ private:
   NotifyPrivate(WorkerStatus aStatus);
 
   bool
   TerminatePrivate()
   {
     return NotifyPrivate(Terminating);
   }
 
-  void
-  PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-                      const Sequence<JSObject*>& aTransferable,
-                      ErrorResult& aRv);
-
   nsresult
   DispatchPrivate(already_AddRefed<WorkerRunnable> aRunnable, nsIEventTarget* aSyncLoopTarget);
 
 public:
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+  NS_INLINE_DECL_REFCOUNTING(WorkerPrivateParent)
 
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
-                                                         DOMEventTargetHelper)
+  void
+  Traverse(nsCycleCollectionTraversalCallback& aCb);
 
   void
   EnableDebugger();
 
   void
   DisableDebugger();
 
   void
-  ClearSelfRef()
+  ClearSelfAndParentEventTargetRef()
   {
     AssertIsOnParentThread();
     MOZ_ASSERT(mSelfRef);
+    mParentEventTargetRef = nullptr;
     mSelfRef = nullptr;
   }
 
   nsresult
   Dispatch(already_AddRefed<WorkerRunnable> aRunnable)
   {
     return DispatchPrivate(Move(aRunnable), nullptr);
   }
@@ -314,21 +315,16 @@ public:
 
   bool
   ModifyBusyCount(bool aIncrease);
 
   bool
   ProxyReleaseMainThreadObjects();
 
   void
-  PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-              const Sequence<JSObject*>& aTransferable,
-              ErrorResult& aRv);
-
-  void
   UpdateContextOptions(const JS::ContextOptions& aContextOptions);
 
   void
   UpdateLanguages(const nsTArray<nsString>& aLanguages);
 
   void
   UpdateJSWorkerMemoryParameter(JSGCParamKey key, uint32_t value);
 
@@ -389,17 +385,25 @@ public:
 
   bool
   IsAcceptingEvents()
   {
     AssertIsOnParentThread();
 
     MutexAutoLock lock(mMutex);
     return mParentStatus < Terminating;
-    }
+  }
+
+  WorkerStatus
+  ParentStatusProtected()
+  {
+    AssertIsOnParentThread();
+    MutexAutoLock lock(mMutex);
+    return mParentStatus;
+  }
 
   WorkerStatus
   ParentStatus() const
   {
     mMutex.AssertCurrentThreadOwns();
     return mParentStatus;
   }
 
@@ -824,20 +828,16 @@ public:
   StealLoadFailedAsyncRunnable()
   {
     return mLoadInfo.mLoadFailedAsyncRunnable.forget();
   }
 
   void
   FlushReportsToSharedWorkers(nsIConsoleReportCollector* aReporter);
 
-  IMPL_EVENT_HANDLER(message)
-  IMPL_EVENT_HANDLER(messageerror)
-  IMPL_EVENT_HANDLER(error)
-
   // Check whether this worker is a secure context.  For use from the parent
   // thread only; the canonical "is secure context" boolean is stored on the
   // compartment of the worker global.  The only reason we don't
   // AssertIsOnParentThread() here is so we can assert that this value matches
   // the one on the compartment, which has to be done from the worker thread.
   bool IsSecureContext() const
   {
     return mIsSecureContext;
@@ -964,27 +964,16 @@ class WorkerPrivate : public WorkerPriva
   bool mFetchHandlerWasAdded;
   bool mOnLine;
 
 protected:
   ~WorkerPrivate();
 
 public:
   static already_AddRefed<WorkerPrivate>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              const WorkerOptions& aOptions,
-              ErrorResult& aRv);
-
-  static already_AddRefed<WorkerPrivate>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              bool aIsChromeWorker, WorkerType aWorkerType,
-              const nsAString& aWorkerName,
-              WorkerLoadInfo* aLoadInfo, ErrorResult& aRv);
-
-  static already_AddRefed<WorkerPrivate>
   Constructor(JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker,
               WorkerType aWorkerType, const nsAString& aWorkerName,
               const nsACString& aServiceWorkerScope,
               WorkerLoadInfo* aLoadInfo, ErrorResult& aRv);
 
   enum LoadGroupBehavior
   {
     InheritLoadGroup,
@@ -1384,16 +1373,31 @@ public:
   Control(const ServiceWorkerDescriptor& aServiceWorker);
 
   void
   ExecutionReady();
 
   PerformanceStorage*
   GetPerformanceStorage();
 
+  Worker*
+  ParentEventTargetRef() const
+  {
+    MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef);
+    return mParentEventTargetRef;
+  }
+
+  void
+  SetParentEventTargetRef(Worker* aParentEventTargetRef)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef);
+    MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef);
+    mParentEventTargetRef = aParentEventTargetRef;
+  }
+
 private:
   WorkerPrivate(WorkerPrivate* aParent,
                 const nsAString& aScriptURL, bool aIsChromeWorker,
                 WorkerType aWorkerType, const nsAString& aWorkerName,
                 const nsACString& aServiceWorkerScope,
                 WorkerLoadInfo& aLoadInfo);
 
   bool
@@ -1486,35 +1490,16 @@ private:
   bool
   HasActiveHolders()
   {
     return !(mChildWorkers.IsEmpty() && mTimeouts.IsEmpty() &&
              mHolders.IsEmpty());
   }
 };
 
-// This class is only used to trick the DOM bindings.  We never create
-// instances of it, and static_casting to it is fine since it doesn't add
-// anything to WorkerPrivate.
-class ChromeWorkerPrivate : public WorkerPrivate
-{
-public:
-  static already_AddRefed<ChromeWorkerPrivate>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
-              ErrorResult& rv);
-
-  static bool
-  WorkerAvailable(JSContext* aCx, JSObject* /* unused */);
-
-private:
-  ChromeWorkerPrivate() = delete;
-  ChromeWorkerPrivate(const ChromeWorkerPrivate& aRHS) = delete;
-  ChromeWorkerPrivate& operator =(const ChromeWorkerPrivate& aRHS) = delete;
-};
-
 class AutoSyncLoopHolder
 {
   WorkerPrivate* mWorkerPrivate;
   nsCOMPtr<nsIEventTarget> mTarget;
   uint32_t mIndex;
 
 public:
   // See CreateNewSyncLoop() for more information about the correct value to use
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -325,17 +325,18 @@ WorkerRunnable::Run()
     cx = aes->cx();
   } else {
     maybeJSAPI.emplace();
     maybeJSAPI->Init();
     jsapi = maybeJSAPI.ptr();
     cx = jsapi->cx();
   }
 
-  // Note that we can't assert anything about mWorkerPrivate->GetWrapper()
+  // Note that we can't assert anything about
+  // mWorkerPrivate->ParentEventTargetRef()->GetWrapper()
   // existing, since it may in fact have been GCed (and we may be one of the
   // runnables cleaning up the worker as a result).
 
   // If we are on the parent thread and that thread is not the main thread,
   // then we must be a dedicated worker (because there are no
   // Shared/ServiceWorkers whose parent is itself a worker) and then we
   // definitely have a globalObject.  If it _is_ the main thread, globalObject
   // can be null for workers started from JSMs or other non-window contexts,
@@ -343,37 +344,41 @@ WorkerRunnable::Run()
   MOZ_ASSERT_IF(!targetIsWorkerThread && !isMainThread,
                 mWorkerPrivate->IsDedicatedWorker() && globalObject);
 
   // If we're on the parent thread we might be in a null compartment in the
   // situation described above when globalObject is null.  Make sure to enter
   // the compartment of the worker's reflector if there is one.  There might
   // not be one if we're just starting to compile the script for this worker.
   Maybe<JSAutoCompartment> ac;
-  if (!targetIsWorkerThread && mWorkerPrivate->GetWrapper()) {
+  if (!targetIsWorkerThread &&
+      mWorkerPrivate->IsDedicatedWorker() &&
+      mWorkerPrivate->ParentEventTargetRef()->GetWrapper()) {
+    JSObject* wrapper = mWorkerPrivate->ParentEventTargetRef()->GetWrapper();
+
     // If we're on the parent thread and have a reflector and a globalObject,
     // then the compartments of cx, globalObject, and the worker's reflector
     // should all match.
     MOZ_ASSERT_IF(globalObject,
-                  js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) ==
+                  js::GetObjectCompartment(wrapper) ==
                     js::GetContextCompartment(cx));
     MOZ_ASSERT_IF(globalObject,
-                  js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) ==
+                  js::GetObjectCompartment(wrapper) ==
                     js::GetObjectCompartment(globalObject->GetGlobalJSObject()));
 
     // If we're on the parent thread and have a reflector, then our
     // JSContext had better be either in the null compartment (and hence
     // have no globalObject) or in the compartment of our reflector.
     MOZ_ASSERT(!js::GetContextCompartment(cx) ||
-               js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) ==
+               js::GetObjectCompartment(wrapper) ==
                  js::GetContextCompartment(cx),
                "Must either be in the null compartment or in our reflector "
                "compartment");
 
-    ac.emplace(cx, mWorkerPrivate->GetWrapper());
+    ac.emplace(cx, wrapper);
   }
 
   MOZ_ASSERT(!jsapi->HasException());
   result = WorkerRun(cx, mWorkerPrivate);
   MOZ_ASSERT_IF(result, !jsapi->HasException());
   jsapi->ReportException();
 
   // We can't even assert that this didn't create our global, since in the case
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -4,17 +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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Workers")
 
 # Public stuff.
 EXPORTS.mozilla.dom += [
+    'ChromeWorker.h',
     'SharedWorker.h',
+    'Worker.h',
     'WorkerCommon.h',
     'WorkerDebugger.h',
     'WorkerDebuggerManager.h',
     'WorkerHolder.h',
     'WorkerHolderToken.h',
     'WorkerLoadInfo.h',
     'WorkerLocation.h',
     'WorkerNavigator.h',
@@ -33,23 +35,25 @@ EXPORTS.mozilla.dom.workerinternals += [
 XPIDL_MODULE = 'dom_workers'
 
 XPIDL_SOURCES += [
     'nsIWorkerDebugger.idl',
     'nsIWorkerDebuggerManager.idl',
 ]
 
 UNIFIED_SOURCES += [
+    'ChromeWorker.cpp',
     'ChromeWorkerScope.cpp',
     'MessageEventRunnable.cpp',
     'Principal.cpp',
     'RegisterBindings.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
     'SharedWorker.cpp',
+    'Worker.cpp',
     'WorkerDebugger.cpp',
     'WorkerDebuggerManager.cpp',
     'WorkerError.cpp',
     'WorkerEventTarget.cpp',
     'WorkerHolder.cpp',
     'WorkerHolderToken.cpp',
     'WorkerLoadInfo.cpp',
     'WorkerLocation.cpp',
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -77,8 +77,10 @@ skip-if = (os == 'linux') # Bug 1244409
 [test_filePosting.xul]
 [test_fileReadSlice.xul]
 [test_fileReaderSync.xul]
 [test_fileReaderSyncErrors.xul]
 [test_fileSlice.xul]
 [test_fileSubWorker.xul]
 [test_bug1062920.xul]
 [test_sharedWorker_privateBrowsing.html]
+[test_shutdownCheck.xul]
+support-files = worker_shutdownCheck.js
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_shutdownCheck.xul
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+
+<window title="Worker shutdown check"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+SimpleTest.waitForExplicitFinish()
+
+const URL = "worker_shutdownCheck.js";
+
+function checkWorker() {
+  const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].
+              getService(Ci.nsIWorkerDebuggerManager);
+
+  let e = wdm.getWorkerDebuggerEnumerator();
+  while (e.hasMoreElements()) {
+    let dbg = e.getNext().QueryInterface(Ci.nsIWorkerDebugger);
+    if (dbg.url == URL) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+new Promise(resolve => {
+  var w = new Worker(URL);
+  ok(checkWorker(), "We have the worker");
+  w.onmessage = () => { resolve(); }
+}).then(() => {
+  info("Waiting...");
+
+  // We don't know if the worker thread is able to shutdown when calling
+  // CC/GC. Better to check again in case.
+  function checkGC() {
+    Cu.forceCC();
+    Cu.forceGC();
+    if (!checkWorker()) {
+      ok(true, "We don't have the worker");
+      SimpleTest.finish();
+      return;
+    }
+    setTimeout(checkGC, 200);
+  }
+
+  checkGC();
+});
+
+  ]]>
+  </script>
+</window>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/worker_shutdownCheck.js
@@ -0,0 +1,1 @@
+postMessage("Ok!");
--- a/editor/composer/nsEditingSession.cpp
+++ b/editor/composer/nsEditingSession.cpp
@@ -443,26 +443,27 @@ nsEditingSession::SetupEditorOnWindow(mo
   rv = htmlEditor->SetContentsMIMEType(mimeCType.get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIContentViewer> contentViewer;
   rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE);
 
-  nsCOMPtr<nsIDOMDocument> domDoc =
-    do_QueryInterface(contentViewer->GetDocument());
-  NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIDocument> doc = contentViewer->GetDocument();
+  if (NS_WARN_IF(!doc)) {
+    return NS_ERROR_FAILURE;
+  }
 
   // Set up as a doc state listener
   // Important! We must have this to broadcast the "obs_documentCreated" message
   rv = htmlEditor->AddDocumentStateListener(mComposerCommandsUpdater);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = htmlEditor->Init(domDoc, nullptr /* root content */,
+  rv = htmlEditor->Init(*doc, nullptr /* root content */,
                         nullptr, mEditorFlags, EmptyString());
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<Selection> selection = htmlEditor->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -211,58 +211,55 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
  NS_INTERFACE_MAP_ENTRY(nsIEditor)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(EditorBase)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorBase)
 
 
-NS_IMETHODIMP
-EditorBase::Init(nsIDOMDocument* aDOMDocument,
-                 nsIContent* aRoot,
+nsresult
+EditorBase::Init(nsIDocument& aDocument,
+                 Element* aRoot,
                  nsISelectionController* aSelectionController,
                  uint32_t aFlags,
                  const nsAString& aValue)
 {
   MOZ_ASSERT(mAction == EditAction::none,
              "Initializing during an edit action is an error");
-  MOZ_ASSERT(aDOMDocument);
-  if (!aDOMDocument) {
-    return NS_ERROR_NULL_POINTER;
-  }
 
   // First only set flags, but other stuff shouldn't be initialized now.
   // Don't move this call after initializing mDocument.
   // SetFlags() can check whether it's called during initialization or not by
   // them.  Note that SetFlags() will be called by PostCreate().
 #ifdef DEBUG
   nsresult rv =
 #endif
   SetFlags(aFlags);
   NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed");
 
-  mDocument = do_QueryInterface(aDOMDocument);
+  mDocument = &aDocument;
   // HTML editors currently don't have their own selection controller,
   // so they'll pass null as aSelCon, and we'll get the selection controller
   // off of the presshell.
   nsCOMPtr<nsISelectionController> selectionController;
   if (aSelectionController) {
     mSelectionController = aSelectionController;
     selectionController = aSelectionController;
   } else {
     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     selectionController = do_QueryInterface(presShell);
   }
   MOZ_ASSERT(selectionController,
              "Selection controller should be available at this point");
 
   //set up root element if we are passed one.
-  if (aRoot)
-    mRootElement = do_QueryInterface(aRoot);
+  if (aRoot) {
+    mRootElement = aRoot;
+  }
 
   mUpdateCount=0;
 
   // If this is an editor for <input> or <textarea>, the text node which
   // has composition string is always recreated with same content. Therefore,
   // we need to nodify mComposition of text node destruction and replacing
   // composing string when this receives eCompositionChange event next time.
   if (mComposition &&
@@ -1348,24 +1345,16 @@ nsresult
 EditorBase::RemoveAttribute(Element* aElement,
                             nsAtom* aAttribute)
 {
   RefPtr<ChangeAttributeTransaction> transaction =
     ChangeAttributeTransaction::CreateToRemove(*aElement, *aAttribute);
   return DoTransaction(transaction);
 }
 
-bool
-EditorBase::OutputsMozDirty()
-{
-  // Return true for Composer (!IsInteractionAllowed()) or mail
-  // (IsMailEditor()), but false for webpages.
-  return !IsInteractionAllowed() || IsMailEditor();
-}
-
 NS_IMETHODIMP
 EditorBase::MarkNodeDirty(nsIDOMNode* aNode)
 {
   // Mark the node dirty, but not for webpages (bug 599983)
   if (!OutputsMozDirty()) {
     return NS_OK;
   }
   nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
@@ -2504,17 +2493,17 @@ EditorBase::CommitComposition()
   if (!pc) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return mComposition ?
     IMEStateManager::NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, pc) : NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 EditorBase::GetPreferredIMEState(IMEState* aState)
 {
   NS_ENSURE_ARG_POINTER(aState);
   aState->mEnabled = IMEState::ENABLED;
   aState->mOpen = IMEState::DONT_CHANGE_OPEN_STATE;
 
   if (IsReadonly() || IsDisabled()) {
     aState->mEnabled = IMEState::DISABLED;
@@ -5242,17 +5231,17 @@ public:
                             nsISelectionController::SELECTION_NORMAL);
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsISelectionController> mSelectionController;
 };
 
-NS_IMETHODIMP
+nsresult
 EditorBase::FinalizeSelection()
 {
   nsCOMPtr<nsISelectionController> selectionController =
     GetSelectionController();
   if (NS_WARN_IF(!selectionController)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -5410,22 +5399,16 @@ EditorBase::SwitchTextDirectionTo(uint32
   }
 
   if (NS_SUCCEEDED(rv)) {
     FireInputEvent();
   }
 }
 
 bool
-EditorBase::IsModifiableNode(nsIDOMNode* aNode)
-{
-  return true;
-}
-
-bool
 EditorBase::IsModifiableNode(nsINode* aNode)
 {
   return true;
 }
 
 nsIContent*
 EditorBase::GetFocusedContent()
 {
@@ -5562,26 +5545,16 @@ EditorBase::GetSuppressDispatchingInputE
 
 NS_IMETHODIMP
 EditorBase::SetSuppressDispatchingInputEvent(bool aSuppress)
 {
   mDispatchInputEvent = !aSuppress;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-EditorBase::GetIsInEditAction(bool* aIsInEditAction)
-{
-  // NOTE: If you need to override this method, you need to make
-  //       IsInEditAction() virtual.
-  MOZ_ASSERT(aIsInEditAction, "aIsInEditAction must not be null");
-  *aIsInEditAction = IsInEditAction();
-  return NS_OK;
-}
-
 int32_t
 EditorBase::GetIMESelectionStartOffsetIn(nsINode* aTextNode)
 {
   MOZ_ASSERT(aTextNode, "aTextNode must not be nullptr");
 
   nsISelectionController* selectionController = GetSelectionController();
   if (NS_WARN_IF(!selectionController)) {
     return -1;
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -215,16 +215,33 @@ protected:
    * for someone to derive from the EditorBase later? I don't believe so.
    */
   virtual ~EditorBase();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
 
+  /**
+   * Init is to tell the implementation of nsIEditor to begin its services
+   * @param aDoc          The dom document interface being observed
+   * @param aRoot         This is the root of the editable section of this
+   *                      document. If it is null then we get root
+   *                      from document body.
+   * @param aSelCon       this should be used to get the selection location
+   *                      (will be null for HTML editors)
+   * @param aFlags        A bitmask of flags for specifying the behavior
+   *                      of the editor.
+   */
+  virtual nsresult Init(nsIDocument& doc,
+                        Element* aRoot,
+                        nsISelectionController* aSelCon,
+                        uint32_t aFlags,
+                        const nsAString& aInitialValue);
+
   bool IsInitialized() const { return !!mDocument; }
   already_AddRefed<nsIDOMDocument> GetDOMDocument();
   already_AddRefed<nsIDocument> GetDocument();
   already_AddRefed<nsIPresShell> GetPresShell();
   nsPresContext* GetPresContext()
   {
     RefPtr<nsIPresShell> presShell = GetPresShell();
     return presShell ? presShell->GetPresContext() : nullptr;
@@ -453,28 +470,38 @@ public:
    * IME event handlers.
    */
   virtual nsresult BeginIMEComposition(WidgetCompositionEvent* aEvent);
   virtual nsresult UpdateIMEComposition(
                      WidgetCompositionEvent* aCompositionChangeEvet) = 0;
   void EndIMEComposition();
 
   /**
+   * Get preferred IME status of current widget.
+   */
+  virtual nsresult GetPreferredIMEState(widget::IMEState* aState);
+
+  /**
    * Commit composition if there is.
    * Note that when there is a composition, this requests to commit composition
    * to native IME.  Therefore, when there is composition, this can do anything.
    * For example, the editor instance, the widget or the process itself may
    * be destroyed.
    */
   nsresult CommitComposition();
 
   void SwitchTextDirectionTo(uint32_t aDirection);
 
   RangeUpdater& RangeUpdaterRef() { return mRangeUpdater; }
 
+  /**
+   * Finalizes selection and caret for the editor.
+   */
+  nsresult FinalizeSelection();
+
 protected:
   nsresult DetermineCurrentDirection();
   void FireInputEvent();
 
   /**
    * Create an element node whose name is aTag at before aPointToInsert.  When
    * this succeed to create an element node, this sets aPointToInsert to the
    * new element because the relation of child and offset may be broken.
@@ -1285,16 +1312,27 @@ public:
   }
 
   bool Destroyed() const
   {
     return mDidPreDestroy;
   }
 
   /**
+   * Returns true if markNodeDirty() has any effect.  Returns false if
+   * markNodeDirty() is a no-op.
+   */
+  bool OutputsMozDirty() const
+  {
+    // Return true for Composer (!IsInteractionAllowed()) or mail
+    // (IsMailEditor()), but false for webpages.
+    return !IsInteractionAllowed() || IsMailEditor();
+  }
+
+  /**
    * GetTransactionManager() returns transaction manager associated with the
    * editor.  This may return nullptr if undo/redo hasn't been enabled.
    */
   already_AddRefed<nsITransactionManager> GetTransactionManager() const;
 
   /**
    * Get the input event target. This might return null.
    */
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -226,42 +226,39 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIHTMLAbsPosEditor)
   NS_INTERFACE_MAP_ENTRY(nsIHTMLInlineTableEditor)
   NS_INTERFACE_MAP_ENTRY(nsITableEditor)
   NS_INTERFACE_MAP_ENTRY(nsIEditorStyleSheets)
   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
 NS_INTERFACE_MAP_END_INHERITING(TextEditor)
 
-NS_IMETHODIMP
-HTMLEditor::Init(nsIDOMDocument* aDoc,
-                 nsIContent* aRoot,
+nsresult
+HTMLEditor::Init(nsIDocument& aDoc,
+                 Element* aRoot,
                  nsISelectionController* aSelCon,
                  uint32_t aFlags,
                  const nsAString& aInitialValue)
 {
-  NS_PRECONDITION(aDoc && !aSelCon, "bad arg");
-  NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
   MOZ_ASSERT(aInitialValue.IsEmpty(), "Non-empty initial values not supported");
 
   nsresult rulesRv = NS_OK;
 
   {
     // block to scope AutoEditInitRulesTrigger
     AutoEditInitRulesTrigger rulesTrigger(this, rulesRv);
 
     // Init the plaintext editor
     nsresult rv = TextEditor::Init(aDoc, aRoot, nullptr, aFlags, aInitialValue);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // Init mutation observer
-    nsCOMPtr<nsINode> document = do_QueryInterface(aDoc);
-    document->AddMutationObserverUnlessExists(this);
+    aDoc.AddMutationObserverUnlessExists(this);
 
     if (!mRootElement) {
       UpdateRootElement();
     }
 
     // disable Composer-only features
     if (IsMailEditor()) {
       SetAbsolutePositioningEnabled(false);
@@ -3084,17 +3081,18 @@ HTMLEditor::DeleteNode(nsINode* aNode)
   return DeleteNode(aNode->AsDOMNode());
 }
 
 NS_IMETHODIMP
 HTMLEditor::DeleteNode(nsIDOMNode* aNode)
 {
   // do nothing if the node is read-only
   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-  if (NS_WARN_IF(!IsModifiableNode(aNode) && !IsMozEditorBogusNode(content))) {
+  if (NS_WARN_IF(!IsModifiableNode(content) &&
+                 !IsMozEditorBogusNode(content))) {
     return NS_ERROR_FAILURE;
   }
 
   return EditorBase::DeleteNode(aNode);
 }
 
 nsresult
 HTMLEditor::DeleteText(nsGenericDOMDataNode& aCharData,
@@ -3244,23 +3242,16 @@ HTMLEditor::ContentRemoved(nsIDocument* 
       return;
     }
     // Protect the edit rules object from dying
     RefPtr<TextEditRules> rules(mRules);
     rules->DocumentModified();
   }
 }
 
-NS_IMETHODIMP_(bool)
-HTMLEditor::IsModifiableNode(nsIDOMNode* aNode)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  return IsModifiableNode(node);
-}
-
 bool
 HTMLEditor::IsModifiableNode(nsINode* aNode)
 {
   return !aNode || aNode->IsEditable();
 }
 
 NS_IMETHODIMP
 HTMLEditor::DebugUnitTests(int32_t* outNumTests,
@@ -4831,17 +4822,17 @@ HTMLEditor::IsAcceptableInputEvent(Widge
 
   // Finally, check whether we're actually focused or not.  When we're not
   // focused, we should ignore the dispatched event by script (or something)
   // because content editable element needs selection in itself for editing.
   // However, when we're not focused, it's not guaranteed.
   return IsActiveInDOMWindow();
 }
 
-NS_IMETHODIMP
+nsresult
 HTMLEditor::GetPreferredIMEState(IMEState* aState)
 {
   // HTML editor don't prefer the CSS ime-mode because IE didn't do so too.
   aState->mOpen = IMEState::DONT_CHANGE_OPEN_STATE;
   if (IsReadonly() || IsDisabled()) {
     aState->mEnabled = IMEState::DISABLED;
   } else {
     aState->mEnabled = IMEState::ENABLED;
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -101,25 +101,25 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, TextEditor)
 
   HTMLEditor();
 
   bool GetReturnInParagraphCreatesNewParagraph();
   Element* GetSelectionContainer();
 
-  // nsIEditor overrides
-  NS_IMETHOD GetPreferredIMEState(widget::IMEState* aState) override;
-
   // nsISelectionListener overrides
   NS_IMETHOD NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
                                     nsISelection* aSelection,
                                     int16_t aReason) override;
 
   // TextEditor overrides
+  virtual nsresult Init(nsIDocument& aDoc, Element* aRoot,
+                        nsISelectionController* aSelCon, uint32_t aFlags,
+                        const nsAString& aValue) override;
   NS_IMETHOD BeginningOfDocument() override;
   virtual nsresult HandleKeyPressEvent(
                      WidgetKeyboardEvent* aKeyboardEvent) override;
   virtual nsIContent* GetFocusedContent() override;
   virtual already_AddRefed<nsIContent> GetFocusedContentForIME() override;
   virtual bool IsActiveInDOMWindow() override;
   virtual dom::EventTarget* GetDOMEventTarget() override;
   virtual Element* GetEditorRoot() override;
@@ -216,21 +216,20 @@ public:
                                   bool* outIsSpace,
                                   bool* outIsNBSP,
                                   nsIContent** outNode = nullptr,
                                   int32_t* outOffset = 0);
 
   // Overrides of EditorBase interface methods
   virtual nsresult EndUpdateViewBatch() override;
 
-  NS_IMETHOD Init(nsIDOMDocument* aDoc, nsIContent* aRoot,
-                  nsISelectionController* aSelCon, uint32_t aFlags,
-                  const nsAString& aValue) override;
   NS_IMETHOD PreDestroy(bool aDestroyingFrames) override;
 
+  virtual nsresult GetPreferredIMEState(widget::IMEState* aState) override;
+
   /**
    * @param aElement        Must not be null.
    */
   static bool NodeIsBlockStatic(const nsINode* aElement);
   static nsresult NodeIsBlockStatic(nsIDOMNode *aNode, bool *aIsBlock);
 
   // non-virtual methods of interface methods
   bool AbsolutePositioningEnabled() const
@@ -386,17 +385,16 @@ public:
   nsresult DeleteText(nsGenericDOMDataNode& aTextNode, uint32_t aOffset,
                       uint32_t aLength);
   virtual nsresult
   InsertTextImpl(nsIDocument& aDocument,
                  const nsAString& aStringToInsert,
                  const EditorRawDOMPoint& aPointToInsert,
                  EditorRawDOMPoint* aPointAfterInsertedString =
                    nullptr) override;
-  NS_IMETHOD_(bool) IsModifiableNode(nsIDOMNode* aNode) override;
   virtual bool IsModifiableNode(nsINode* aNode) override;
 
   NS_IMETHOD SelectAll() override;
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet,
                               bool aWasAlternate, nsresult aStatus) override;
 
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -108,26 +108,23 @@ NS_IMPL_ADDREF_INHERITED(TextEditor, Edi
 NS_IMPL_RELEASE_INHERITED(TextEditor, EditorBase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextEditor)
   NS_INTERFACE_MAP_ENTRY(nsIPlaintextEditor)
   NS_INTERFACE_MAP_ENTRY(nsIEditorMailSupport)
 NS_INTERFACE_MAP_END_INHERITING(EditorBase)
 
 
-NS_IMETHODIMP
-TextEditor::Init(nsIDOMDocument* aDoc,
-                 nsIContent* aRoot,
+nsresult
+TextEditor::Init(nsIDocument& aDoc,
+                 Element* aRoot,
                  nsISelectionController* aSelCon,
                  uint32_t aFlags,
                  const nsAString& aInitialValue)
 {
-  NS_PRECONDITION(aDoc, "bad arg");
-  NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
-
   if (mRules) {
     mRules->DetachEditor();
   }
 
   nsresult rulesRv = NS_OK;
   {
     // block to scope AutoEditInitRulesTrigger
     AutoEditInitRulesTrigger rulesTrigger(this, rulesRv);
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -69,19 +69,19 @@ public:
                      bool aSuppressTransaction) override;
   virtual nsresult SetAttributeOrEquivalent(Element* aElement,
                                             nsAtom* aAttribute,
                                             const nsAString& aValue,
                                             bool aSuppressTransaction) override;
   using EditorBase::RemoveAttributeOrEquivalent;
   using EditorBase::SetAttributeOrEquivalent;
 
-  NS_IMETHOD Init(nsIDOMDocument* aDoc, nsIContent* aRoot,
-                  nsISelectionController* aSelCon, uint32_t aFlags,
-                  const nsAString& aValue) override;
+  virtual nsresult Init(nsIDocument& aDoc, Element* aRoot,
+                        nsISelectionController* aSelCon, uint32_t aFlags,
+                        const nsAString& aValue) override;
 
   nsresult DocumentIsEmpty(bool* aIsEmpty);
   NS_IMETHOD GetDocumentIsEmpty(bool* aDocumentIsEmpty) override;
 
   NS_IMETHOD DeleteSelection(EDirection aAction,
                              EStripWrappers aStripWrappers) override;
 
   NS_IMETHOD SetDocumentCharacterSet(const nsACString& characterSet) override;
--- a/editor/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -20,24 +20,19 @@ interface nsIEditActionListener;
 interface nsIInlineSpellChecker;
 interface nsITransferable;
 
 %{C++
 namespace mozilla {
 class EditorBase;
 class HTMLEditor;
 class TextEditor;
-namespace widget {
-struct IMEState;
-} // namespace widget
 } // namespace mozilla
 %}
 
-native IMEState(mozilla::widget::IMEState);
-
 [scriptable, builtinclass, uuid(094be624-f0bf-400f-89e2-6a84baab9474)]
 interface nsIEditor  : nsISupports
 {
 %{C++
   typedef short EDirection;
   typedef short EStripWrappers;
 %}
   const short eNone = 0;
@@ -48,38 +43,16 @@ interface nsIEditor  : nsISupports
   const short eToBeginningOfLine = 5;
   const short eToEndOfLine = 6;
 
   const short eStrip = 0;
   const short eNoStrip = 1;
 
   readonly attribute nsISelection selection;
 
-  /**
-   * Finalizes selection and caret for the editor.
-   */
-  [noscript] void finalizeSelection();
-
-  /**
-   * Init is to tell the implementation of nsIEditor to begin its services
-   * @param aDoc          The dom document interface being observed
-   * @param aRoot         This is the root of the editable section of this
-   *                      document. If it is null then we get root
-   *                      from document body.
-   * @param aSelCon       this should be used to get the selection location
-   *                      (will be null for HTML editors)
-   * @param aFlags        A bitmask of flags for specifying the behavior
-   *                      of the editor.
-   */
-  [noscript] void init(in nsIDOMDocument doc,
-                       in nsIContent aRoot,
-                       in nsISelectionController aSelCon,
-                       in unsigned long aFlags,
-                       in AString initialValue);
-
   void setAttributeOrEquivalent(in nsIDOMElement element,
                                 in AString sourceAttrName,
                                 in AString sourceAttrValue,
                                 in boolean aSuppressTransaction);
   void removeAttributeOrEquivalent(in nsIDOMElement element,
                                    in DOMString sourceAttrName,
                                    in boolean aSuppressTransaction);
 
@@ -474,22 +447,16 @@ interface nsIEditor  : nsISupports
 
   /**
    * deleteNode removes aChild from aParent.
    * @param aChild    The node to delete
    */
   void deleteNode(in nsIDOMNode child);
 
   /**
-   * Returns true if markNodeDirty() has any effect.  Returns false if
-   * markNodeDirty() is a no-op.
-   */
-  [notxpcom] boolean outputsMozDirty();
-
-  /**
    * markNodeDirty() sets a special dirty attribute on the node.
    * Usually this will be called immediately after creating a new node.
    * @param aNode      The node for which to insert formatting.
    */
   void markNodeDirty(in nsIDOMNode node);
 
 /* ---------- direction controller ---------- */
 
@@ -545,40 +512,25 @@ interface nsIEditor  : nsISupports
   void dumpContentTree();
 
   /** Dumps a text representation of the content tree to standard out */
   void debugDumpContent() ;
 
   /* Run unit tests. Noop in optimized builds */
   void debugUnitTests(out long outNumTests, out long  outNumTestsFailed);
 
-  /* checks if a node is read-only or not */
-  [notxpcom] boolean isModifiableNode(in nsIDOMNode aNode);
-
   /* Set true if you want to suppress dispatching input event. */
   attribute boolean suppressDispatchingInputEvent;
 
   /**
-   * True if an edit action is being handled (in other words, between calls of
-   * nsIEditorObserver::BeforeEditAction() and nsIEditorObserver::EditAction()
-   * or nsIEditorObserver::CancelEditAction().  Otherwise, false.
-   */
-  [noscript] readonly attribute boolean isInEditAction;
-
-  /**
    * forceCompositionEnd() force the composition end
    */
   void forceCompositionEnd();
 
   /**
-   * Get preferred IME status of current widget.
-   */
-  [noscript] IMEState getPreferredIMEState();
-
-  /**
    * whether this editor has active IME transaction
    */
   readonly attribute boolean composing;
 
 %{C++
   /**
    * AsEditorBase() returns a pointer to EditorBase class.
    *
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -355,16 +355,17 @@ DrawTargetRecording::FillGlyphs(ScaledFo
 	  if (fontDesc.IsValid()) {
 	    mRecorder->RecordEvent(fontDesc);
 	  } else {
 	    gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise UnscaledFont";
 	  }
 	}
 	mRecorder->AddStoredObject(unscaledFont);
       }
+      mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, unscaledFont));
     }
     RecordingFontUserData *userData = new RecordingFontUserData;
     userData->refPtr = aFont;
     userData->recorder = mRecorder;
     aFont->AddUserData(userDataKey, userData, &RecordingFontUserDataDestroyFunc);
     userData->recorder->AddScaledFont(aFont);
   }
 
--- a/gfx/layers/wr/ScrollingLayersHelper.cpp
+++ b/gfx/layers/wr/ScrollingLayersHelper.cpp
@@ -119,48 +119,49 @@ ScrollingLayersHelper::BeginItem(nsDispl
   // generated while processing aItem. However those display items only care
   // about the topmost clip on the stack. If that were all we cared about we
   // would only need to push one thing here and we would be done. However, we
   // also care about the ScrollingLayersHelper instance that might be created
   // for nested display items, in the case where aItem is a wrapper item. The
   // nested ScrollingLayersHelper may rely on things like TopmostScrollId and
   // TopmostClipId, so now we need to push at most two things onto the stack.
 
-  Maybe<wr::WrScrollId> leafmostId = ids.first;
+  wr::WrScrollId rootId = wr::WrScrollId { 0 };
+  wr::WrScrollId leafmostId = ids.first.valueOr(rootId);
+
   FrameMetrics::ViewID viewId = aItem->GetActiveScrolledRoot()
       ? aItem->GetActiveScrolledRoot()->GetViewId()
       : FrameMetrics::NULL_SCROLL_ID;
-  Maybe<wr::WrScrollId> scrollId =
-      mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
-  MOZ_ASSERT(scrollId.isSome());
+  wr::WrScrollId scrollId =
+      mBuilder->GetScrollIdForDefinedScrollLayer(viewId).valueOr(rootId);
 
   // If the leafmost ASR is not the same as the item's ASR then we are dealing
   // with a case where the item's clip chain is scrolled by something other than
   // the item's ASR. So for those cases we need to use the ClipAndScroll API.
   bool needClipAndScroll = (leafmostId != scrollId);
 
   // The other scenario where we need to push a ClipAndScroll is when we are
   // in a nested display item where the enclosing item pushed a ClipAndScroll,
   // and our clip chain extends from that item's clip chain. To check this we
   // want to make sure that (a) we are inside a ClipAndScroll, and (b) nothing
   // else was pushed onto mBuilder's stack since that ClipAndScroll.
   if (!needClipAndScroll &&
       mBuilder->TopmostScrollId() == scrollId &&
       !mBuilder->TopmostIsClip()) {
     if (auto cs = EnclosingClipAndScroll()) {
-      MOZ_ASSERT(cs->first == *scrollId);
+      MOZ_ASSERT(cs->first == scrollId);
       needClipAndScroll = true;
     }
   }
 
   // If we don't need a ClipAndScroll, ensure the item's ASR is at the top of
   // the scroll stack
   if (!needClipAndScroll && mBuilder->TopmostScrollId() != scrollId) {
     MOZ_ASSERT(leafmostId == scrollId); // because !needClipAndScroll
-    clips.mScrollId = scrollId;
+    clips.mScrollId = Some(scrollId);
   }
   // And ensure the leafmost clip, if scrolled by that ASR, is at the top of the
   // stack.
   if (ids.second && clip->mASR == leafmostASR) {
     clips.mClipId = ids.second;
   }
   // If we need the ClipAndScroll, we want to replace the topmost scroll layer
   // with the item's ASR but preseve the topmost clip (which is scrolled by
@@ -169,17 +170,17 @@ ScrollingLayersHelper::BeginItem(nsDispl
     // If mClipId is set that means we want to push it such that it's going
     // to be the TopmostClipId(), but we haven't actually pushed it yet.
     // But we still want to take that instead of the actual current TopmostClipId().
     Maybe<wr::WrClipId> clipId = clips.mClipId;
     if (!clipId) {
       clipId = mBuilder->TopmostClipId();
     }
 
-    clips.mClipAndScroll = Some(std::make_pair(*scrollId, clipId));
+    clips.mClipAndScroll = Some(std::make_pair(scrollId, clipId));
   }
 
   clips.Apply(mBuilder);
   mItemClipStack.push_back(clips);
 
   SLH_LOG("done setup for %p\n", aItem);
 }
 
@@ -294,17 +295,19 @@ ScrollingLayersHelper::RecurseAndDefineC
       // But if the ASRs are different, this is the outermost clip that's
       // still inside aAsr, and we need to make it a child of aAsr rather
       // than aChain->mParent.
       ancestorIds.second = Nothing();
     }
   } else {
     MOZ_ASSERT(!ancestorIds.second);
     FrameMetrics::ViewID viewId = aChain->mASR ? aChain->mASR->GetViewId() : FrameMetrics::NULL_SCROLL_ID;
-    auto scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId);
+
+    wr::WrScrollId rootId = wr::WrScrollId { 0 };
+    auto scrollId = mBuilder->GetScrollIdForDefinedScrollLayer(viewId).valueOr(rootId);
     if (mBuilder->TopmostScrollId() == scrollId) {
       if (mBuilder->TopmostIsClip()) {
         // If aChain->mASR is already the topmost scroll layer on the stack, but
         // but there was another clip pushed *on top* of that ASR, then that clip
         // shares the ASR, and we need to make our clip a child of that clip, which
         // in turn will already be a descendant of the correct ASR.
         // This covers the cases where e.g. the Gecko display list has nested items,
         // and the clip chain on the nested item implicitly extends from the clip
@@ -323,17 +326,17 @@ ScrollingLayersHelper::RecurseAndDefineC
         // item had a clip scrolled by a different ASR than the item itself),
         // then we have need to propagate that behaviour as well. For example if
         // the enclosing display item pushed a ClipAndScroll with (scrollid=S,
         // clipid=C), then then clip we're defining here (call it D) needs to be
         // defined as a child of C, and we'll need to push the ClipAndScroll
         // (S, D) for this item. This hunk of code ensures that we define D
         // as a child of C, and when we set the needClipAndScroll flag elsewhere
         // in this file we make sure to set it for this scenario.
-        MOZ_ASSERT(Some(cs->first) == scrollId);
+        MOZ_ASSERT(cs->first == scrollId);
         ancestorIds.first = Nothing();
         ancestorIds.second = cs->second;
       }
     }
   }
   // At most one of the ancestor pair should be defined here, and the one that
   // is defined will be the parent clip for the new clip that we're defining.
   MOZ_ASSERT(!(ancestorIds.first && ancestorIds.second));
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -17,16 +17,20 @@
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/UpdateImageHelper.h"
 #include "nsDisplayList.h"
 #include "WebRenderCanvasRenderer.h"
 
+#ifdef XP_WIN
+#include "gfxDWriteFonts.h"
+#endif
+
 // Useful for debugging, it dumps the Gecko display list *before* we try to
 // build WR commands from it, and dumps the WR display list after building it.
 #define DUMP_LISTS 0
 
 namespace mozilla {
 
 using namespace gfx;
 
@@ -253,16 +257,20 @@ WebRenderLayerManager::EndTransactionWit
   AUTO_PROFILER_TRACING("Paint", "RenderLayers");
 
 #if DUMP_LISTS
   // Useful for debugging, it dumps the display list *before* we try to build
   // WR commands from it
   if (XRE_IsContentProcess()) nsFrame::PrintDisplayList(aDisplayListBuilder, *aDisplayList);
 #endif
 
+#ifdef XP_WIN
+  gfxDWriteFont::UpdateClearTypeUsage();
+#endif
+
   // Since we don't do repeat transactions right now, just set the time
   mAnimationReadyTime = TimeStamp::Now();
 
   WrBridge()->BeginTransaction();
   DiscardCompositorAnimations();
 
   LayoutDeviceIntSize size = mWidget->GetClientSize();
   wr::LayoutSize contentSize { (float)size.width, (float)size.height };
new file mode 100644
--- /dev/null
+++ b/gfx/tests/reftest/1435143-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+    #green {
+        position: absolute;
+        background: green;
+        border-radius: 1px;
+        transform: translateX(100px);
+    }
+    #text {
+        visibility: hidden;
+    }
+    </style>
+  </head>
+
+  <body>
+    <div id="header">
+      <div id="green"><span id="text">Text.</span></div>
+    </div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/gfx/tests/reftest/1435143.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+    #header {
+        position: fixed;
+    }
+    #green {
+        position: absolute;
+        background: green;
+        border-radius: 1px;
+        transform: translateX(100px);
+    }
+    #text {
+        visibility: hidden;
+    }
+    </style>
+  </head>
+
+  <body>
+    <div id="header">
+      <div id="green"><span id="text">Text.</span></div>
+    </div>
+  </body>
+</html>
+
--- a/gfx/tests/reftest/reftest.list
+++ b/gfx/tests/reftest/reftest.list
@@ -5,8 +5,9 @@ fuzzy-if(Android,8,1000) == 709477-1.htm
 skip-if(!asyncPan) == 1086723.html 1086723-ref.html
 == 853889-1.html 853889-1-ref.html
 skip-if(Android) fuzzy-if(skiaContent,1,587) == 1143303-1.svg pass.svg
 fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius
 == 1131264-1.svg pass.svg
 == 1419528.html 1419528-ref.html
 == 1424673.html 1424673-ref.html
 == 1429411.html 1429411-ref.html
+== 1435143.html 1435143-ref.html
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1306,25 +1306,25 @@ DisplayListBuilder::TopmostClipId()
   for (auto it = mClipStack.crbegin(); it != mClipStack.crend(); it++) {
     if (it->is<wr::WrClipId>()) {
       return Some(it->as<wr::WrClipId>());
     }
   }
   return Nothing();
 }
 
-Maybe<wr::WrScrollId>
+wr::WrScrollId
 DisplayListBuilder::TopmostScrollId()
 {
   for (auto it = mClipStack.crbegin(); it != mClipStack.crend(); it++) {
     if (it->is<wr::WrScrollId>()) {
-      return Some(it->as<wr::WrScrollId>());
+      return it->as<wr::WrScrollId>();
     }
   }
-  return Nothing();
+  return wr::WrScrollId { 0 };
 }
 
 bool
 DisplayListBuilder::TopmostIsClip()
 {
   if (mClipStack.empty()) {
     return false;
   }
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -430,17 +430,17 @@ public:
                      const wr::BorderRadius& aBorderRadius,
                      const wr::BoxShadowClipMode& aClipMode);
 
   // Returns the clip id that was most recently pushed with PushClip and that
   // has not yet been popped with PopClip. Return Nothing() if the clip stack
   // is empty.
   Maybe<wr::WrClipId> TopmostClipId();
   // Same as TopmostClipId() but for scroll layers.
-  Maybe<wr::WrScrollId> TopmostScrollId();
+  wr::WrScrollId TopmostScrollId();
   // If the topmost item on the stack is a clip or a scroll layer
   bool TopmostIsClip();
 
   // Set the hit-test info to be used for all display items until the next call
   // to SetHitTestInfo or ClearHitTestInfo.
   void SetHitTestInfo(const layers::FrameMetrics::ViewID& aScrollId,
                       gfx::CompositorHitTestInfo aHitInfo);
   // Clears the hit-test info so that subsequent display items will not have it.
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -766,16 +766,20 @@ struct WrClipId {
 // Corresponds to a clip id for for a scroll frame in webrender. Similar
 // to WrClipId but a separate struct so we don't get them mixed up in C++.
 struct WrScrollId {
   uint64_t id;
 
   bool operator==(const WrScrollId& other) const {
     return id == other.id;
   }
+
+  bool operator!=(const WrScrollId& other) const {
+    return id != other.id;
+  }
 };
 
 // Corresponds to a clip id for a position:sticky clip in webrender. Similar
 // to WrClipId but a separate struct so we don't get them mixed up in C++.
 struct WrStickyId {
   uint64_t id;
 
   bool operator==(const WrStickyId& other) const {
--- a/image/DecodedSurfaceProvider.cpp
+++ b/image/DecodedSurfaceProvider.cpp
@@ -117,17 +117,17 @@ DecodedSurfaceProvider::SetLocked(bool a
                      : DrawableFrameRef();
 }
 
 size_t
 DecodedSurfaceProvider::LogicalSizeInBytes() const
 {
   // Single frame images are always 32bpp.
   IntSize size = GetSurfaceKey().Size();
-  return size.width * size.height * sizeof(uint32_t);
+  return size_t(size.width) * size_t(size.height) * sizeof(uint32_t);
 }
 
 void
 DecodedSurfaceProvider::Run()
 {
   MutexAutoLock lock(mMutex);
 
   if (!mDecoder || !mImage) {
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -875,17 +875,18 @@ nsGIFDecoder2::FinishImageDescriptor(con
   const bool isInterlaced = packedFields & PACKED_FIELDS_INTERLACED_BIT;
 
   // Create the SurfacePipe we'll use to write output for this frame.
   if (NS_FAILED(BeginImageFrame(frameRect, realDepth, isInterlaced))) {
     return Transition::TerminateFailure();
   }
 
   // Clear state from last image.
-  mGIFStruct.pixels_remaining = frameRect.Width() * frameRect.Height();
+  mGIFStruct.pixels_remaining =
+    int64_t(frameRect.Width()) * int64_t(frameRect.Height());
 
   if (haveLocalColorTable) {
     // We have a local color table, so prepare to read it into the palette of
     // the current frame.
     mGIFStruct.local_colormap_size = 1 << depth;
 
     if (mGIFStruct.images_decoded == 0) {
       // The first frame has a local color table. Allocate space for it as we
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -473,16 +473,24 @@ BaselineCacheIRCompiler::emitGuardFuncti
     masm.branchPtr(Assembler::NotEqual,
                    prototypeObject,
                    scratch1, failure->label());
 
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitLoadValueResult()
+{
+    AutoOutputRegister output(*this);
+    masm.loadValue(stubAddress(reader.stubOffset()), output.valueReg());
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitLoadFixedSlotResult()
 {
     AutoOutputRegister output(*this);
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
 
     masm.load32(stubAddress(reader.stubOffset()), scratch);
     masm.loadValue(BaseIndex(obj, scratch, TimesOne), output.valueReg());
@@ -2087,16 +2095,19 @@ BaselineCacheIRCompiler::init(CacheKind 
     size_t numInputs = writer_.numInputOperands();
 
     // Baseline passes the first 2 inputs in R0/R1, other Values are stored on
     // the stack.
     size_t numInputsInRegs = std::min(numInputs, size_t(2));
     AllocatableGeneralRegisterSet available(ICStubCompiler::availableGeneralRegs(numInputsInRegs));
 
     switch (kind) {
+      case CacheKind::GetIntrinsic:
+        MOZ_ASSERT(numInputs == 0);
+        break;
       case CacheKind::GetProp:
       case CacheKind::TypeOf:
       case CacheKind::GetIterator:
       case CacheKind::ToBool:
         MOZ_ASSERT(numInputs == 1);
         allocator.initInputLocation(0, R0);
         break;
       case CacheKind::Compare:
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1387,23 +1387,35 @@ DoGetIntrinsicFallback(JSContext* cx, Ba
     // directly.
 
     TypeScript::Monitor(cx, script, pc, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
-    JitSpew(JitSpew_BaselineIC, "  Generating GetIntrinsic optimized stub");
-    ICGetIntrinsic_Constant::Compiler compiler(cx, res);
-    ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
-    if (!newStub)
-        return false;
-
-    stub->addNewStub(newStub);
+    if (stub->state().maybeTransition())
+        stub->discardStubs(cx);
+
+    if (stub->state().canAttachStub()) {
+        bool attached = false;
+        RootedScript script(cx, frame->script());
+        GetIntrinsicIRGenerator gen(cx, script, pc, stub->state().mode(), res);
+        if (gen.tryAttachStub()) {
+            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
+                                                        BaselineCacheIRStubKind::Regular,
+                                                        ICStubEngine::Baseline, script, stub,
+                                                        &attached);
+            if (newStub)
+                JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
+        }
+        if (!attached)
+            stub->state().trackNotAttached();
+    }
+
     return true;
 }
 
 typedef bool (*DoGetIntrinsicFallbackFn)(JSContext*, BaselineFrame*, ICGetIntrinsic_Fallback*,
                                          MutableHandleValue);
 static const VMFunction DoGetIntrinsicFallbackInfo =
     FunctionInfo<DoGetIntrinsicFallbackFn>(DoGetIntrinsicFallback, "DoGetIntrinsicFallback",
                                            TailCall);
@@ -1416,27 +1428,16 @@ ICGetIntrinsic_Fallback::Compiler::gener
     EmitRestoreTailCallReg(masm);
 
     masm.push(ICStubReg);
     pushStubPayload(masm, R0.scratchReg());
 
     return tailCallVM(DoGetIntrinsicFallbackInfo, masm);
 }
 
-bool
-ICGetIntrinsic_Constant::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
-    masm.loadValue(Address(ICStubReg, ICGetIntrinsic_Constant::offsetOfValue()), R0);
-
-    EmitReturnFromIC(masm);
-    return true;
-}
-
 //
 // SetProp_Fallback
 //
 
 static bool
 DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_, Value* stack,
                   HandleValue lhs, HandleValue rhs)
 {
@@ -4377,24 +4378,16 @@ ICTypeUpdate_SingleObject::ICTypeUpdate_
     obj_(obj)
 { }
 
 ICTypeUpdate_ObjectGroup::ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGroup* group)
   : ICStub(TypeUpdate_ObjectGroup, stubCode),
     group_(group)
 { }
 
-ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value)
-  : ICStub(GetIntrinsic_Constant, stubCode),
-    value_(value)
-{ }
-
-ICGetIntrinsic_Constant::~ICGetIntrinsic_Constant()
-{ }
-
 ICCall_Scripted::ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
                                  JSFunction* callee, JSObject* templateObject,
                                  uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
     callee_(callee),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 { }
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -494,51 +494,16 @@ class ICGetIntrinsic_Fallback : public I
         { }
 
         ICStub* getStub(ICStubSpace* space) override {
             return newStub<ICGetIntrinsic_Fallback>(space, getStubCode());
         }
     };
 };
 
-// Stub that loads the constant result of a GETINTRINSIC operation.
-class ICGetIntrinsic_Constant : public ICStub
-{
-    friend class ICStubSpace;
-
-    GCPtrValue value_;
-
-    ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value);
-    ~ICGetIntrinsic_Constant();
-
-  public:
-    GCPtrValue& value() {
-        return value_;
-    }
-    static size_t offsetOfValue() {
-        return offsetof(ICGetIntrinsic_Constant, value_);
-    }
-
-    class Compiler : public ICStubCompiler {
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-        HandleValue value_;
-
-      public:
-        Compiler(JSContext* cx, HandleValue value)
-          : ICStubCompiler(cx, ICStub::GetIntrinsic_Constant, Engine::Baseline),
-            value_(value)
-        {}
-
-        ICStub* getStub(ICStubSpace* space) override {
-            return newStub<ICGetIntrinsic_Constant>(space, getStubCode(), value_);
-        }
-    };
-};
-
 // SetProp
 //     JSOP_SETPROP
 //     JSOP_SETNAME
 //     JSOP_SETGNAME
 //     JSOP_INITPROP
 
 class ICSetProp_Fallback : public ICFallbackStub
 {
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -51,17 +51,16 @@ namespace jit {
     _(In_Fallback)                               \
     _(HasOwn_Fallback)                           \
                                                  \
     _(GetName_Fallback)                          \
                                                  \
     _(BindName_Fallback)                         \
                                                  \
     _(GetIntrinsic_Fallback)                     \
-    _(GetIntrinsic_Constant)                     \
                                                  \
     _(SetProp_Fallback)                          \
                                                  \
     _(TableSwitch)                               \
                                                  \
     _(GetIterator_Fallback)                      \
     _(IteratorMore_Fallback)                     \
     _(IteratorMore_Native)                       \
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -4827,9 +4827,53 @@ ToBoolIRGenerator::tryAttachObject()
         return false;
 
     ValOperandId valId(writer.setInputOperandId(0));
     ObjOperandId objId = writer.guardIsObject(valId);
     writer.loadObjectTruthyResult(objId);
     writer.returnFromIC();
     trackAttached("ToBoolObject");
     return true;
+}
+
+GetIntrinsicIRGenerator::GetIntrinsicIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode,
+                                                 HandleValue val)
+  : IRGenerator(cx, script, pc, CacheKind::GetIntrinsic, mode)
+  , val_(val)
+{}
+
+void
+GetIntrinsicIRGenerator::trackAttached(const char* name)
+{
+#ifdef JS_CACHEIR_SPEW
+    CacheIRSpewer& sp = CacheIRSpewer::singleton();
+    if (sp.enabled()) {
+        LockGuard<Mutex> guard(sp.lock());
+        sp.beginCache(guard, *this);
+        sp.valueProperty(guard, "val", val_);
+        sp.attached(guard, name);
+        sp.endCache(guard);
+    }
+#endif
+}
+
+void
+GetIntrinsicIRGenerator::trackNotAttached()
+{
+#ifdef JS_CACHEIR_SPEW
+    CacheIRSpewer& sp = CacheIRSpewer::singleton();
+    if (sp.enabled()) {
+        LockGuard<Mutex> guard(sp.lock());
+        sp.beginCache(guard, *this);
+        sp.valueProperty(guard, "val", val_);
+        sp.endCache(guard);
+    }
+#endif
+}
+
+bool
+GetIntrinsicIRGenerator::tryAttachStub()
+{
+    writer.loadValueResult(val_);
+    writer.returnFromIC();
+    trackAttached("GetIntrinsic");
+    return true;
 }
\ No newline at end of file
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -137,16 +137,17 @@ class TypedOperandId : public OperandId
 };
 
 #define CACHE_IR_KINDS(_)   \
     _(GetProp)              \
     _(GetElem)              \
     _(GetName)              \
     _(GetPropSuper)         \
     _(GetElemSuper)         \
+    _(GetIntrinsic)         \
     _(SetProp)              \
     _(SetElem)              \
     _(BindName)             \
     _(In)                   \
     _(HasOwn)               \
     _(TypeOf)               \
     _(InstanceOf)           \
     _(GetIterator)          \
@@ -270,16 +271,17 @@ extern const char* CacheKindNames[];
     _(LoadBooleanResult)                  \
     _(LoadStringResult)                   \
     _(LoadInstanceOfObjectResult)         \
     _(LoadTypeOfObjectResult)             \
     _(LoadInt32TruthyResult)              \
     _(LoadDoubleTruthyResult)             \
     _(LoadStringTruthyResult)             \
     _(LoadObjectTruthyResult)             \
+    _(LoadValueResult)                    \
                                           \
     _(CallStringSplitResult)              \
                                           \
     _(CompareStringResult)                \
     _(CompareObjectResult)                \
     _(CompareSymbolResult)                \
                                           \
     _(CallPrintString)                    \
@@ -1029,16 +1031,20 @@ class MOZ_RAII CacheIRWriter : public JS
         writeOpWithOperandId(CacheOp::LoadDoubleTruthyResult, dbl);
     }
     void loadStringTruthyResult(StringOperandId str) {
         writeOpWithOperandId(CacheOp::LoadStringTruthyResult, str);
     }
     void loadObjectTruthyResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadObjectTruthyResult, obj);
     }
+    void loadValueResult(const Value& val) {
+        writeOp(CacheOp::LoadValueResult);
+        addStubField(val.asRawBits(), StubField::Type::Value);
+    }
     void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) {
         writeOp(CacheOp::CallStringSplitResult);
         writeOperandId(str);
         writeOperandId(sep);
         addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
     }
 
     void compareStringResult(uint32_t op, StringOperandId lhs, StringOperandId rhs) {
@@ -1637,12 +1643,26 @@ class MOZ_RAII ToBoolIRGenerator : publi
 
   public:
     ToBoolIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
                       HandleValue val);
 
     bool tryAttachStub();
 };
 
+class MOZ_RAII GetIntrinsicIRGenerator : public IRGenerator
+{
+    HandleValue val_;
+
+    void trackAttached(const char* name);
+    void trackNotAttached();
+
+  public:
+    GetIntrinsicIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode,
+                            HandleValue val);
+
+    bool tryAttachStub();
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_CacheIR_h */
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -354,16 +354,17 @@ CodeGenerator::visitOutOfLineICFallback(
 
         masm.jump(ool->rejoin());
         return;
       }
       case CacheKind::Call:
       case CacheKind::Compare:
       case CacheKind::TypeOf:
       case CacheKind::ToBool:
+      case CacheKind::GetIntrinsic:
         MOZ_CRASH("Unsupported IC");
     }
     MOZ_CRASH();
 }
 
 StringObject*
 MNewStringObject::templateObj() const
 {
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -542,16 +542,17 @@ IonCacheIRCompiler::init()
         allocator.initInputLocation(1, TypedOrValueRegister(MIRType::Object,
                                                             AnyRegister(ic->rhs())));
         break;
       }
       case CacheKind::Call:
       case CacheKind::Compare:
       case CacheKind::TypeOf:
       case CacheKind::ToBool:
+      case CacheKind::GetIntrinsic:
         MOZ_CRASH("Unsupported IC");
     }
 
     if (liveRegs_)
         liveFloatRegs_ = LiveFloatRegisterSet(liveRegs_->fpus());
 
     allocator.initAvailableRegs(available);
     allocator.initAvailableRegsAfterSpill();
@@ -883,16 +884,23 @@ IonCacheIRCompiler::emitGuardFunctionPro
     masm.branchPtr(Assembler::NotEqual,
                    prototypeObject,
                    scratch1, failure->label());
 
     return true;
 }
 
 bool
+IonCacheIRCompiler::emitLoadValueResult()
+{
+   MOZ_CRASH("Baseline-specific op");
+}
+
+
+bool
 IonCacheIRCompiler::emitLoadFixedSlotResult()
 {
     AutoOutputRegister output(*this);
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     int32_t offset = int32StubField(reader.stubOffset());
     masm.loadTypedOrValue(Address(obj, offset), output);
     return true;
 }
--- a/js/src/jit/IonIC.cpp
+++ b/js/src/jit/IonIC.cpp
@@ -59,16 +59,17 @@ IonIC::scratchRegisterForEntryJump()
       case CacheKind::GetIterator:
         return asGetIteratorIC()->temp1();
       case CacheKind::InstanceOf:
         return asInstanceOfIC()->output();
       case CacheKind::Call:
       case CacheKind::Compare:
       case CacheKind::TypeOf:
       case CacheKind::ToBool:
+      case CacheKind::GetIntrinsic:
         MOZ_CRASH("Unsupported IC");
     }
 
     MOZ_CRASH("Invalid kind");
 }
 
 void
 IonIC::discardStubs(Zone* zone)
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -287,21 +287,16 @@ ICStub::trace(JSTracer* trc)
         TraceEdge(trc, &updateStub->object(), "baseline-update-singleton");
         break;
       }
       case ICStub::TypeUpdate_ObjectGroup: {
         ICTypeUpdate_ObjectGroup* updateStub = toTypeUpdate_ObjectGroup();
         TraceEdge(trc, &updateStub->group(), "baseline-update-group");
         break;
       }
-      case ICStub::GetIntrinsic_Constant: {
-        ICGetIntrinsic_Constant* constantStub = toGetIntrinsic_Constant();
-        TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
-        break;
-      }
       case ICStub::NewArray_Fallback: {
         ICNewArray_Fallback* stub = toNewArray_Fallback();
         TraceNullableEdge(trc, &stub->templateObject(), "baseline-newarray-template");
         TraceEdge(trc, &stub->templateGroup(), "baseline-newarray-template-group");
         break;
       }
       case ICStub::NewObject_Fallback: {
         ICNewObject_Fallback* stub = toNewObject_Fallback();
--- a/js/src/jit/arm64/vixl/MacroAssembler-vixl.cpp
+++ b/js/src/jit/arm64/vixl/MacroAssembler-vixl.cpp
@@ -422,17 +422,21 @@ void MacroAssembler::LogicalMacro(const 
 
     unsigned n, imm_s, imm_r;
     if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
       // Immediate can be encoded in the instruction.
       LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
     } else {
       // Immediate can't be encoded: synthesize using move immediate.
       Register temp = temps.AcquireSameSizeAs(rn);
-      Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
+
+      // If the left-hand input is the stack pointer, we can't pre-shift the
+      // immediate, as the encoding won't allow the subsequent post shift.
+      PreShiftImmMode mode = rn.IsSP() ? kNoShift : kAnyShift;
+      Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate, mode);
 
       // VIXL can acquire temp registers. Assert that the caller is aware.
       VIXL_ASSERT(!temp.Is(rd) && !temp.Is(rn));
       VIXL_ASSERT(!temp.Is(operand.maybeReg()));
 
       if (rd.Is(sp)) {
         // If rd is the stack pointer we cannot use it as the destination
         // register so we use the temp register as an intermediate again.
@@ -960,37 +964,46 @@ void MacroAssembler::Negs(const Register
 
 bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
                                               int64_t imm) {
   return OneInstrMoveImmediateHelper(this, dst, imm);
 }
 
 
 Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
-                                                  int64_t imm) {
+                                                  int64_t imm,
+                                                  PreShiftImmMode mode) {
   int reg_size = dst.size();
 
   // Encode the immediate in a single move instruction, if possible.
   if (TryOneInstrMoveImmediate(dst, imm)) {
     // The move was successful; nothing to do here.
   } else {
     // Pre-shift the immediate to the least-significant bits of the register.
     int shift_low = CountTrailingZeros(imm, reg_size);
+    if (mode == kLimitShiftForSP) {
+      // When applied to the stack pointer, the subsequent arithmetic operation
+      // can use the extend form to shift left by a maximum of four bits. Right
+      // shifts are not allowed, so we filter them out later before the new
+      // immediate is tested.
+      shift_low = std::min(shift_low, 4);
+    }
+
     int64_t imm_low = imm >> shift_low;
 
     // Pre-shift the immediate to the most-significant bits of the register,
     // inserting set bits in the least-significant bits.
     int shift_high = CountLeadingZeros(imm, reg_size);
     int64_t imm_high = (imm << shift_high) | ((INT64_C(1) << shift_high) - 1);
 
-    if (TryOneInstrMoveImmediate(dst, imm_low)) {
+    if ((mode != kNoShift) && TryOneInstrMoveImmediate(dst, imm_low)) {
       // The new immediate has been moved into the destination's low bits:
       // return a new leftward-shifting operand.
       return Operand(dst, LSL, shift_low);
-    } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
+    } else if ((mode == kAnyShift) && TryOneInstrMoveImmediate(dst, imm_high)) {
       // The new immediate has been moved into the destination's high bits:
       // return a new rightward-shifting operand.
       return Operand(dst, LSR, shift_high);
     } else {
       Mov(dst, imm);
     }
   }
   return Operand(dst);
@@ -1032,29 +1045,37 @@ void MacroAssembler::AddSubMacro(const R
 
   if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
       (S == LeaveFlags)) {
     // The instruction would be a nop. Avoid generating useless code.
     return;
   }
 
   if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) ||
-      (rn.IsZero() && !operand.IsShiftedRegister())                ||
+      (rn.IsZero() && !operand.IsShiftedRegister()) ||
       (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
     UseScratchRegisterScope temps(this);
     Register temp = temps.AcquireSameSizeAs(rn);
-
-    // VIXL can acquire temp registers. Assert that the caller is aware.
-    VIXL_ASSERT(!temp.Is(rd) && !temp.Is(rn));
-    VIXL_ASSERT(!temp.Is(operand.maybeReg()));
+    if (operand.IsImmediate()) {
+      PreShiftImmMode mode = kAnyShift;
 
-    if (operand.IsImmediate()) {
+      // If the destination or source register is the stack pointer, we can
+      // only pre-shift the immediate right by values supported in the add/sub
+      // extend encoding.
+      if (rd.IsSP()) {
+        // If the destination is SP and flags will be set, we can't pre-shift
+        // the immediate at all. 
+        mode = (S == SetFlags) ? kNoShift : kLimitShiftForSP;
+      } else if (rn.IsSP()) {
+        mode = kLimitShiftForSP;
+      } 
+
       Operand imm_operand =
-          MoveImmediateForShiftedOp(temp, operand.immediate());
-      AddSub(rd, rn, imm_operand, S, op);
+          MoveImmediateForShiftedOp(temp, operand.immediate(), mode);
+      AddSub(rd, rn, imm_operand, S, op); 
     } else {
       Mov(temp, operand);
       AddSub(rd, rn, temp, S, op);
     }
   } else {
     AddSub(rd, rn, operand, S, op);
   }
 }
--- a/js/src/jit/arm64/vixl/MacroAssembler-vixl.h
+++ b/js/src/jit/arm64/vixl/MacroAssembler-vixl.h
@@ -137,16 +137,31 @@ enum BranchType {
   kBranchTypeLastCondition = nv,
   kBranchTypeFirstUsingReg = reg_zero,
   kBranchTypeFirstUsingBit = reg_bit_clear
 };
 
 
 enum DiscardMoveMode { kDontDiscardForSameWReg, kDiscardForSameWReg };
 
+// The macro assembler supports moving automatically pre-shifted immediates for
+// arithmetic and logical instructions, and then applying a post shift in the
+// instruction to undo the modification, in order to reduce the code emitted for
+// an operation. For example:
+//
+//  Add(x0, x0, 0x1f7de) => movz x16, 0xfbef; add x0, x0, x16, lsl #1.
+//
+// This optimisation can be only partially applied when the stack pointer is an
+// operand or destination, so this enumeration is used to control the shift.
+enum PreShiftImmMode {
+  kNoShift,          // Don't pre-shift.
+  kLimitShiftForSP,  // Limit pre-shift for add/sub extend use.
+  kAnyShift          // Allow any pre-shift.
+};
+
 
 class MacroAssembler : public js::jit::Assembler {
  public:
   MacroAssembler();
 
   // Finalize a code buffer of generated instructions. This function must be
   // called before executing or copying code from the buffer.
   void FinalizeCode();
@@ -267,17 +282,19 @@ class MacroAssembler : public js::jit::A
   // Returns false, otherwise.
   bool TryOneInstrMoveImmediate(const Register& dst, int64_t imm);
 
   // Move an immediate into register dst, and return an Operand object for
   // use with a subsequent instruction that accepts a shift. The value moved
   // into dst is not necessarily equal to imm; it may have had a shifting
   // operation applied to it that will be subsequently undone by the shift
   // applied in the Operand.
-  Operand MoveImmediateForShiftedOp(const Register& dst, int64_t imm);
+  Operand MoveImmediateForShiftedOp(const Register& dst,
+		                    int64_t imm,
+				    PreShiftImmMode mode);
 
   // Synthesises the address represented by a MemOperand into a register.
   void ComputeAddress(const Register& dst, const MemOperand& mem_op);
 
   // Conditional macros.
   void Ccmp(const Register& rn,
             const Operand& operand,
             StatusFlags nzcv,
--- a/js/src/wasm/WasmFrameIter.cpp
+++ b/js/src/wasm/WasmFrameIter.cpp
@@ -272,48 +272,34 @@ static const unsigned PoppedTLSReg = 0;
 static const unsigned BeforePushRetAddr = 0;
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedTLS = 1;
 static const unsigned PushedFP = 1;
 static const unsigned SetFP = 0;
 static const unsigned PoppedFP = 0;
 static const unsigned PoppedTLSReg = 0;
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-static const unsigned BeforePushRetAddr = 0;
 static const unsigned PushedRetAddr = 8;
-static const unsigned PushedTLS = 16;
-static const unsigned PushedFP = 24;
-static const unsigned SetFP = 28;
-static const unsigned PoppedFP = 16;
-static const unsigned PoppedTLSReg = 8;
+static const unsigned PushedTLS = 12;
+static const unsigned PushedFP = 16;
+static const unsigned SetFP = 20;
+static const unsigned PoppedFP = 8;
+static const unsigned PoppedTLSReg = 4;
 #elif defined(JS_CODEGEN_NONE)
 // Synthetic values to satisfy asserts and avoid compiler warnings.
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedTLS = 1;
 static const unsigned PushedFP = 2;
 static const unsigned SetFP = 3;
 static const unsigned PoppedFP = 4;
 static const unsigned PoppedTLSReg = 5;
 #else
 # error "Unknown architecture!"
 #endif
 
-static void
-PushRetAddr(MacroAssembler& masm, unsigned entry)
-{
-#if defined(JS_CODEGEN_ARM)
-    MOZ_ASSERT(masm.currentOffset() - entry == BeforePushRetAddr);
-    masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-    MOZ_ASSERT(masm.currentOffset() - entry == BeforePushRetAddr);
-    masm.push(ra);
-#else
-    // The x86/x64 call instruction pushes the return address.
-#endif
-}
 
 static void
 LoadActivation(MacroAssembler& masm, const Register& dest)
 {
     // WasmCall pushes a JitActivation.
     masm.loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest);
     masm.loadPtr(Address(dest, JSContext::offsetOfActivation()), dest);
 }
@@ -345,32 +331,51 @@ static void
 GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                          uint32_t* entry, uint32_t* tierEntry, CompileMode mode, uint32_t funcIndex)
 {
     // ProfilingFrameIterator needs to know the offsets of several key
     // instructions from entry. To save space, we make these offsets static
     // constants and assert that they match the actual codegen below. On ARM,
     // this requires AutoForbidPools to prevent a constant pool from being
     // randomly inserted between two instructions.
-    {
-#if defined(JS_CODEGEN_ARM)
-        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 7);
-#endif
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
         *entry = masm.currentOffset();
 
-        PushRetAddr(masm, *entry);
+        masm.subFromStackPtr(Imm32(sizeof(Frame)));
+        masm.storePtr(ra, Address(StackPointer, offsetof(Frame, returnAddress)));
+        MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry);
+        masm.storePtr(WasmTlsReg, Address(StackPointer, offsetof(Frame, tls)));
+        MOZ_ASSERT_IF(!masm.oom(), PushedTLS == masm.currentOffset() - *entry);
+        masm.storePtr(FramePointer, Address(StackPointer, offsetof(Frame, callerFP)));
+        MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
+        masm.moveStackPtrTo(FramePointer);
+        MOZ_ASSERT_IF(!masm.oom(), SetFP == masm.currentOffset() - *entry);
+#else
+    {
+# if defined(JS_CODEGEN_ARM)
+        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 7);
+
+        *entry = masm.currentOffset();
+
+        MOZ_ASSERT(BeforePushRetAddr == 0);
+        masm.push(lr);
+# else
+        *entry = masm.currentOffset();
+        // The x86/x64 call instruction pushes the return address.
+# endif
+
         MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry);
         masm.push(WasmTlsReg);
         MOZ_ASSERT_IF(!masm.oom(), PushedTLS == masm.currentOffset() - *entry);
         masm.push(FramePointer);
         MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
         masm.moveStackPtrTo(FramePointer);
         MOZ_ASSERT_IF(!masm.oom(), SetFP == masm.currentOffset() - *entry);
     }
-
+#endif
     // Tiering works as follows.  The Code owns a jumpTable, which has one
     // pointer-sized element for each function up to the largest funcIndex in
     // the module.  Each table element is an address into the Tier-1 or the
     // Tier-2 function at that index; the elements are updated when Tier-2 code
     // becomes available.  The Tier-1 function will unconditionally jump to this
     // address.  The table elements are written racily but without tearing when
     // Tier-2 compilation is finished.
     //
@@ -404,41 +409,53 @@ GenerateCallableEpilogue(MacroAssembler&
                          uint32_t* ret)
 {
     if (framePushed)
         masm.addToStackPtr(Imm32(framePushed));
 
     if (!reason.isNone())
         ClearExitFP(masm, ABINonArgReturnVolatileReg);
 
+    DebugOnly<uint32_t> poppedFP;
+    DebugOnly<uint32_t> poppedTlsReg;
+
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+
+    masm.loadPtr(Address(StackPointer, offsetof(Frame, callerFP)), FramePointer);
+    poppedFP = masm.currentOffset();
+    masm.loadPtr(Address(StackPointer, offsetof(Frame, tls)), WasmTlsReg);
+    poppedTlsReg = masm.currentOffset();
+    masm.loadPtr(Address(StackPointer, offsetof(Frame, returnAddress)), ra);
+
+    *ret = masm.currentOffset();
+    masm.as_jr(ra);
+    masm.addToStackPtr(Imm32(sizeof(Frame)));
+
+#else
     // Forbid pools for the same reason as described in GenerateCallablePrologue.
-#if defined(JS_CODEGEN_ARM)
+# if defined(JS_CODEGEN_ARM)
     AutoForbidPools afp(&masm, /* number of instructions in scope = */ 7);
-#endif
+# endif
 
     // There is an important ordering constraint here: fp must be repointed to
     // the caller's frame before any field of the frame currently pointed to by
     // fp is popped: asynchronous signal handlers (which use stack space
     // starting at sp) could otherwise clobber these fields while they are still
     // accessible via fp (fp fields are read during frame iteration which is
     // *also* done asynchronously).
 
     masm.pop(FramePointer);
-    DebugOnly<uint32_t> poppedFP = masm.currentOffset();
+    poppedFP = masm.currentOffset();
 
     masm.pop(WasmTlsReg);
-    DebugOnly<uint32_t> poppedTlsReg = masm.currentOffset();
+    poppedTlsReg = masm.currentOffset();
 
-#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-    masm.pop(ra);
-    *ret = masm.currentOffset();
-    masm.branch(ra);
-#else
     *ret = masm.currentOffset();
     masm.ret();
+
 #endif
 
     MOZ_ASSERT_IF(!masm.oom(), PoppedFP == *ret - poppedFP);
     MOZ_ASSERT_IF(!masm.oom(), PoppedTLSReg == *ret - poppedTlsReg);
 }
 
 void
 wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
@@ -720,23 +737,19 @@ js::wasm::StartUnwinding(const RegisterS
       case CodeRange::Function:
       case CodeRange::FarJumpIsland:
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
       case CodeRange::BuiltinThunk:
       case CodeRange::OldTrapExit:
       case CodeRange::DebugTrap:
 #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        if ((offsetFromEntry >= BeforePushRetAddr && offsetFromEntry < PushedFP) || codeRange->isThunk()) {
-            // See BUG 1407986.
-            // On MIPS push is emulated by two instructions: adjusting the sp
-            // and storing the value to sp.
-            // Execution might be interrupted in between the two operation so we
-            // have to relay on register state instead of state saved on stack
-            // until the wasm::Frame is completely built.
+        if (offsetFromEntry < PushedFP || codeRange->isThunk()) {
+            // On MIPS we relay on register state instead of state saved on
+            // stack until the wasm::Frame is completely built.
             // On entry the return address is in ra (registers.lr) and
             // fp holds the caller's fp.
             fixedPC = (uint8_t*) registers.lr;
             fixedFP = fp;
             AssertMatchesCallSite(fixedPC, fixedFP);
         } else
 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
         if (offsetFromEntry == BeforePushRetAddr || codeRange->isThunk()) {
@@ -759,39 +772,36 @@ js::wasm::StartUnwinding(const RegisterS
             fixedFP = fp;
             AssertMatchesCallSite(fixedPC, fixedFP);
         } else if (offsetFromEntry == PushedFP) {
             // The full Frame has been pushed; fp is still the caller's fp.
             MOZ_ASSERT(fp == reinterpret_cast<Frame*>(sp)->callerFP);
             fixedPC = reinterpret_cast<Frame*>(sp)->returnAddress;
             fixedFP = fp;
             AssertMatchesCallSite(fixedPC, fixedFP);
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+        } else if (offsetInCode >= codeRange->ret() - PoppedFP &&
+                   offsetInCode <= codeRange->ret())
+        {
+            (void)PoppedTLSReg;
+            // The fixedFP field of the Frame has been loaded into fp.
+            // The ra and TLS might also be loaded, but the Frame structure is
+            // still on stack, so we can acess the ra form there.
+            MOZ_ASSERT(fp == reinterpret_cast<Frame*>(sp)->callerFP);
+            fixedPC = reinterpret_cast<Frame*>(sp)->returnAddress;
+            fixedFP = fp;
+            AssertMatchesCallSite(fixedPC, fixedFP);
+#else
         } else if (offsetInCode >= codeRange->ret() - PoppedFP &&
                    offsetInCode < codeRange->ret() - PoppedTLSReg)
         {
             // The fixedFP field of the Frame has been popped into fp.
             fixedPC = sp[1];
             fixedFP = fp;
             AssertMatchesCallSite(fixedPC, fixedFP);
-#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        } else if (offsetInCode >= codeRange->ret() - PoppedTLSReg &&
-                   offsetInCode < codeRange->ret())
-        {
-            // The fixedFP field of the Frame has been popped into fp, but the
-            // exit reason hasn't been popped yet.
-            fixedPC = sp[0];
-            fixedFP = fp;
-            AssertMatchesCallSite(fixedPC, fixedFP);
-        } else if (offsetInCode == codeRange->ret()) {
-            // Both the TLS, fixedFP and ra have been popped and fp now
-            // points to the caller's frame.
-            fixedPC = (uint8_t*) registers.lr;
-            fixedFP = fp;
-            AssertMatchesCallSite(fixedPC, fixedFP);
-#else
         } else if (offsetInCode == codeRange->ret()) {
             // Both the TLS and fixedFP fields have been popped and fp now
             // points to the caller's frame.
             fixedPC = sp[0];
             fixedFP = fp;
             AssertMatchesCallSite(fixedPC, fixedFP);
 #endif
         } else {
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1869,16 +1869,21 @@ struct Frame
     // The caller's Frame*. See GenerateCallableEpilogue for why this must be
     // the first field of wasm::Frame (in a downward-growing stack).
     Frame* callerFP;
 
     // The saved value of WasmTlsReg on entry to the function. This is
     // effectively the callee's instance.
     TlsData* tls;
 
+#if defined(JS_CODEGEN_MIPS32)
+    // Double word aligned frame ensures correct alignment for wasm locals
+    // on architectures that require the stack alignment to be more than word size.
+    uintptr_t padding_;
+#endif
     // The return address pushed by the call (in the case of ARM/MIPS the return
     // address is pushed by the first instruction of the prologue).
     void* returnAddress;
 
     // Helper functions:
 
     Instance* instance() const { return tls->instance; }
 };
@@ -1920,18 +1925,20 @@ class DebugFrame
             bool hasCachedSavedFrame_ : 1;
             bool hasCachedReturnJSValue_ : 1;
         };
         void* flagsWord_;
     };
 
     // Avoid -Wunused-private-field warnings.
   protected:
-#if JS_BITS_PER_WORD == 32
-    uint32_t padding_;  // See alignmentStaticAsserts().
+#if JS_BITS_PER_WORD == 32 && !defined(JS_CODEGEN_MIPS32)
+    // See alignmentStaticAsserts().
+    // For MIPS32 padding is already incorporated in the frame.
+    uint32_t padding_;
 #endif
 
   private:
     // The Frame goes at the end since the stack grows down.
     Frame frame_;
 
   public:
     static DebugFrame* from(Frame* fp);
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -227,36 +227,88 @@
 #    define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread))
 #  else
 #    define MOZ_TSAN_BLACKLIST /* nothing */
 #  endif
 #else
 #  define MOZ_TSAN_BLACKLIST /* nothing */
 #endif
 
-/*
- * The MOZ_NO_SANITIZE_* family of macros is an annotation based on a more recently
- * introduced Clang feature that allows disabling various sanitizer features for
- * the particular function, including those from UndefinedBehaviorSanitizer.
- */
-
 #if defined(__has_attribute)
 #  if __has_attribute(no_sanitize)
 #    define MOZ_HAVE_NO_SANITIZE_ATTR
 #  endif
 #endif
 
+/*
+ * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW disables *un*signed integer overflow
+ * checking on the function it annotates, in builds configured to perform it.
+ * (Currently this is only Clang using -fsanitize=unsigned-integer-overflow, or
+ * via --enable-unsigned-overflow-sanitizer in Mozilla's build system.)  It has
+ * no effect in other builds.
+ *
+ * Place this attribute at the very beginning of a function declaration.
+ *
+ * Unsigned integer overflow isn't *necessarily* a bug.  It's well-defined in
+ * C/C++, and code may reasonably depend upon it.  For example,
+ *
+ *   MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline bool
+ *   IsDecimal(char aChar)
+ *   {
+ *     // For chars less than '0', unsigned integer underflow occurs, to a value
+ *     // much greater than 10, so the overall test is false.
+ *     // For chars greater than '0', no overflow occurs, and only '0' to '9'
+ *     // pass the overall test.
+ *     return static_cast<unsigned int>(aChar) - '0' < 10;
+ *   }
+ *
+ * But even well-defined unsigned overflow often causes bugs when it occurs, so
+ * it should be restricted to functions annotated with this attribute.
+ *
+ * The compiler instrumentation to detect unsigned integer overflow has costs
+ * both at compile time and at runtime.  Functions that are repeatedly inlined
+ * at compile time will also implicitly inline the necessary instrumentation,
+ * increasing compile time.  Similarly, frequently-executed functions that
+ * require large amounts of instrumentation will also notice significant runtime
+ * slowdown to execute that instrumentation.  Use this attribute to eliminate
+ * those costs -- but only after carefully verifying that no overflow can occur.
+ */
 #if defined(MOZ_HAVE_NO_SANITIZE_ATTR)
-#  define MOZ_NO_SANITIZE_UINT_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
-#  define MOZ_NO_SANITIZE_INT_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow")))
+#  define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
 #else
-#  define MOZ_NO_SANITIZE_UINT_OVERFLOW /* nothing */
-#  define MOZ_NO_SANITIZE_INT_OVERFLOW /* nothing */
+#  define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW /* nothing */
 #endif
 
+/*
+ * MOZ_NO_SANITIZE_SIGNED_OVERFLOW disables *signed* integer overflow checking
+ * on the function it annotates, in builds configured to perform it.  (Currently
+ * this is only Clang using -fsanitize=signed-integer-overflow, or via
+ * --enable-signed-overflow-sanitizer in Mozilla's build system.  GCC support
+ * will probably be added in the future.)  It has no effect in other builds.
+ *
+ * Place this attribute at the very beginning of a function declaration.
+ *
+ * Signed integer overflow is undefined behavior in C/C++: *anything* can happen
+ * when it occurs.  *Maybe* wraparound behavior will occur, but maybe also the
+ * compiler will assume no overflow happens and will adversely optimize the rest
+ * of your code.  Code that contains signed integer overflow needs to be fixed.
+ *
+ * The compiler instrumentation to detect signed integer overflow has costs both
+ * at compile time and at runtime.  Functions that are repeatedly inlined at
+ * compile time will also implicitly inline the necessary instrumentation,
+ * increasing compile time.  Similarly, frequently-executed functions that
+ * require large amounts of instrumentation will also notice significant runtime
+ * slowdown to execute that instrumentation.  Use this attribute to eliminate
+ * those costs -- but only after carefully verifying that no overflow can occur.
+ */
+#if defined(MOZ_HAVE_NO_SANITIZE_ATTR)
+#  define MOZ_NO_SANITIZE_SIGNED_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow")))
+#else
+#  define MOZ_NO_SANITIZE_SIGNED_OVERFLOW /* nothing */
+#endif
 
 #undef MOZ_HAVE_NO_SANITIZE_ATTR
 
 
 /**
  * MOZ_ALLOCATOR tells the compiler that the function it marks returns either a
  * "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the
  * block is not pointed to by any other reachable pointer in the program.
--- a/mfbt/MathAlgorithms.h
+++ b/mfbt/MathAlgorithms.h
@@ -556,16 +556,20 @@ struct WrapToSignedHelper
     (UnsignedType(1) << (CHAR_BIT * sizeof(SignedType) - 1)) - 1;
   static constexpr SignedType MinValue = -MaxValue - 1;
 
   static constexpr UnsignedType MinValueUnsigned =
     static_cast<UnsignedType>(MinValue);
   static constexpr UnsignedType MaxValueUnsigned =
     static_cast<UnsignedType>(MaxValue);
 
+  // Overflow-correctness was proven in bug 1432646 and is explained in the
+  // comment below.  This function is very hot, both at compile time and
+  // runtime, so disable all overflow checking in it.
+  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW MOZ_NO_SANITIZE_SIGNED_OVERFLOW
   static constexpr SignedType compute(UnsignedType aValue)
   {
     // This algorithm was originally provided here:
     // https://stackoverflow.com/questions/13150449/efficient-unsigned-to-signed-cast-avoiding-implementation-defined-behavior
     //
     // If the value is in the non-negative signed range, just cast.
     //
     // If the value will be negative, compute its delta from the first number
--- a/mobile/android/app/src/main/res/layout/customtabs_action_bar_custom_view.xml
+++ b/mobile/android/app/src/main/res/layout/customtabs_action_bar_custom_view.xml
@@ -47,15 +47,15 @@
 
         <TextView
             android:id="@+id/custom_tabs_action_bar_url"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:textColor="?android:textColorPrimary"
             android:textSize="10sp"
-            android:ellipsize="middle"
+            android:ellipsize="start"
             android:scrollHorizontally="true"
             tools:text="https://mozilla.org"/>
 
     </LinearLayout>
 
 </LinearLayout>
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java
@@ -3,16 +3,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/. */
 
 package org.mozilla.gecko.customtabs;
 
 import android.content.res.Resources;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.MenuItemCompat;
@@ -232,13 +233,14 @@ public class ActionBarPresenter {
 
         // If no title to use, use Url as title
         if (TextUtils.isEmpty(title)) {
             mTitleView.setText(url);
             mUrlView.setText(null);
             mUrlView.setVisibility(View.GONE);
         } else {
             mTitleView.setText(title);
-            mUrlView.setText(url);
+            String domain = Uri.parse(url).getHost();
+            mUrlView.setText(domain);
             mUrlView.setVisibility(View.VISIBLE);
         }
     }
 }
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -3918,17 +3918,17 @@ Preferences::GetString(const char* aPref
 }
 
 /* static */ nsresult
 Preferences::GetLocalizedCString(const char* aPrefName,
                                  nsACString& aResult,
                                  PrefValueKind aKind)
 {
   nsAutoString result;
-  nsresult rv = GetLocalizedString(aPrefName, result);
+  nsresult rv = GetLocalizedString(aPrefName, result, aKind);
   if (NS_SUCCEEDED(rv)) {
     CopyUTF16toUTF8(result, aResult);
   }
   return rv;
 }
 
 /* static */ nsresult
 Preferences::GetLocalizedString(const char* aPrefName,
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -89,17 +89,18 @@ public:
     NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
     return (aKind == PrefValueKind::Default) ? sPreferences->mDefaultRootBranch
                                              : sPreferences->mRootBranch;
   }
 
   // Gets the type of the pref.
   static int32_t GetType(const char* aPrefName);
 
-  // Fallible value getters.
+  // Fallible value getters. When `aKind` is `User` they will get the user
+  // value if possible, and fall back to the default value otherwise.
   static nsresult GetBool(const char* aPrefName,
                           bool* aResult,
                           PrefValueKind aKind = PrefValueKind::User);
   static nsresult GetInt(const char* aPrefName,
                          int32_t* aResult,
                          PrefValueKind aKind = PrefValueKind::User);
   static nsresult GetUint(const char* aPrefName,
                           uint32_t* aResult,
@@ -124,48 +125,48 @@ public:
                                      nsAString& aResult,
                                      PrefValueKind aKind = PrefValueKind::User);
   static nsresult GetComplex(const char* aPrefName,
                              const nsIID& aType,
                              void** aResult,
                              PrefValueKind aKind = PrefValueKind::User);
 
   // Infallible getters of user or default values, with fallback results on
-  // failure.
-  // Infallible value getters.
+  // failure. When `aKind` is `User` they will get the user value if possible,
+  // and fall back to the default value otherwise.
   static bool GetBool(const char* aPrefName,
                       bool aFallback = false,
                       PrefValueKind aKind = PrefValueKind::User)
   {
     bool result = aFallback;
-    GetBool(aPrefName, &result);
+    GetBool(aPrefName, &result, aKind);
     return result;
   }
   static int32_t GetInt(const char* aPrefName,
                         int32_t aFallback = 0,
                         PrefValueKind aKind = PrefValueKind::User)
   {
     int32_t result = aFallback;
-    GetInt(aPrefName, &result);
+    GetInt(aPrefName, &result, aKind);
     return result;
   }
   static uint32_t GetUint(const char* aPrefName,
                           uint32_t aFallback = 0,
                           PrefValueKind aKind = PrefValueKind::User)
   {
     uint32_t result = aFallback;
-    GetUint(aPrefName, &result);
+    GetUint(aPrefName, &result, aKind);
     return result;
   }
   static float GetFloat(const char* aPrefName,
                         float aFallback = 0.0f,
                         PrefValueKind aKind = PrefValueKind::User)
   {
     float result = aFallback;
-    GetFloat(aPrefName, &result);
+    GetFloat(aPrefName, &result, aKind);
     return result;
   }
 
   // Value setters. These fail if run outside the parent process.
 
   static nsresult SetBool(const char* aPrefName,
                           bool aValue,
                           PrefValueKind aKind = PrefValueKind::User);
new file mode 100644
--- /dev/null
+++ b/modules/libpref/test/gtest/Basics.cpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
+TEST(PrefsBasics, Errors)
+{
+  Preferences::SetBool("foo.bool", true, PrefValueKind::Default);
+  Preferences::SetBool("foo.bool", false, PrefValueKind::User);
+  ASSERT_EQ(Preferences::GetBool("foo.bool", false, PrefValueKind::Default),
+            true);
+  ASSERT_EQ(Preferences::GetBool("foo.bool", true, PrefValueKind::User), false);
+
+  Preferences::SetInt("foo.int", -66, PrefValueKind::Default);
+  Preferences::SetInt("foo.int", -77, PrefValueKind::User);
+  ASSERT_EQ(Preferences::GetInt("foo.int", 1, PrefValueKind::Default), -66);
+  ASSERT_EQ(Preferences::GetInt("foo.int", 1, PrefValueKind::User), -77);
+
+  Preferences::SetUint("foo.uint", 88, PrefValueKind::Default);
+  Preferences::SetUint("foo.uint", 99, PrefValueKind::User);
+  ASSERT_EQ(Preferences::GetUint("foo.uint", 1, PrefValueKind::Default), 88U);
+  ASSERT_EQ(Preferences::GetUint("foo.uint", 1, PrefValueKind::User), 99U);
+
+  Preferences::SetFloat("foo.float", 3.33f, PrefValueKind::Default);
+  Preferences::SetFloat("foo.float", 4.44f, PrefValueKind::User);
+  ASSERT_FLOAT_EQ(
+    Preferences::GetFloat("foo.float", 1.0f, PrefValueKind::Default), 3.33f);
+  ASSERT_FLOAT_EQ(Preferences::GetFloat("foo.float", 1.0f, PrefValueKind::User),
+                  4.44f);
+}
--- a/modules/libpref/test/gtest/moz.build
+++ b/modules/libpref/test/gtest/moz.build
@@ -6,16 +6,17 @@
 
 Library('libpreftests')
 
 LOCAL_INCLUDES += [
     '../..',
 ]
 
 UNIFIED_SOURCES = [
+    'Basics.cpp',
     'CallbackAndVarCacheOrder.cpp',
     'Parser.cpp',
 ]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
 
 # THE MOCK_METHOD2 macro from gtest triggers this clang warning and it's hard
--- a/taskcluster/ci/release-partner-repack/kind.yml
+++ b/taskcluster/ci/release-partner-repack/kind.yml
@@ -145,46 +145,46 @@ jobs:
          - index.releases.v1.{branch}.latest.{product}.latest.partner_repacks.win64
 
    firefox-macosx-eme-free:
       label: firefox macosx64 EME-free repacks
       worker:
          properties:
             repack_manifests_url:
                by-project:
-                  mozilla-beta: "https://github.com/mozilla-partners/mozilla-EME-free-manifest"
-                  mozilla-release: "https://github.com/mozilla-partners/mozilla-EME-free-manifest"
+                  mozilla-beta: "git@github.com:mozilla-partners/mozilla-EME-free-manifest"
+                  mozilla-release: "git@github.com:mozilla-partners/mozilla-EME-free-manifest"
                   default: "git@github.com:mozilla-releng/staging-repack-manifests.git"
       run:
          buildername: release-{branch}-firefox-macosx64_partner_repacks
       routes:
          - index.releases.v1.{branch}.{revision}.{product}.{underscore_version}.build{build_number}.eme_free_repacks.macosx64
          - index.releases.v1.{branch}.latest.{product}.latest.eme_free_repacks.macosx64
 
    firefox-win32-eme-free:
       label: firefox win32 EME-free repacks
       worker:
          properties:
             repack_manifests_url:
                by-project:
-                  mozilla-beta: "https://github.com/mozilla-partners/mozilla-EME-free-manifest"
-                  mozilla-release: "https://github.com/mozilla-partners/mozilla-EME-free-manifest"
+                  mozilla-beta: "git@github.com:mozilla-partners/mozilla-EME-free-manifest"
+                  mozilla-release: "git@github.com:mozilla-partners/mozilla-EME-free-manifest"
                   default: "git@github.com:mozilla-releng/staging-repack-manifests.git"
       run:
          buildername: release-{branch}-firefox-win32_partner_repacks
       routes:
          - index.releases.v1.{branch}.{revision}.{product}.{underscore_version}.build{build_number}.eme_free_repacks.win32
          - index.releases.v1.{branch}.latest.{product}.latest.eme_free_repacks.win32
 
    firefox-win64-eme-free:
       label: firefox win64 EME-free repacks
       worker:
          properties:
             repack_manifests_url:
                by-project:
-                  mozilla-beta: "https://github.com/mozilla-partners/mozilla-EME-free-manifest"
-                  mozilla-release: "https://github.com/mozilla-partners/mozilla-EME-free-manifest"
+                  mozilla-beta: "git@github.com:mozilla-partners/mozilla-EME-free-manifest"
+                  mozilla-release: "git@github.com:mozilla-partners/mozilla-EME-free-manifest"
                   default: "git@github.com:mozilla-releng/staging-repack-manifests.git"
       run:
          buildername: release-{branch}-firefox-win64_partner_repacks
       routes:
          - index.releases.v1.{branch}.{revision}.{product}.{underscore_version}.build{build_number}.eme_free_repacks.win64
          - index.releases.v1.{branch}.latest.{product}.latest.eme_free_repacks.win64
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/release-secondary-update-verify/kind.yml
@@ -0,0 +1,169 @@
+# 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/.
+
+loader: taskgraph.loader.transform:loader
+
+kind-dependencies:
+   - post-balrog-dummy
+   - post-beetmover-dummy
+   - release-updates-builder
+
+transforms:
+   - taskgraph.transforms.release_deps:transforms
+   - taskgraph.transforms.update_verify:transforms
+   - taskgraph.transforms.task:transforms
+
+job-defaults:
+   name: secondary-update-verify
+   run-on-projects: []  # to make sure this never runs as part of CI
+   shipping-phase: promote
+   worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+   worker:
+      implementation: docker-worker
+      os: linux
+      docker-image:
+         in-tree: "update-verify"
+      max-run-time: 7200
+      retry-exit-status:
+         - 255
+      env:
+         NO_BBCONFIG: "1"
+         BUILD_TOOLS_REPO:
+            by-project:
+               jamun: https://hg.mozilla.org/users/stage-ffxbld/tools
+               maple: https://hg.mozilla.org/users/asasaki_mozilla.com/tools
+               default: https://hg.mozilla.org/build/tools
+         CHANNEL:
+            by-project:
+               mozilla-release: "beta-localtest"
+               default: "default"
+   extra:
+      chunks: 12
+   notifications:
+      completed:
+         subject: "COMPLETED: [{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]}] {task_def[metadata][name]} task"
+         message: "COMPLETED: [{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]}] {task_def[metadata][name]} task"
+         plugins:
+            by-project:
+               mozilla-beta: ["log_collect"]
+               mozilla-release: ["log_collect"]
+               default: []
+
+      failed:
+         subject: "FAILED: [{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]}] {task_def[metadata][name]} task"
+         message: "FAILED: [{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]}] {task_def[metadata][name]} task"
+         plugins:
+            by-project:
+               mozilla-beta: ["log_collect", "ses"]
+               mozilla-release: ["log_collect", "ses"]
+               default: ["ses"]
+         emails:
+            by-project:
+               mozilla-beta: ["release-automation-notifications@mozilla.com"]
+               mozilla-release: ["release-automation-notifications@mozilla.com"]
+               try: ["{task_def[metadata][owner]}"]
+               maple: ["release+tcstaging@mozilla.com"]
+               default: []
+
+      exception:
+         subject: "EXCEPTION: [{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]}] {task_def[metadata][name]} task"
+         message: "EXCEPTION: [{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]}] {task_def[metadata][name]} task"
+         plugins:
+            by-project:
+               mozilla-beta: ["log_collect", "ses"]
+               mozilla-release: ["log_collect", "ses"]
+               default: ["ses"]
+         emails:
+            by-project:
+               mozilla-beta: ["release-automation-notifications@mozilla.com"]
+               mozilla-release: ["release-automation-notifications@mozilla.com"]
+               try: ["{task_def[metadata][owner]}"]
+               maple: ["release+tcstaging@mozilla.com"]
+               default: []
+
+jobs:
+   firefox-secondary-linux64:
+      description: linux64 secondary channel update verify
+      shipping-product: firefox
+      worker:
+         env:
+            VERIFY_CONFIG:
+               by-project:
+                  mozilla-release: "beta-firefox-linux64.cfg"
+                  default: "none"
+      treeherder:
+         symbol: UVS
+         platform: linux64/opt
+         kind: test
+         tier: 1
+      attributes:
+         build_platform: linux64
+
+   firefox-secondary-linux:
+      description: linux secondary channel update verify
+      shipping-product: firefox
+      worker:
+         env:
+            VERIFY_CONFIG:
+               by-project:
+                  mozilla-release: "beta-firefox-linux.cfg"
+                  default: "none"
+      treeherder:
+         symbol: UVS
+         platform: linux/opt
+         kind: test
+         tier: 1
+      attributes:
+         build_platform: linux
+
+   firefox-secondary-win64:
+      description: win64 secondary channel update verify
+      shipping-product: firefox
+      worker:
+         env:
+            VERIFY_CONFIG:
+               by-project:
+                  mozilla-release: "beta-firefox-win64.cfg"
+                  default: "none"
+      treeherder:
+         symbol: UVS
+         platform: win64/opt
+         kind: test
+         tier: 1
+      attributes:
+         build_platform: win64
+
+   firefox-secondary-win32:
+      description: win32 secondary channel update verify
+      shipping-product: firefox
+      worker:
+         env:
+            VERIFY_CONFIG:
+               by-project:
+                  mozilla-release: "beta-firefox-win32.cfg"
+                  default: "none"
+      treeherder:
+         symbol: UVS
+         platform: win32/opt
+         kind: test
+         tier: 1
+      attributes:
+         build_platform: win32
+
+   firefox-secondary-macosx64:
+      description: macosx64 secondary channel update verify
+      shipping-product: firefox
+      worker:
+         env:
+            VERIFY_CONFIG:
+               by-project:
+                  mozilla-release: "beta-firefox-macosx64.cfg"
+                  default: "none"
+      treeherder:
+         symbol: UVS
+         platform: macosx64/opt
+         kind: test
+         tier: 1
+      attributes:
+         build_platform: macosx64
--- a/taskcluster/ci/release-update-verify/kind.yml
+++ b/taskcluster/ci/release-update-verify/kind.yml
@@ -219,121 +219,16 @@ jobs:
       treeherder:
          symbol: UV
          platform: macosx64/opt
          kind: test
          tier: 1
       attributes:
          build_platform: macosx64
 
-   firefox-secondary-linux64:
-      description: linux64 secondary channel update verify
-      shipping-product: firefox
-      worker:
-         env:
-            CHANNEL:
-               by-project:
-                  mozilla-release: "beta-localtest"
-                  default: "default"
-            VERIFY_CONFIG:
-               by-project:
-                  mozilla-release: "beta-firefox-linux64.cfg"
-                  default: "none"
-      treeherder:
-         symbol: UVS
-         platform: linux64/opt
-         kind: test
-         tier: 1
-      attributes:
-         build_platform: linux64
-
-   firefox-secondary-linux:
-      description: linux secondary channel update verify
-      shipping-product: firefox
-      worker:
-         env:
-            CHANNEL:
-               by-project:
-                  mozilla-release: "beta-localtest"
-                  default: "default"
-            VERIFY_CONFIG:
-               by-project:
-                  mozilla-release: "beta-firefox-linux.cfg"
-                  default: "none"
-      treeherder:
-         symbol: UVS
-         platform: linux/opt
-         kind: test
-         tier: 1
-      attributes:
-         build_platform: linux
-
-   firefox-secondary-win64:
-      description: win64 secondary channel update verify
-      shipping-product: firefox
-      worker:
-         env:
-            CHANNEL:
-               by-project:
-                  mozilla-release: "beta-localtest"
-                  default: "default"
-            VERIFY_CONFIG:
-               by-project:
-                  mozilla-release: "beta-firefox-win64.cfg"
-                  default: "none"
-      treeherder:
-         symbol: UVS
-         platform: win64/opt
-         kind: test
-         tier: 1
-      attributes:
-         build_platform: win64
-
-   firefox-secondary-win32:
-      description: win32 secondary channel update verify
-      shipping-product: firefox
-      worker:
-         env:
-            CHANNEL:
-               by-project:
-                  mozilla-release: "beta-localtest"
-                  default: "default"
-            VERIFY_CONFIG:
-               by-project:
-                  mozilla-release: "beta-firefox-win32.cfg"
-                  default: "none"
-      treeherder:
-         symbol: UVS
-         platform: win32/opt
-         kind: test
-         tier: 1
-      attributes:
-         build_platform: win32
-
-   firefox-secondary-macosx64:
-      description: macosx64 secondary channel update verify
-      shipping-product: firefox
-      worker:
-         env:
-            CHANNEL:
-               by-project:
-                  mozilla-release: "beta-localtest"
-                  default: "default"
-            VERIFY_CONFIG:
-               by-project:
-                  mozilla-release: "beta-firefox-macosx64.cfg"
-                  default: "none"
-      treeherder:
-         symbol: UVS
-         platform: macosx64/opt
-         kind: test
-         tier: 1
-      attributes:
-         build_platform: macosx64
-
    devedition-linux64:
       description: linux64 update verify
       shipping-product: devedition
       worker:
          env:
             CHANNEL:
                by-project:
                   jamun: "aurora-localtest"
--- a/taskcluster/docker/update-verify/Dockerfile
+++ b/taskcluster/docker/update-verify/Dockerfile
@@ -1,11 +1,61 @@
-FROM python:2-slim-stretch
+FROM ubuntu:16.04
 
 MAINTAINER release@mozilla.com
 
 RUN dpkg --add-architecture i386 && apt-get -q update \
     # p7zip-full is for extracting Windows and OS X packages
-    # Mercurial is for cloning required repositories
     # wget is for downloading update.xml, installers, and MARs
     # libgtk-3-0 and libgtk2.0-0 are required to run the Firefox updater
-    && apt-get -q --yes install p7zip-full mercurial wget libgtk-3-0 libgtk-3.0:i386 libgtk2.0-0 libgtk2.0-0:i386 \
+    && apt-get -q --yes install p7zip-full wget libgtk-3-0 libgtk-3.0:i386 libgtk2.0-0 libgtk2.0-0:i386 \
     && apt-get clean
+
+RUN mkdir /builds
+RUN groupadd -g 500 worker
+RUN useradd -u 500 -g 500 -d /builds/worker -s /bin/bash -m worker
+WORKDIR /builds/worker
+
+VOLUME /builds/worker/.cache
+VOLUME /builds/worker/checkouts
+
+RUN mkdir /build
+# %include python/mozbuild/mozbuild/action/tooltool.py
+ADD topsrcdir/python/mozbuild/mozbuild/action/tooltool.py /build/tooltool.py
+
+# %include testing/mozharness/external_tools/robustcheckout.py
+ADD topsrcdir/testing/mozharness/external_tools/robustcheckout.py /usr/local/mercurial/robustcheckout.py
+
+# %include taskcluster/docker/recipes/hgrc
+COPY topsrcdir/taskcluster/docker/recipes/hgrc /etc/mercurial/hgrc.d/mozilla.rc
+
+# %include taskcluster/docker/recipes/install-node.sh
+ADD topsrcdir/taskcluster/docker/recipes/install-node.sh /build/install-node.sh
+
+# %include taskcluster/docker/recipes/install-mercurial.sh
+ADD topsrcdir/taskcluster/docker/recipes/install-mercurial.sh /build/install-mercurial.sh
+ADD system-setup.sh /tmp/system-setup.sh
+# %include tools/lint/eslint/manifest.tt
+ADD topsrcdir/tools/lint/eslint/manifest.tt /tmp/eslint.tt
+# %include tools/lint/eslint/eslint-plugin-mozilla/manifest.tt
+ADD topsrcdir/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt /tmp/eslint-plugin-mozilla.tt
+# %include tools/lint/python/flake8_requirements.txt
+ADD topsrcdir/tools/lint/python/flake8_requirements.txt /tmp/flake8_requirements.txt
+# %include tools/lint/tox/tox_requirements.txt
+ADD topsrcdir/tools/lint/tox/tox_requirements.txt /tmp/tox_requirements.txt
+RUN bash /tmp/system-setup.sh
+
+# %include taskcluster/docker/recipes/run-task
+ADD topsrcdir/taskcluster/docker/recipes/run-task /builds/worker/bin/run-task
+RUN chown -R worker:worker /builds/worker/bin && chmod 755 /builds/worker/bin/*
+
+# Set variable normally configured at login, by the shells parent process, these
+# are taken from GNU su manual
+ENV           HOME          /builds/worker
+ENV           SHELL         /bin/bash
+ENV           USER          worker
+ENV           LOGNAME       worker
+ENV           HOSTNAME      taskcluster-worker
+ENV           LANG          en_US.UTF-8
+ENV           LC_ALL        en_US.UTF-8
+
+# Set a default command useful for debugging
+CMD ["/bin/bash", "--login"]
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/update-verify/system-setup.sh
@@ -0,0 +1,100 @@
+#!/usr/bin/env bash
+# This allows ubuntu-desktop to be installed without human interaction
+export DEBIAN_FRONTEND=noninteractive
+
+set -ve
+
+test "$(whoami)" == 'root'
+
+mkdir -p /setup
+cd /setup
+
+apt_packages=()
+apt_packages+=('codespell')
+apt_packages+=('curl')
+apt_packages+=('locales')
+apt_packages+=('git')
+apt_packages+=('python')
+apt_packages+=('python-pip')
+apt_packages+=('python3')
+apt_packages+=('python3-pip')
+apt_packages+=('shellcheck')
+apt_packages+=('sudo')
+apt_packages+=('wget')
+apt_packages+=('xz-utils')
+
+apt-get update
+apt-get install -y "${apt_packages[@]}"
+
+# Without this we get spurious "LC_ALL: cannot change locale (en_US.UTF-8)" errors,
+# and python scripts raise UnicodeEncodeError when trying to print unicode characters.
+locale-gen en_US.UTF-8
+dpkg-reconfigure locales
+
+su -c 'git config --global user.email "worker@mozilla.test"' worker
+su -c 'git config --global user.name "worker"' worker
+
+tooltool_fetch() {
+    cat >manifest.tt
+    /build/tooltool.py fetch
+    rm manifest.tt
+}
+
+cd /build
+# shellcheck disable=SC1091
+. install-mercurial.sh
+
+###
+# ESLint Setup
+###
+
+# install node
+# shellcheck disable=SC1091
+. install-node.sh
+
+###
+# jsdoc Setup
+###
+
+npm install -g jsdoc@3.5.5
+
+/build/tooltool.py fetch -m /tmp/eslint.tt
+mv /build/node_modules /build/node_modules_eslint
+/build/tooltool.py fetch -m /tmp/eslint-plugin-mozilla.tt
+mv /build/node_modules /build/node_modules_eslint-plugin-mozilla
+
+###
+# fzf setup
+###
+
+tooltool_fetch <<EOF
+[
+  {
+    "size": 866160,
+    "digest": "9f0ef6bf44b8622bd0e4e8b0b5b5c714c0a2ce4487e6f234e7d4caac458164c521949f4d84b8296274e8bd20966f835e26f6492ba499405d38b620181e82429e",
+    "algorithm": "sha512",
+    "filename": "fzf-0.16.11-linux_amd64.tgz",
+    "unpack": true
+  }
+]
+EOF
+mv fzf /usr/local/bin
+
+###
+# Flake8 Setup
+###
+
+cd /setup
+
+pip install --require-hashes -r /tmp/flake8_requirements.txt
+
+###
+# tox Setup
+###
+
+cd /setup
+
+pip install --require-hashes -r /tmp/tox_requirements.txt
+
+cd /
+rm -rf /setup
--- a/taskcluster/docs/kinds.rst
+++ b/taskcluster/docs/kinds.rst
@@ -290,16 +290,20 @@ Verifies the contents and package of rel
 release-secondary-balrog-publishing
 ---------------------
 Schedule an RC release to go live in Balrog. Usually this will happen on the beta channel, to a smaller audience, before the RC goes live on the release channel.
 
 release-update-verify
 ---------------------
 Verifies the contents and package of release update MARs.
 
+release-secondary-update-verify
+---------------------
+Verifies the contents and package of release update MARs.
+
 release-updates-builder
 -----------------------
 Top level Balrog blob submission & patcher/update verify config updates.
 
 release-uptake-monitoring
 -------------------------
 Run uptake monitoring for releases.
 
--- a/taskcluster/taskgraph/target_tasks.py
+++ b/taskcluster/taskgraph/target_tasks.py
@@ -328,21 +328,19 @@ def target_tasks_promote_firefox(full_ta
         # At some point this should filter by shipping_phase == 'build' and
         # shipping_product matches.
         if task.label in beta_release_tasks:
             return True
 
         # 'secondary' update/final verify tasks only run for
         # RCs
         if parameters.get('release_type') != 'rc':
-            if task.kind in ('release-buildbot-update-verify',
-                             'release-update-verify',
+            if task.kind in ('release-secondary-update-verify',
                              'release-secondary-final-verify'):
-                if 'secondary' in task.label:
-                    return False
+                return False
 
         if task.attributes.get('shipping_product') == 'firefox' and \
                 task.attributes.get('shipping_phase') == 'promote':
             return True
 
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
--- a/taskcluster/taskgraph/transforms/release_deps.py
+++ b/taskcluster/taskgraph/transforms/release_deps.py
@@ -54,16 +54,21 @@ def add_dependencies(config, jobs):
                     continue
                 # Skip old-id
                 if 'old-id' in dep_task.label:
                     continue
             # We can only depend on tasks in the current or previous phases
             dep_phase = dep_task.attributes.get('shipping_phase')
             if dep_phase and PHASES.index(dep_phase) > PHASES.index(phase):
                 continue
+
+            if dep_task.attributes.get("build_platform") and \
+               job.get("attributes", {}).get("build_platform"):
+                if dep_task.attributes["build_platform"] != job["attributes"]["build_platform"]:
+                    continue
             # Add matching product tasks to deps
             if _get_product(dep_task.task) == product or \
                     dep_task.attributes.get('shipping_product') == product:
                 dependencies[dep_task.label] = dep_task.label
 
         job.setdefault('dependencies', {}).update(dependencies)
 
         yield job
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -1948,23 +1948,24 @@ toolbar#nav-bar {
                      if os.path.isdir(os.path.join(parent, sub))]
 
         if not gmp_paths:
             # This is fatal for desktop environments.
             raise EnvironmentError('Could not find test gmp plugins')
 
         return os.pathsep.join(gmp_paths)
 
-    def cleanup(self, options):
+    def cleanup(self, options, final=False):
         """ remove temporary files and profile """
         if hasattr(self, 'manifest') and self.manifest is not None:
-            os.remove(self.manifest)
+            if os.path.exists(self.manifest):
+                os.remove(self.manifest)
         if hasattr(self, 'profile'):
             del self.profile
-        if options.pidFile != "":
+        if options.pidFile != "" and os.path.exists(options.pidFile):
             try:
                 os.remove(options.pidFile)
                 if os.path.exists(options.pidFile + ".xpcshell.pid"):
                     os.remove(options.pidFile + ".xpcshell.pid")
             except Exception:
                 self.log.warning(
                     "cleaning up pidfile '%s' was unsuccessful from the test harness" %
                     options.pidFile)
@@ -2594,16 +2595,19 @@ toolbar#nav-bar {
             result = result or res
 
             # Dump the logging buffer
             self.message_logger.dump_buffered()
 
             if res == -1:
                 break
 
+        if self.manifest is not None:
+            self.cleanup(options, True)
+
         e10s_mode = "e10s" if options.e10s else "non-e10s"
 
         # printing total number of tests
         if options.flavor == 'browser':
             print("TEST-INFO | checking window state")
             print("Browser Chrome Test Summary")
             print("\tPassed: %s" % self.countpass)
             print("\tFailed: %s" % self.countfail)
@@ -2809,17 +2813,17 @@ toolbar#nav-bar {
             log=self.log,
             stack_fixer=get_stack_fixer_function(options.utilityPath,
                                                  options.symbolsPath),
         )
 
         self.log.info("runtests.py | Running tests: end.")
 
         if self.manifest is not None:
-            self.cleanup(options)
+            self.cleanup(options, False)
 
         return status
 
     def handleTimeout(self, timeout, proc, utilityPath, debuggerInfo,
                       browser_pid, processLog):
         """handle process output timeout"""
         # TODO: bug 913975 : _processOutput should call self.processOutputLine
         # one more time one timeout (I think)
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -28,16 +28,17 @@ class MochiRemote(MochitestDesktop):
     localProfile = None
     logMessages = []
 
     def __init__(self, automation, devmgr, options):
         MochitestDesktop.__init__(self, options.flavor, vars(options))
 
         self._automation = automation
         self._dm = devmgr
+        self.chromePushed = False
         self.environment = self._automation.environment
         self.remoteProfile = os.path.join(options.remoteTestRoot, "profile/")
         self.remoteModulesDir = os.path.join(options.remoteTestRoot, "modules/")
         self.remoteCache = os.path.join(options.remoteTestRoot, "cache/")
         self._automation.setRemoteProfile(self.remoteProfile)
         self.remoteLog = options.remoteLogFile
         self.localLog = options.logFile
         self._automation.deleteANRs()
@@ -51,31 +52,34 @@ class MochiRemote(MochitestDesktop):
             "chrome")
         self._dm.removeDir(self.remoteChromeTestDir)
         self._dm.mkDir(self.remoteChromeTestDir)
         self._dm.removeDir(self.remoteProfile)
         self._dm.removeDir(self.remoteCache)
         # move necko cache to a location that can be cleaned up
         options.extraPrefs += ["browser.cache.disk.parent_directory=%s" % self.remoteCache]
 
-    def cleanup(self, options):
-        if self._dm.fileExists(self.remoteLog):
-            self._dm.getFile(self.remoteLog, self.localLog)
-            self._dm.removeFile(self.remoteLog)
+    def cleanup(self, options, final=False):
+        if final:
+            self._dm.removeDir(self.remoteChromeTestDir)
+            self.chromePushed = False
+            blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
+            if blobberUploadDir:
+                self._dm.getDirectory(self.remoteMozLog, blobberUploadDir)
         else:
-            self.log.warning(
-                "Unable to retrieve log file (%s) from remote device" %
-                self.remoteLog)
-        self._dm.removeDir(self.remoteChromeTestDir)
+            if self._dm.fileExists(self.remoteLog):
+                self._dm.getFile(self.remoteLog, self.localLog)
+                self._dm.removeFile(self.remoteLog)
+            else:
+                self.log.warning(
+                    "Unable to retrieve log file (%s) from remote device" %
+                    self.remoteLog)
         self._dm.removeDir(self.remoteProfile)
         self._dm.removeDir(self.remoteCache)
-        blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
-        if blobberUploadDir:
-            self._dm.getDirectory(self.remoteMozLog, blobberUploadDir)
-        MochitestDesktop.cleanup(self, options)
+        MochitestDesktop.cleanup(self, options, final)
         self.localProfile = None
 
     def findPath(self, paths, filename=None):
         for path in paths:
             p = path
             if filename:
                 p = os.path.join(p, filename)
             if os.path.exists(self.getFullPath(p)):
@@ -225,21 +229,22 @@ class MochiRemote(MochitestDesktop):
             raise
 
         options.profilePath = self.remoteProfile
         options.logFile = self.localLog
         return retVal
 
     def getChromeTestDir(self, options):
         local = super(MochiRemote, self).getChromeTestDir(options)
-        local = os.path.join(local, "chrome")
         remote = self.remoteChromeTestDir
-        if options.flavor == 'chrome':
+        if options.flavor == 'chrome' and not self.chromePushed:
             self.log.info("pushing %s to %s on device..." % (local, remote))
+            local = os.path.join(local, "chrome")
             self._dm.pushDir(local, remote)
+            self.chromePushed = True
         return remote
 
     def getLogFilePath(self, logFile):
         return logFile
 
     def printDeviceInfo(self, printLogcat=False):
         try:
             if printLogcat:
@@ -291,24 +296,29 @@ class MochiRemote(MochitestDesktop):
         # whereas runtest.py's `runApp` takes a mozprofile object.
         if 'profileDir' not in kwargs and 'profile' in kwargs:
             kwargs['profileDir'] = kwargs.pop('profile').profile
 
         # remove args not supported by automation.py
         kwargs.pop('marionette_args', None)
 
         ret, _ = self._automation.runApp(*args, **kwargs)
+        self.countpass += self.counts['pass']
+        self.countfail += self.counts['fail']
+        self.counttodo += self.counts['todo']
+
         return ret, None
 
 
 def run_test_harness(parser, options):
     parser.validate(options)
 
     message_logger = MessageLogger(logger=None)
-    process_args = {'messageLogger': message_logger}
+    counts = dict()
+    process_args = {'messageLogger': message_logger, 'counts': counts}
     auto = RemoteAutomation(None, "fennec", processArgs=process_args)
 
     if options is None:
         raise ValueError("Invalid options specified, use --help for a list of valid options")
 
     options.runByManifest = False
     # roboextender is used by mochitest-chrome tests like test_java_addons.html,
     # but not by any plain mochitests
@@ -318,16 +328,17 @@ def run_test_harness(parser, options):
     dm = options.dm
     auto.setDeviceManager(dm)
     mochitest = MochiRemote(auto, dm, options)
     options.dm = None
 
     log = mochitest.log
     message_logger.logger = log
     mochitest.message_logger = message_logger
+    mochitest.counts = counts
 
     # Check that Firefox is installed
     expected = options.app.split('/')[-1]
     installed = dm.shellCheckOutput(['pm', 'list', 'packages', expected])
     if expected not in installed:
         log.error("%s is not installed on this device" % expected)
         return 1
 
--- a/testing/mozharness/configs/partner_repacks/release_mozilla-esr52_desktop.py
+++ b/testing/mozharness/configs/partner_repacks/release_mozilla-esr52_desktop.py
@@ -1,6 +1,6 @@
 config = {
     "appName": "Firefox",
     "log_name": "partner_repack",
-    "repack_manifests_url": "https://github.com/mozilla-partners/mozilla-sha1-manifest",
+    "repack_manifests_url": "git@github.com:mozilla-partners/mozilla-sha1-manifest",
     "repo_file": "https://raw.githubusercontent.com/mozilla/git-repo/master/repo",
 }
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/__dir__.ini
@@ -0,0 +1,1 @@
+prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/base-uri/base-uri_iframe_sandbox.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/base-uri/base-uri_iframe_sandbox.sub.html.ini
@@ -1,3 +1,2 @@
 [base-uri_iframe_sandbox.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   expected: ERROR
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/base-uri/report-uri-does-not-respect-base-uri.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[report-uri-does-not-respect-base-uri.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/blob/blob-urls-do-not-match-self.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[blob-urls-do-not-match-self.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/child-src/child-src-worker-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/child-src/child-src-worker-blocked.sub.html.ini
@@ -1,5 +1,4 @@
 [child-src-worker-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Should throw a securitypolicyviolation event]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-beacon-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/connect-src/connect-src-beacon-blocked.sub.html.ini
@@ -1,9 +1,8 @@
 [connect-src-beacon-blocked.sub.html]
   type: testharness
-  prefs: [security.csp.enable_violation_events:true]
   [sendBeacon should not throw.]
     expected: FAIL
 
   [redirect case]
     expected: TIMEOUT
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-beacon-redirect-to-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[connect-src-beacon-redirect-to-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-eventsource-blocked.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[connect-src-eventsource-blocked.sub.html]
-  type: testharness
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-eventsource-redirect-to-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/connect-src/connect-src-eventsource-redirect-to-blocked.sub.html.ini
@@ -1,6 +1,5 @@
 [connect-src-eventsource-redirect-to-blocked.sub.html]
   type: testharness
-  prefs: [security.csp.enable_violation_events:true]
   [Expecting logs: ["PASS EventSource() did not follow the disallowed redirect.","PASS successfullyParsed is true","TEST COMPLETE"\]]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-websocket-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/connect-src/connect-src-websocket-blocked.sub.html.ini
@@ -1,6 +1,5 @@
 [connect-src-websocket-blocked.sub.html]
   type: testharness
-  prefs: [security.csp.enable_violation_events:true]
   [WebSocket should fire error event.]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-blocked.sub.html.ini
@@ -1,8 +1,7 @@
 [connect-src-xmlhttprequest-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [XHR should fire onerror.]
     expected: TIMEOUT
 
   [XHR should fire onerror after a redirect.]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/connect-src/connect-src-xmlhttprequest-redirect-to-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[connect-src-xmlhttprequest-redirect-to-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/connect-src/worker-from-guid.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[worker-from-guid.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/font-src/font-stylesheet-font-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[font-stylesheet-font-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/form-action/form-action-src-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/form-action/form-action-src-blocked.sub.html.ini
@@ -1,6 +1,5 @@
 [form-action-src-blocked.sub.html]
   type: testharness
-  prefs: [security.csp.enable_violation_events:true]
   [form-action-src-blocked]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/form-action/form-action-src-get-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/form-action/form-action-src-get-blocked.sub.html.ini
@@ -1,6 +1,5 @@
 [form-action-src-get-blocked.sub.html]
   type: testharness
-  prefs: [security.csp.enable_violation_events:true]
   [form-action-src-allowed]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/form-action/form-action-src-javascript-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/form-action/form-action-src-javascript-blocked.sub.html.ini
@@ -1,6 +1,5 @@
 [form-action-src-javascript-blocked.sub.html]
   type: testharness
-  prefs: [security.csp.enable_violation_events:true]
   [form-action-src-javascript-blocked]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/generic/generic-0_1-img-src.html.ini
+++ b/testing/web-platform/meta/content-security-policy/generic/generic-0_1-img-src.html.ini
@@ -1,8 +1,7 @@
 [generic-0_1-img-src.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Violation report status OK.]
     expected: FAIL
 
   [Should fire violation events for every failed violation]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/generic/generic-0_1-script-src.html.ini
+++ b/testing/web-platform/meta/content-security-policy/generic/generic-0_1-script-src.html.ini
@@ -1,8 +1,7 @@
 [generic-0_1-script-src.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Violation report status OK.]
     expected: FAIL
 
   [Should fire violation events for every failed violation]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/generic/generic-0_10_1.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[generic-0_10_1.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/generic/generic-0_2_2.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[generic-0_2_2.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/generic/generic-0_2_3.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[generic-0_2_3.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/generic/generic-0_8_1.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[generic-0_8_1.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/img-src/report-blocked-data-uri.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[report-blocked-data-uri.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-7_1_2.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/media-src/media-src-7_1_2.sub.html.ini
@@ -1,5 +1,4 @@
 [media-src-7_1_2.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that securitypolicyviolation events are fired]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-7_2_2.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/media-src/media-src-7_2_2.sub.html.ini
@@ -1,5 +1,4 @@
 [media-src-7_2_2.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that securitypolicyviolation events are fired]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-7_3_2.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/media-src/media-src-7_3_2.sub.html.ini
@@ -1,5 +1,4 @@
 [media-src-7_3_2.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that securitypolicyviolation events are fired]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-blocked.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/media-src/media-src-blocked.sub.html.ini
@@ -1,5 +1,4 @@
 [media-src-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that securitypolicyviolation events are fired]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/navigation/to-javascript-url-script-src.html.ini
+++ b/testing/web-platform/meta/content-security-policy/navigation/to-javascript-url-script-src.html.ini
@@ -1,11 +1,10 @@
 [to-javascript-url-script-src.html]
   expected: TIMEOUT
-  prefs: [security.csp.enable_violation_events:true]
   [<iframe src='javascript:'> blocked without 'unsafe-inline'.]
     expected: TIMEOUT
 
   [<iframe> navigated to 'javascript:' blocked without 'unsafe-inline'.]
     expected: TIMEOUT
 
   [<iframe src='...'> with 'unsafe-inline' navigated to 'javascript:' blocked in this document]
     expected: TIMEOUT
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/object-src/object-src-url-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[object-src-url-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/injected-inline-script-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[injected-inline-script-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/javascript-window-open-blocked.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/javascript-window-open-blocked.html.ini
@@ -1,5 +1,4 @@
 [javascript-window-open-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Check that a securitypolicyviolation event is fired]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_1.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[script-src-1_1.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_10.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-1_10.html.ini
@@ -1,5 +1,4 @@
 [script-src-1_10.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that securitypolicyviolation event is fired]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_2.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-1_2.html.ini
@@ -1,4 +1,3 @@
 [script-src-1_2.html]
   disabled:
     if os == "win": bug 1172411
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_2_1.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-1_2_1.html.ini
@@ -1,4 +1,3 @@
 [script-src-1_2_1.html]
   disabled:
     if os == "win": bug 1094323
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4.html.ini
@@ -1,5 +1,4 @@
 [script-src-1_4.html]
-  prefs: [security.csp.enable_violation_events:true]
   [eval() should throw without 'unsafe-eval' keyword source in script-src directive.]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4_1.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4_1.html.ini
@@ -1,4 +1,3 @@
 [script-src-1_4_1.html]
   disabled:
     if os == "win": bug 1094323
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4_2.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4_2.html.ini
@@ -1,5 +1,4 @@
 [script-src-1_4_2.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Unsafe eval ran in Function() constructor.]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html.ini
@@ -1,8 +1,7 @@
 [script-src-report-only-policy-works-with-external-hash-policy.html]
-  prefs: [security.csp.enable_violation_events:true]
   [External script in a script tag with matching SRI hash should run.]
     expected: FAIL
 
   [Should fire securitypolicyviolation event]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html.ini
@@ -1,5 +1,4 @@
 [script-src-report-only-policy-works-with-hash-policy.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that the securitypolicyviolation event is fired]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_discard_whitelist.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[script-src-strict_dynamic_discard_whitelist.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_different_nonce.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[script-src-strict_dynamic_double_policy_different_nonce.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_report_only.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[script-src-strict_dynamic_double_policy_report_only.html]
-  type: testharness
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_hashes.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_hashes.html.ini
@@ -1,3 +1,2 @@
 [script-src-strict_dynamic_hashes.html]
   expected: ERROR
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_javascript_uri.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[script-src-strict_dynamic_javascript_uri.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_non_parser_inserted_incorrect_nonce.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[script-src-strict_dynamic_non_parser_inserted_incorrect_nonce.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini
+++ b/testing/web-platform/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini
@@ -1,9 +1,8 @@
 [script-src-strict_dynamic_parser_inserted.html]
   expected: TIMEOUT
-  prefs: [security.csp.enable_violation_events:true]
   [Script injected via `innerHTML` is not allowed with `strict-dynamic`.]
     expected: TIMEOUT
 
   [Script injected via `insertAdjacentHTML` is not allowed with `strict-dynamic`.]
     expected: TIMEOUT
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/scripthash-unicode-normalization.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[scripthash-unicode-normalization.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/scriptnonce-and-scripthash.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[scriptnonce-and-scripthash.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/scriptnonce-ignore-unsafeinline.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[scriptnonce-ignore-unsafeinline.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini
+++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/blockeduri-inline.html.ini
@@ -1,5 +1,4 @@
 [blockeduri-inline.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Inline violations have a blockedURI of 'inline']
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/idl.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[idl.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[img-src-redirect-upgrade-reporting.https.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html.ini
@@ -1,5 +1,4 @@
 [securitypolicyviolation-block-cross-origin-image-from-script.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Non-redirected cross-origin URLs are not stripped.]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html.ini
@@ -1,5 +1,4 @@
 [securitypolicyviolation-block-cross-origin-image.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Non-redirected cross-origin URLs are not stripped.]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html.ini
+++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html.ini
@@ -1,5 +1,4 @@
 [securitypolicyviolation-block-image-from-script.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Non-redirected cross-origin URLs are not stripped.]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[securitypolicyviolation-block-image.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/targeting.html.ini
+++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/targeting.html.ini
@@ -1,10 +1,10 @@
 [targeting.html]
-  prefs: [dom.webcomponents.shadowdom.enabled:true, security.csp.enable_violation_events:true]
+  prefs: [dom.webcomponents.shadowdom.enabled:true]
   expected: TIMEOUT
   [These tests should not fail.]
     expected: NOTRUN
 
   [Inline violations target the right element.]
     expected: FAIL
 
   [Correct targeting inside shadow tree (inline handler).]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[upgrade-insecure-requests-reporting.https.html]
-  type: testharness
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/injected-inline-style-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[injected-inline-style-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/inline-style-allowed-while-cloning-objects.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[inline-style-allowed-while-cloning-objects.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/inline-style-attribute-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[inline-style-attribute-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-hash-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-hash-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-imported-style-blocked.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[style-src-imported-style-blocked.html]
-  type: testharness
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-injected-inline-style-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-injected-inline-style-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-injected-stylesheet-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-injected-stylesheet-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-attribute-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-inline-style-attribute-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-inline-style-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini
+++ b/testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked-error-event.html.ini
@@ -1,6 +1,5 @@
 [style-src-inline-style-nonce-blocked-error-event.html]
   expected: TIMEOUT
-  prefs: [security.csp.enable_violation_events:true]
   [Test that paragraph remains unmodified and error events received.]
     expected: NOTRUN
 
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-inline-style-nonce-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-inline-style-nonce-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-none-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-none-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/style-src-stylesheet-nonce-blocked.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-src-stylesheet-nonce-blocked.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/stylehash-basic-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[stylehash-basic-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/stylenonce-allowed.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[stylenonce-allowed.sub.html]
-  type: testharness
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/style-src/stylenonce-blocked.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[stylenonce-blocked.sub.html]
-  type: testharness
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[object-in-svg-foreignobject.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/svg/svg-inline.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[svg-inline.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/unsafe-eval/eval-blocked-and-sends-report.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[eval-blocked-and-sends-report.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/unsafe-eval/eval-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[eval-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/unsafe-eval/eval-scripts-setInterval-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[eval-scripts-setInterval-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/unsafe-eval/eval-scripts-setTimeout-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[eval-scripts-setTimeout-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/unsafe-eval/function-constructor-blocked.sub.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[function-constructor-blocked.sub.html]
-  prefs: [security.csp.enable_violation_events:true]
--- a/testing/web-platform/meta/content-security-policy/unsafe-hashed-attributes/script_event_handlers_allowed.html.ini
+++ b/testing/web-platform/meta/content-security-policy/unsafe-hashed-attributes/script_event_handlers_allowed.html.ini
@@ -1,5 +1,4 @@
 [script_event_handlers_allowed.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that the inline event handler is allowed to run]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/unsafe-hashed-attributes/script_event_handlers_denied_matching_hash_no_unsafe_inline_attribute.html.ini
+++ b/testing/web-platform/meta/content-security-policy/unsafe-hashed-attributes/script_event_handlers_denied_matching_hash_no_unsafe_inline_attribute.html.ini
@@ -1,5 +1,4 @@
 [script_event_handlers_denied_matching_hash_no_unsafe_inline_attribute.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that the inline event handler is not allowed to run]
     expected: FAIL
 
--- a/testing/web-platform/meta/content-security-policy/unsafe-hashed-attributes/script_event_handlers_denied_not_matching_hash.html.ini
+++ b/testing/web-platform/meta/content-security-policy/unsafe-hashed-attributes/script_event_handlers_denied_not_matching_hash.html.ini
@@ -1,5 +1,4 @@
 [script_event_handlers_denied_not_matching_hash.html]
-  prefs: [security.csp.enable_violation_events:true]
   [Test that the inline event handler is not allowed to run]
     expected: FAIL
 
--- a/toolkit/components/autocomplete/nsIAutoCompleteInput.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteInput.idl
@@ -55,28 +55,16 @@ interface nsIAutoCompleteInput : nsISupp
   attribute unsigned long minResultsForPopup;
 
   /*
    * The maximum number of rows to show in the autocomplete popup.
    */
   attribute unsigned long maxRows;
 
   /*
-   * Option to show a second column in the popup which contains
-   * the comment for each autocomplete result
-   */
-  attribute boolean showCommentColumn;
-
-  /*
-   * Option to show a third column in the popup which contains
-   * an additional image for each autocomplete result
-   */
-  attribute boolean showImageColumn;
-
-  /*
    * Number of milliseconds after a keystroke before a search begins
    */
   attribute unsigned long timeout;
 
   /*
    * An extra parameter to configure searches with.
    */
   attribute AString searchParam;
--- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
+++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
@@ -57,19 +57,16 @@ AutoCompleteInput.prototype = {
   disableAutoComplete: false,
   completeDefaultIndex: true,
   completeSelectedIndex: true,
   forceComplete: false,
 
   minResultsForPopup: 0,
   maxRows: 0,
 
-  showCommentColumn: false,
-  showImageColumn: false,
-
   timeout: 10,
   searchParam: "",
 
   get searchCount() {
     return this.searches.length;
   },
   getSearchAt(aIndex) {
     return this.searches[aIndex];
--- a/toolkit/components/satchel/AutoCompletePopup.jsm
+++ b/toolkit/components/satchel/AutoCompletePopup.jsm
@@ -182,18 +182,16 @@ this.AutoCompletePopup = {
       // Reset fields that were set from the last time the search popup was open
       this.openedPopup.mInput = AutoCompleteResultView;
       // Temporarily increase the maxRows as we don't want to show
       // the scrollbar in form autofill popup.
       if (firstResultStyle == "autofill-profile") {
         this.openedPopup._normalMaxRows = this.openedPopup.maxRows;
         this.openedPopup.mInput.maxRows = 100;
       }
-      this.openedPopup.showCommentColumn = false;
-      this.openedPopup.showImageColumn = false;
       this.openedPopup.addEventListener("popuphidden", this);
       this.openedPopup.addEventListener("popupshowing", this);
       this.openedPopup.openPopupAtScreenRect("after_start", rect.left, rect.top,
                                              rect.width, rect.height, false,
                                              false);
       this.openedPopup.invalidate();
     } else {
       this.closePopup();
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -514,41 +514,16 @@ nsFormFillController::GetMaxRows(uint32_
 NS_IMETHODIMP
 nsFormFillController::SetMaxRows(uint32_t aMaxRows)
 {
   mMaxRows = aMaxRows;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFormFillController::GetShowImageColumn(bool *aShowImageColumn)
-{
-  *aShowImageColumn = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsFormFillController::SetShowImageColumn(bool aShowImageColumn)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-
-NS_IMETHODIMP
-nsFormFillController::GetShowCommentColumn(bool *aShowCommentColumn)
-{
-  *aShowCommentColumn = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsFormFillController::SetShowCommentColumn(bool aShowCommentColumn)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
 nsFormFillController::GetTimeout(uint32_t *aTimeout)
 {
   *aTimeout = mTimeout;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsFormFillController::SetTimeout(uint32_t aTimeout)
 {
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -72,17 +72,18 @@
 
           let popup = null;
           let popupId = this.getAttribute("autocompletepopup");
           if (popupId) {
             popup = document.getElementById(popupId);
           }
           if (!popup) {
             popup = document.createElement("panel");
-            popup.setAttribute("type", "autocomplete");
+            popup.setAttribute("type", "autocomplete-richlistbox");
+            popup.setAttribute("autogenerated", "true");
             popup.setAttribute("noautofocus", "true");
 
             let popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
             popupset.appendChild(popup);
           }
           popup.mInput = this;
 
           return this._popup = popup;
@@ -110,24 +111,16 @@
       <property name="forceComplete"
                 onset="this.setAttribute('forcecomplete', val); return val;"
                 onget="return this.getAttribute('forcecomplete') == 'true';"/>
 
       <property name="minResultsForPopup"
                 onset="this.setAttribute('minresultsforpopup', val); return val;"
                 onget="var m = parseInt(this.getAttribute('minresultsforpopup')); return isNaN(m) ? 1 : m;"/>
 
-      <property name="showCommentColumn"
-                onset="this.setAttribute('showcommentcolumn', val); return val;"
-                onget="return this.getAttribute('showcommentcolumn') == 'true';"/>
-
-      <property name="showImageColumn"
-                onset="this.setAttribute('showimagecolumn', val); return val;"
-                onget="return this.getAttribute('showimagecolumn') == 'true';"/>
-
       <property name="timeout"
                 onset="this.setAttribute('timeout', val); return val;">
         <getter><![CDATA[
           // For security reasons delay searches on pasted values.
           if (this._valueIsPasted) {
             let t = parseInt(this.getAttribute("pastetimeout"));
             return isNaN(t) ? 1000 : t;
           }
@@ -664,231 +657,34 @@
           }
           if (!this.ignoreBlurWhileSearching)
             this.detachController();
         }
       ]]></handler>
     </handlers>
   </binding>
 
-  <binding id="autocomplete-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-base-popup">
+  <binding id="autocomplete-rich-result-popup" extends="chrome://global/content/bindings/popup.xml#popup">
     <resources>
       <stylesheet src="chrome://global/content/autocomplete.css"/>
-      <stylesheet src="chrome://global/skin/tree.css"/>
       <stylesheet src="chrome://global/skin/autocomplete.css"/>
     </resources>
 
     <content ignorekeys="true" level="top" consumeoutsideclicks="never">
-      <xul:tree anonid="tree" class="autocomplete-tree plain" hidecolumnpicker="true" flex="1" seltype="single">
-        <xul:treecols anonid="treecols">
-          <xul:treecol id="treecolAutoCompleteValue" class="autocomplete-treecol" flex="1" overflow="true"/>
-        </xul:treecols>
-        <xul:treechildren class="autocomplete-treebody"/>
-      </xul:tree>
+      <xul:richlistbox anonid="richlistbox" class="autocomplete-richlistbox" flex="1"/>
+      <xul:hbox>
+        <children/>
+      </xul:hbox>
     </content>
 
-    <implementation>
-      <field name="mShowCommentColumn">false</field>
-      <field name="mShowImageColumn">false</field>
-
-      <property name="showCommentColumn"
-                   onget="return this.mShowCommentColumn;">
-        <setter>
-          <![CDATA[
-          if (!val && this.mShowCommentColumn) {
-            // reset the flex on the value column and remove the comment column
-            document.getElementById("treecolAutoCompleteValue").setAttribute("flex", 1);
-            this.removeColumn("treecolAutoCompleteComment");
-          } else if (val && !this.mShowCommentColumn) {
-            // reset the flex on the value column and add the comment column
-            document.getElementById("treecolAutoCompleteValue").setAttribute("flex", 2);
-            this.addColumn({id: "treecolAutoCompleteComment", flex: 1});
-          }
-          this.mShowCommentColumn = val;
-          return val;
-        ]]>
-        </setter>
-      </property>
-
-      <property name="showImageColumn"
-                onget="return this.mShowImageColumn;">
-        <setter>
-          <![CDATA[
-          if (!val && this.mShowImageColumn) {
-            // remove the image column
-            this.removeColumn("treecolAutoCompleteImage");
-          } else if (val && !this.mShowImageColumn) {
-            // add the image column
-            this.addColumn({id: "treecolAutoCompleteImage", flex: 1});
-          }
-          this.mShowImageColumn = val;
-          return val;
-        ]]>
-        </setter>
-      </property>
-
-
-      <method name="addColumn">
-        <parameter name="aAttrs"/>
-        <body>
-          <![CDATA[
-          var col = document.createElement("treecol");
-          col.setAttribute("class", "autocomplete-treecol");
-          for (var name in aAttrs)
-            col.setAttribute(name, aAttrs[name]);
-          this.treecols.appendChild(col);
-          return col;
-        ]]>
-        </body>
-      </method>
-
-      <method name="removeColumn">
-        <parameter name="aColId"/>
-        <body>
-          <![CDATA[
-          return this.treecols.removeChild(document.getElementById(aColId));
-        ]]>
-        </body>
-      </method>
-
-      <property name="selectedIndex"
-                onget="return this.tree.currentIndex;">
-        <setter>
-          <![CDATA[
-          this.tree.view.selection.select(val);
-          if (this.tree.treeBoxObject.height > 0)
-            this.tree.treeBoxObject.ensureRowIsVisible(val < 0 ? 0 : val);
-          // Fire select event on xul:tree so that accessibility API
-          // support layer can fire appropriate accessibility events.
-          var event = document.createEvent("Events");
-          event.initEvent("select", true, true);
-          this.tree.dispatchEvent(event);
-          return val;
-        ]]></setter>
-      </property>
-
-      <method name="adjustHeight">
-        <body>
-          <![CDATA[
-          // detect the desired height of the tree
-          var bx = this.tree.treeBoxObject;
-          var view = this.tree.view;
-          if (!view)
-            return;
-          var rows = this.maxRows;
-          if (!view.rowCount || (rows && view.rowCount < rows))
-            rows = view.rowCount;
-
-          var height = rows * bx.rowHeight;
-
-          if (height == 0) {
-            this.tree.setAttribute("collapsed", "true");
-          } else {
-            if (this.tree.hasAttribute("collapsed"))
-              this.tree.removeAttribute("collapsed");
-
-            this.tree.setAttribute("height", height);
-          }
-          this.tree.setAttribute("hidescrollbar", view.rowCount <= rows);
-        ]]>
-        </body>
-      </method>
-
-      <method name="openAutocompletePopup">
-        <parameter name="aInput"/>
-        <parameter name="aElement"/>
-        <body><![CDATA[
-          // until we have "baseBinding", (see bug #373652) this allows
-          // us to override openAutocompletePopup(), but still call
-          // the method on the base class
-          this._openAutocompletePopup(aInput, aElement);
-        ]]></body>
-      </method>
-
-      <method name="_openAutocompletePopup">
-        <parameter name="aInput"/>
-        <parameter name="aElement"/>
-        <body><![CDATA[
-          if (!this.mPopupOpen) {
-            this.mInput = aInput;
-            this.view = aInput.controller.QueryInterface(Components.interfaces.nsITreeView);
-            this.invalidate();
-
-            this.showCommentColumn = this.mInput.showCommentColumn;
-            this.showImageColumn = this.mInput.showImageColumn;
-
-            var rect = aElement.getBoundingClientRect();
-            var nav = aElement.ownerGlobal.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                              .getInterface(Components.interfaces.nsIWebNavigation);
-            var docShell = nav.QueryInterface(Components.interfaces.nsIDocShell);
-            var docViewer = docShell.contentViewer;
-            var width = (rect.right - rect.left) * docViewer.fullZoom;
-            this.setAttribute("width", width > 100 ? width : 100);
-
-            // Adjust the direction of the autocomplete popup list based on the textbox direction, bug 649840
-            var popupDirection = aElement.ownerGlobal.getComputedStyle(aElement).direction;
-            this.style.direction = popupDirection;
-
-            this.openPopup(aElement, "after_start", 0, 0, false, false);
-          }
-        ]]></body>
-      </method>
-
-      <method name="invalidate">
-        <body><![CDATA[
-          this.adjustHeight();
-          this.tree.treeBoxObject.invalidate();
-        ]]></body>
-      </method>
-
-      <method name="selectBy">
-        <parameter name="aReverse"/>
-        <parameter name="aPage"/>
-        <body><![CDATA[
-          try {
-            var amount = aPage ? 5 : 1;
-            this.selectedIndex = this.getNextIndex(aReverse, amount, this.selectedIndex, this.tree.view.rowCount - 1);
-            if (this.selectedIndex == -1) {
-              this.input._focus();
-            }
-          } catch (ex) {
-            // do nothing - occasionally timer-related js errors happen here
-            // e.g. "this.selectedIndex has no properties", when you type fast and hit a
-            // navigation key before this popup has opened
-          }
-        ]]></body>
-      </method>
-
-      <!-- =================== PUBLIC MEMBERS =================== -->
-
-      <field name="tree">
-        document.getAnonymousElementByAttribute(this, "anonid", "tree");
-      </field>
-
-      <field name="treecols">
-        document.getAnonymousElementByAttribute(this, "anonid", "treecols");
-      </field>
-
-      <property name="view"
-                onget="return this.mView;">
-        <setter><![CDATA[
-          // We must do this by hand because the tree binding may not be ready yet
-          this.mView = val;
-          this.tree.boxObject.view = val;
-        ]]></setter>
-      </property>
-
-    </implementation>
-  </binding>
-
-  <binding id="autocomplete-base-popup" role="none"
-extends="chrome://global/content/bindings/popup.xml#popup">
     <implementation implements="nsIAutoCompletePopup">
       <field name="mInput">null</field>
       <field name="mPopupOpen">false</field>
+      <field name="_currentIndex">0</field>
+      <field name="_rlbAnimated">false</field>
 
       <!-- =================== nsIAutoCompletePopup =================== -->
 
       <property name="input" readonly="true"
                 onget="return this.mInput"/>
 
       <property name="overrideValue" readonly="true"
                 onget="return null;"/>
@@ -957,96 +753,16 @@ extends="chrome://global/content/binding
 
       <method name="onPopupClick">
         <parameter name="aEvent"/>
         <body><![CDATA[
           var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
           controller.handleEnter(true, aEvent);
         ]]></body>
       </method>
-    </implementation>
-
-    <handlers>
-      <handler event="popupshowing"><![CDATA[
-        // If normalMaxRows wasn't already set by the input, then set it here
-        // so that we restore the correct number when the popup is hidden.
-
-        // Null-check this.mInput; see bug 1017914
-        if (this._normalMaxRows < 0 && this.mInput) {
-          this._normalMaxRows = this.mInput.maxRows;
-        }
-
-        // Set an attribute for styling the popup based on the input.
-        let inputID = "";
-        if (this.mInput && this.mInput.ownerDocument &&
-            this.mInput.ownerDocument.documentURIObject.schemeIs("chrome")) {
-          inputID = this.mInput.id;
-          // Take care of elements with no id that are inside xbl bindings
-          if (!inputID) {
-            let bindingParent = this.mInput.ownerDocument.getBindingParent(this.mInput);
-            if (bindingParent) {
-              inputID = bindingParent.id;
-            }
-          }
-        }
-        this.setAttribute("autocompleteinput", inputID);
-
-        this.mPopupOpen = true;
-      ]]></handler>
-
-      <handler event="popuphiding"><![CDATA[
-        var isListActive = true;
-        if (this.selectedIndex == -1)
-          isListActive = false;
-        var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
-        controller.stopSearch();
-
-        this.removeAttribute("autocompleteinput");
-        this.mPopupOpen = false;
-
-        // Reset the maxRows property to the cached "normal" value (if there's
-        // any), and reset normalMaxRows so that we can detect whether it was set
-        // by the input when the popupshowing handler runs.
-
-        // Null-check this.mInput; see bug 1017914
-        if (this.mInput && this._normalMaxRows > 0) {
-          this.mInput.maxRows = this._normalMaxRows;
-        }
-        this._normalMaxRows = -1;
-        // If the list was being navigated and then closed, make sure
-        // we fire accessible focus event back to textbox
-
-        // Null-check this.mInput; see bug 1017914
-        if (isListActive && this.mInput) {
-          this.mInput.mIgnoreFocus = true;
-          this.mInput._focus();
-          this.mInput.mIgnoreFocus = false;
-        }
-      ]]></handler>
-    </handlers>
-  </binding>
-
-  <binding id="autocomplete-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-base-popup">
-    <resources>
-      <stylesheet src="chrome://global/content/autocomplete.css"/>
-      <stylesheet src="chrome://global/skin/autocomplete.css"/>
-    </resources>
-
-    <content ignorekeys="true" level="top" consumeoutsideclicks="never">
-      <xul:richlistbox anonid="richlistbox" class="autocomplete-richlistbox" flex="1"/>
-      <xul:hbox>
-        <children/>
-      </xul:hbox>
-    </content>
-
-    <implementation implements="nsIAutoCompletePopup">
-      <field name="_currentIndex">0</field>
-      <field name="_rlbAnimated">false</field>
-
-      <!-- =================== nsIAutoCompletePopup =================== -->
 
       <property name="selectedIndex"
                 onget="return this.richlistbox.selectedIndex;">
         <setter>
           <![CDATA[
           this.richlistbox.selectedIndex = val;
           // Since ensureElementIsVisible may cause an expensive Layout flush,
           // invoke it only if there may be a scrollbar, so if we could fetch
@@ -1418,24 +1134,81 @@ extends="chrome://global/content/binding
       </field>
 
       <property name="view"
                 onget="return this.mInput.controller;"
                 onset="return val;"/>
 
     </implementation>
     <handlers>
+      <handler event="popupshowing"><![CDATA[
+        // If normalMaxRows wasn't already set by the input, then set it here
+        // so that we restore the correct number when the popup is hidden.
+
+        // Null-check this.mInput; see bug 1017914
+        if (this._normalMaxRows < 0 && this.mInput) {
+          this._normalMaxRows = this.mInput.maxRows;
+        }
+
+        // Set an attribute for styling the popup based on the input.
+        let inputID = "";
+        if (this.mInput && this.mInput.ownerDocument &&
+            this.mInput.ownerDocument.documentURIObject.schemeIs("chrome")) {
+          inputID = this.mInput.id;
+          // Take care of elements with no id that are inside xbl bindings
+          if (!inputID) {
+            let bindingParent = this.mInput.ownerDocument.getBindingParent(this.mInput);
+            if (bindingParent) {
+              inputID = bindingParent.id;
+            }
+          }
+        }
+        this.setAttribute("autocompleteinput", inputID);
+
+        this.mPopupOpen = true;
+      ]]></handler>
+
       <handler event="popupshown">
         <![CDATA[
           if (this._adjustHeightOnPopupShown) {
             delete this._adjustHeightOnPopupShown;
             this.adjustHeight();
           }
       ]]>
       </handler>
+
+      <handler event="popuphiding"><![CDATA[
+        var isListActive = true;
+        if (this.selectedIndex == -1)
+          isListActive = false;
+        var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
+        controller.stopSearch();
+
+        this.removeAttribute("autocompleteinput");
+        this.mPopupOpen = false;
+
+        // Reset the maxRows property to the cached "normal" value (if there's
+        // any), and reset normalMaxRows so that we can detect whether it was set
+        // by the input when the popupshowing handler runs.
+
+        // Null-check this.mInput; see bug 1017914
+        if (this.mInput && this._normalMaxRows > 0) {
+          this.mInput.maxRows = this._normalMaxRows;
+        }
+        this._normalMaxRows = -1;
+        // If the list was being navigated and then closed, make sure
+        // we fire accessible focus event back to textbox
+
+        // Null-check this.mInput; see bug 1017914
+        if (isListActive && this.mInput) {
+          this.mInput.mIgnoreFocus = true;
+          this.mInput._focus();
+          this.mInput.mIgnoreFocus = false;
+        }
+      ]]></handler>
     </handlers>
   </binding>
 
   <binding id="autocomplete-richlistitem-insecure-field" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistitem">
     <content align="center"
              onoverflow="this._onOverflow();"
              onunderflow="this._onUnderflow();">
       <xul:image anonid="type-icon"
@@ -2446,25 +2219,16 @@ extends="chrome://global/content/binding
         if (!this.selected) {
           control.selectItem(this);
         }
         control.currentItem = this;
       ]]></handler>
     </handlers>
   </binding>
 
-  <binding id="autocomplete-tree" extends="chrome://global/content/bindings/tree.xml#tree">
-    <content>
-      <children includes="treecols"/>
-      <xul:treerows class="autocomplete-treerows tree-rows" xbl:inherits="hidescrollbar" flex="1">
-        <children/>
-      </xul:treerows>
-    </content>
-  </binding>
-
   <binding id="autocomplete-richlistbox" extends="chrome://global/content/bindings/richlistbox.xml#richlistbox">
     <implementation>
       <field name="mLastMoveTime">Date.now()</field>
       <field name="mousedOverIndex">-1</field>
     </implementation>
     <handlers>
       <handler event="mouseup">
         <![CDATA[
@@ -2504,62 +2268,9 @@ extends="chrome://global/content/binding
           this.selectedIndex = index;
         }
 
         this.mLastMoveTime = Date.now();
       ]]>
       </handler>
     </handlers>
   </binding>
-
-  <binding id="autocomplete-treebody">
-    <implementation>
-      <field name="mLastMoveTime">Date.now()</field>
-      <property name="noSelectOnMouseMove">
-        <getter><![CDATA[
-          return this.getAttribute("noSelectOnMouseMove") == "true";
-        ]]></getter>
-        <setter><![CDATA[
-          if (val) {
-            this.setAttribute("noSelectOnMouseMove", "true");
-          } else {
-            this.removeAttribute("noSelectOnMouseMove");
-          }
-          return !!val;
-        ]]></setter>
-      </property>
-    </implementation>
-
-    <handlers>
-      <handler event="mouseup" action="this.parentNode.parentNode.onPopupClick(event);"/>
-
-      <handler event="mousedown"><![CDATA[
-         var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY);
-         if (rc != this.parentNode.currentIndex)
-            this.parentNode.view.selection.select(rc);
-      ]]></handler>
-
-      <handler event="mousemove"><![CDATA[
-        if (this.noSelectOnMouseMove) {
-          // Allow uses of this binding to cancel the event so that
-          // nothing is selected.
-          return;
-        }
-        if (Date.now() - this.mLastMoveTime > 30) {
-         var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY);
-         if (rc != this.parentNode.currentIndex)
-            this.parentNode.view.selection.select(rc);
-         this.mLastMoveTime = Date.now();
-        }
-      ]]></handler>
-    </handlers>
-  </binding>
-
-  <binding id="autocomplete-treerows">
-    <content>
-      <xul:hbox flex="1" class="tree-bodybox">
-        <children/>
-      </xul:hbox>
-      <xul:scrollbar xbl:inherits="collapsed=hidescrollbar" orient="vertical" class="tree-scrollbar"/>
-    </content>
-  </binding>
-
 </bindings>
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -794,62 +794,37 @@ textbox[type="number"] {
 
 /* SeaMonkey uses its own autocomplete and the toolkit's autocomplete widget */
 %ifndef MOZ_SUITE
 
 textbox[type="autocomplete"] {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete");
 }
 
-panel[type="autocomplete"] {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-result-popup");
-}
-
 panel[type="autocomplete-richlistbox"] {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup");
 }
 
-/* FIXME: bug 616258 */
-
-.autocomplete-tree {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-tree");
-  -moz-user-focus: ignore;
-}
-
-.autocomplete-treebody {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-treebody");
-}
-
 .autocomplete-richlistbox {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistbox");
   -moz-user-focus: ignore;
 }
 
 .autocomplete-richlistbox > scrollbox {
   overflow-x: hidden !important;
 }
 
 .autocomplete-richlistitem {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistitem");
   -moz-box-orient: vertical;
   overflow: -moz-hidden-unscrollable;
 }
 
-.autocomplete-treerows {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-treerows");
-}
-
 %endif
 
-/* the C++ implementation of widgets is too eager to make popups visible.
-   this causes problems (bug 120155 and others), thus this workaround: */
-popup[type="autocomplete"][hidden="true"] {
-  visibility: hidden;
-}
-
 /* The following rule is here to fix bug 96899 (and now 117952).
    Somehow trees create a situation
    in which a popupset flows itself as if its popup child is directly within it
    instead of the placeholder child that should actually be inside the popupset.
    This is a stopgap measure, and it does not address the real bug.  */
 .autocomplete-result-popupset {
   max-width: 0px;
   width: 0 !important;
--- a/toolkit/themes/linux/global/autocomplete.css
+++ b/toolkit/themes/linux/global/autocomplete.css
@@ -12,67 +12,29 @@
 /* ::::: autocomplete ::::: */
 
 textbox[nomatch="true"][highlightnonmatches="true"] {
   color: red;
 }
 
 /* ::::: autocomplete popups ::::: */
 
-panel[type="autocomplete"],
 panel[type="autocomplete-richlistbox"],
 .autocomplete-history-popup {
   border: 1px solid ThreeDShadow;
   padding: 0;
   color: -moz-FieldText;
   background-color: -moz-Field;
   -moz-appearance: none;
 }
 
 .autocomplete-history-popup {
   max-height: 180px;
 }
 
-/* ::::: tree ::::: */
-
-.autocomplete-tree {
-  -moz-appearance: none !important;
-  border: none !important;
-  background-color: transparent !important;
-}
-
-.autocomplete-treecol {
-  -moz-appearance: none !important;
-  margin: 0 !important;
-  border: none !important;
-  padding: 0 !important;
-}
-
-/* GTK calculates space for a sort arrow */
-.autocomplete-treecol > .treecol-sortdirection {
-  -moz-appearance: none !important;
-}
-
-.autocomplete-treebody::-moz-tree-cell-text {
-  padding-inline-start: 8px;
-}
-
-treechildren.autocomplete-treebody::-moz-tree-row(selected) {
- background-color: Highlight;
-}
-
-treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
-  color: HighlightText !important;
-}
-
-.autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) {
-  max-width: 16px;
-  height: 16px;
-}
-
 /* ::::: richlistbox autocomplete ::::: */
 
 .autocomplete-richlistbox {
   -moz-appearance: none;
   margin: 1px;
   background-color: transparent;
 }
 
@@ -135,14 +97,28 @@ html|span.ac-tag {
 .ac-separator-text,
 .ac-url-text,
 .ac-action-text,
 .ac-text-overflow-container {
   padding: 0 !important;
   margin: 0 !important;
 }
 
+/* ::::: simple richlistbox autocomplete ::::: */
+
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-type-icon,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-tags,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-separator,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-url,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-action {
+  display: none;
+}
+
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-site-icon {
+  margin-inline-start: 6px;
+}
+
 /* ::::: textboxes inside toolbarpaletteitems ::::: */
 
 toolbarpaletteitem > toolbaritem > textbox > .textbox-input-box > html|*.textbox-input,
 toolbarpaletteitem > toolbaritem > * > textbox > .textbox-input-box > html|*.textbox-input {
   visibility: hidden;
 }
--- a/toolkit/themes/linux/global/tree.css
+++ b/toolkit/themes/linux/global/tree.css
@@ -31,25 +31,25 @@ tree {
 /* ::::: tree rows ::::: */
 
 treechildren::-moz-tree-row {
   border: 1px solid transparent;
   min-height: 18px;
   height: 1.3em;
 }
 
-treechildren:not(.autocomplete-treebody)::-moz-tree-row(multicol, odd) {
+treechildren::-moz-tree-row(multicol, odd) {
   background-color: -moz-oddtreerow;
 }
 
-treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected) {
+treechildren::-moz-tree-row(selected) {
   background-color: -moz-cellhighlight;
 }
 
-treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected, focus) {
+treechildren::-moz-tree-row(selected, focus) {
   background-color: Highlight;
 }
 
 treechildren::-moz-tree-row(current, focus) {
   border: 1px dotted Highlight;
 }
 
 treechildren::-moz-tree-row(selected, current, focus) {
--- a/toolkit/themes/osx/global/autocomplete.css
+++ b/toolkit/themes/osx/global/autocomplete.css
@@ -6,66 +6,29 @@
 @namespace html url("http://www.w3.org/1999/xhtml");
 
 textbox[nomatch="true"][highlightnonmatches="true"] {
   color: red;
 }
 
 /* ::::: autocomplete popups ::::: */
 
-panel[type="autocomplete"],
 panel[type="autocomplete-richlistbox"],
 .autocomplete-history-popup {
   padding: 0px !important;
   color: -moz-FieldText;
   background-color: -moz-Field;
   font: icon;
   -moz-appearance: none;
 }
 
 .autocomplete-history-popup {
   max-height: 180px;
 }
 
-/* ::::: tree ::::: */
-
-.autocomplete-tree {
-  -moz-appearance: none !important;
-  border: none !important;
-  background-color: transparent !important;
-}
-
-.autocomplete-treecol {
-  -moz-appearance: none !important;
-  margin: 0 !important;
-  border: none !important;
-  padding: 0 !important;
-}
-
-.autocomplete-treebody::-moz-tree-cell-text {
-  padding-left: 2px;
-}
-
-.autocomplete-treebody::-moz-tree-row {
-  border-top: none;
-}
-
-treechildren.autocomplete-treebody::-moz-tree-row(selected) {
- background-color: Highlight;
-}
-
-treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
-  color: HighlightText !important;
-}
-
-.autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) {
-  max-width: 16px;
-  height: 16px;
-}
-
 /* ::::: richlistbox autocomplete ::::: */
 
 .autocomplete-richlistbox {
   -moz-appearance: none;
   margin: 0;
 }
 
 .ac-type-icon {
@@ -122,14 +85,28 @@ html|span.ac-tag {
 .ac-separator-text,
 .ac-url-text,
 .ac-action-text,
 .ac-text-overflow-container {
   padding: 0 !important;
   margin: 0 !important;
 }
 
+/* ::::: simple richlistbox autocomplete ::::: */
+
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-type-icon,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-tags,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-separator,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-url,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-action {
+  display: none;
+}
+
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-site-icon {
+  margin-inline-start: 6px;
+}
+
 /* ::::: textboxes inside toolbarpaletteitems ::::: */
 
 toolbarpaletteitem > toolbaritem > textbox > .textbox-input-box > html|*.textbox-input,
 toolbarpaletteitem > toolbaritem > * > textbox > .textbox-input-box > html|*.textbox-input {
   visibility: hidden;
 }
--- a/toolkit/themes/osx/global/tree.css
+++ b/toolkit/themes/osx/global/tree.css
@@ -26,25 +26,25 @@ tree {
 /* ::::: tree rows ::::: */
 
 treechildren::-moz-tree-row {
   border-top: 1px solid transparent;
   height: 18px;
   background-color: -moz-field;
 }
 
-treechildren:not(.autocomplete-treebody)::-moz-tree-row(multicol, odd) {
+treechildren::-moz-tree-row(multicol, odd) {
   background-color: -moz-oddtreerow;
 }
 
-treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected) {
+treechildren::-moz-tree-row(selected) {
   background-color: -moz-mac-secondaryhighlight;
 }
 
-treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected, focus) {
+treechildren::-moz-tree-row(selected, focus) {
   background-color: Highlight;
   color: HighlightText;
 }
 
 tree[seltype="cell"] > treechildren::-moz-tree-row,
 tree[seltype="text"] > treechildren::-moz-tree-row {
   border-top: none;
   background-color: transparent;
--- a/toolkit/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -837,20 +837,16 @@ xul|richlistbox:-moz-focusring {
 xul|listheader,
 xul|treecols {
   -moz-appearance: none;
   border: none;
   border-bottom: 1px solid var(--in-content-border-color);
   padding: 0;
 }
 
-.autocomplete-tree > xul|treecols {
-  border-bottom: none !important;
-}
-
 xul|treecol:not([hideheader="true"]),
 xul|treecolpicker {
   -moz-appearance: none;
   border: none;
   background-color: var(--in-content-box-background-hover);
   color: #808080;
   padding: 5px 10px;
 }
--- a/toolkit/themes/windows/global/autocomplete.css
+++ b/toolkit/themes/windows/global/autocomplete.css
@@ -12,66 +12,28 @@
 /* ::::: autocomplete ::::: */
 
 textbox[nomatch="true"][highlightnonmatches="true"] {
   color: red;
 }
 
 /* ::::: autocomplete popups ::::: */
 
-panel[type="autocomplete"],
 panel[type="autocomplete-richlistbox"],
 .autocomplete-history-popup {
   -moz-appearance: none;
   padding: 0;
   color: -moz-FieldText;
   background-color: -moz-Field;
 }
 
 .autocomplete-history-popup {
   max-height: 180px;
 }
 
-/* ::::: tree ::::: */
-
-.autocomplete-tree {
-  -moz-appearance: none !important;
-  border: none !important;
-  background-color: transparent !important;
-}
-
-.autocomplete-treecol {
-  -moz-appearance: none !important;
-  margin: 0 !important;
-  border: none !important;
-  padding: 0 !important;
-}
-
-/* GTK calculates space for a sort arrow */
-.autocomplete-treecol > .treecol-sortdirection {
-  -moz-appearance: none !important;
-}
-
-.autocomplete-treebody::-moz-tree-cell-text {
-  padding-inline-start: 8px;
-}
-
-treechildren.autocomplete-treebody::-moz-tree-row(selected) {
- background-color: Highlight;
-}
-
-treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
-  color: HighlightText !important;
-}
-
-.autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) {
-  max-width: 16px;
-  height: 16px;
-}
-
 /* ::::: richlistbox autocomplete ::::: */
 
 .autocomplete-richlistbox {
   -moz-appearance: none;
   margin: 0;
 }
 
 .autocomplete-richlistitem[selected] {
@@ -133,15 +95,29 @@ html|span.ac-tag {
 .ac-separator-text,
 .ac-url-text,
 .ac-action-text,
 .ac-text-overflow-container {
   padding: 0 !important;
   margin: 0 !important;
 }
 
+/* ::::: simple richlistbox autocomplete ::::: */
+
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-type-icon,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-tags,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-separator,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-url,
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-action {
+  display: none;
+}
+
+panel[type="autocomplete-richlistbox"][autogenerated] > .autocomplete-richlistbox > .autocomplete-richlistitem > .ac-site-icon {
+  margin-inline-start: 6px;
+}
+
 /* ::::: textboxes inside toolbarpaletteitems ::::: */
 
 toolbarpaletteitem > toolbaritem > textbox > .textbox-input-box> html|*.textbox-input,
 toolbarpaletteitem > toolbaritem > * > textbox > .textbox-input-box > html|*.textbox-input {
   visibility: hidden;
 }
 
--- a/toolkit/themes/windows/global/tree.css
+++ b/toolkit/themes/windows/global/tree.css
@@ -359,71 +359,71 @@ treechildren::-moz-tree-cell-text(active
     --treechildren-hoverCurrentBorder: var(--treechildren-currentColor);
     --treechildren-hoverCurrentBottomBorder: var(--treechildren-currentColor);
     --treechildren-hoverCurrentImage: linear-gradient(rgba(131,183,249,.16), rgba(131,183,249,.16));
     --treechildren-hoverSelectedBorder: var(--treechildren-focusColor);
     --treechildren-hoverSelectedBottomBorder: var(--treechildren-focusColor);
     --treechildren-hoverSelectedImage: linear-gradient(rgb(205,232,255), rgb(205,232,255));
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row {
+  treechildren::-moz-tree-row {
     height: 1.8em;
     color: -moz-FieldText;
     margin-inline-start: 1px;
     margin-inline-end: 1px;
     border-width: 1px;
     border-color: transparent;
     background-repeat: no-repeat;
     background-size: 100% 100%;
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected) {
+  treechildren::-moz-tree-row(selected) {
     border-color: var(--treechildren-selectedBorder);
     border-bottom-color: var(--treechildren-selectedBottomBorder);
     background-image: var(--treechildren-selectedImage);
     background-color: var(--treechildren-selectedBackground);
     outline: var(--treechildren-outline);
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(current, focus) {
+  treechildren::-moz-tree-row(current, focus) {
     border-style: solid;
     border-color: var(--treechildren-currentFocusBorder);
     border-bottom-color: var(--treechildren-currentFocusBottomBorder);
     outline: var(--treechildren-outline);
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected, focus),
+  treechildren::-moz-tree-row(selected, focus),
   treechildren::-moz-tree-row(dropOn) {
     border-color: var(--treechildren-selectedFocusBorder);
     border-bottom-color: var(--treechildren-selectedFocusBottomBorder);
     background-image: var(--treechildren-selectedFocusImage);
     background-color: var(--treechildren-selectedFocusBackground);
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected, current, focus) {
+  treechildren::-moz-tree-row(selected, current, focus) {
     border-style: solid;
     border-color: var(--treechildren-selectedFocusCurrentBorder);
     border-bottom-color: var(--treechildren-selectedFocusCurrentBottomBorder);
     background-image: var(--treechildren-selectedFocusCurrentImage);
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(hover) {
+  treechildren::-moz-tree-row(hover) {
     border-color: var(--treechildren-hoverBottomBorder);
     border-bottom-color: var(--treechildren-hoverBottomBorder);
     background-image: var(--treechildren-hoverImage);
     outline: var(--treechildren-outline);
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(hover, current) {
+  treechildren::-moz-tree-row(hover, current) {
     border-color: var(--treechildren-hoverCurrentBorder);
     border-bottom-color: var(--treechildren-hoverCurrentBottomBorder);
     background-image: var(--treechildren-hoverCurrentImage);
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-row(hover, selected) {
+  treechildren::-moz-tree-row(hover, selected) {
     border-color: var(--treechildren-hoverSelectedBorder);
     border-bottom-color: var(--treechildren-hoverSelectedBottomBorder);
     background-image: var(--treechildren-hoverSelectedImage);
   }
 
   tree[disabled="true"] > treechildren::-moz-tree-row {
     background: none;
     border-color: transparent;
@@ -434,23 +434,23 @@ treechildren::-moz-tree-cell-text(active
     background-color: transparent;
     border-radius: 0;
   }
 
   treechildren::-moz-tree-cell-text(primary, dropOn) {
     color: -moz-FieldText;
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-cell-text {
+  treechildren::-moz-tree-cell-text {
     padding-bottom: initial;
     border-color: transparent;
     background-color: transparent;
   }
 
-  treechildren:not(.autocomplete-treebody)::-moz-tree-cell-text(selected, focus) {
+  treechildren::-moz-tree-cell-text(selected, focus) {
     color: -moz-DialogText;
   }
 
   @media (-moz-os-version: windows-win7),
          (-moz-os-version: windows-win8) {
     treechildren {
       --treechildren-outline: 1px solid var(--treechildren-2ndBorderColor);
       --treechildren-selectedBorder: var(--treechildren-selectedColor);
@@ -479,15 +479,15 @@ treechildren::-moz-tree-cell-text(active
       --treechildren-selectedImage: linear-gradient(rgba(190,190,190,.1), rgba(190,190,190,.4));
       --treechildren-selectedFocusImage: linear-gradient(rgba(131,183,249,.16), rgba(131,183,249,.375));
       --treechildren-selectedFocusCurrentImage: linear-gradient(rgba(131,183,249,.28), rgba(131,183,249,.5));
       --treechildren-hoverImage: linear-gradient(rgba(131,183,249,.05), rgba(131,183,249,.16));
       --treechildren-hoverCurrentImage: linear-gradient(rgba(131,183,249,.05), rgba(131,183,249,.16));
       --treechildren-hoverSelectedImage: linear-gradient(rgba(131,183,249,.28), rgba(131,183,249,.5));
     }
 
-    treechildren:not(.autocomplete-treebody)::-moz-tree-row {
+    treechildren::-moz-tree-row {
       border-radius: 3px;
       -moz-outline-radius: 3px;
     }
   }
 }
 %endif