Merge inbound to mozilla-central. a=merge
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Sun, 02 Sep 2018 00:56:16 +0300
changeset 434422 8284cddccf78566ca4dc45272940ccae4b1150df
parent 434408 d718fc7c16e6d3db5e8a9fa3afae83727ea1e395 (current diff)
parent 434421 354e37362d068f8f120d759c6ed61507f46c2918 (diff)
child 434423 88b606c56fedc9027c0c07f39e13ff18b71b298b
child 434433 7f63a3e0614789ff83efd539a4395ee809d4af59
push id34555
push usernbeleuzu@mozilla.com
push dateSat, 01 Sep 2018 21:56:29 +0000
treeherdermozilla-central@8284cddccf78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
8284cddccf78 / 63.0a1 / 20180901220104 / files
nightly linux64
8284cddccf78 / 63.0a1 / 20180901220104 / files
nightly mac
8284cddccf78 / 63.0a1 / 20180901220104 / files
nightly win32
8284cddccf78 / 63.0a1 / 20180901220104 / files
nightly win64
8284cddccf78 / 63.0a1 / 20180901220104 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
toolkit/themes/linux/global/dropmarker.css
toolkit/themes/osx/global/dropmarker.css
toolkit/themes/windows/global/dropmarker.css
--- a/browser/base/content/contentTheme.js
+++ b/browser/base/content/contentTheme.js
@@ -29,16 +29,24 @@ const inContentVariableMap = [
         element.setAttribute("lwt-newtab-brighttext", "true");
       }
 
       return `rgba(${r}, ${g}, ${b}, ${a})`;
     },
   }],
   ["--lwt-sidebar-background-color", {
     lwtProperty: "sidebar",
+    processColor(rgbaChannels) {
+      if (!rgbaChannels) {
+        return null;
+      }
+      const {r, g, b} = rgbaChannels;
+      // Drop alpha channel
+      return `rgb(${r}, ${g}, ${b})`;
+    },
   }],
   ["--lwt-sidebar-text-color", {
     lwtProperty: "sidebar_text",
     processColor(rgbaChannels, element) {
       if (!rgbaChannels) {
         element.removeAttribute("lwt-sidebar");
         element.removeAttribute("lwt-sidebar-brighttext");
         return null;
--- a/browser/components/preferences/in-content/extensionControlled.js
+++ b/browser/components/preferences/in-content/extensionControlled.js
@@ -58,17 +58,19 @@ let extensionControlledContentIds = {
   },
 };
 
 const extensionControlledL10nKeys = {
   "homepage_override": "homepage-override",
   "newTabURL": "new-tab-url",
   "defaultSearch": "default-search",
   "privacy.containers": "privacy-containers",
-  "websites.trackingProtectionMode": "websites-tracking-protection-mode",
+  "websites.trackingProtectionMode": contentBlockingUiEnabled ?
+                                       "websites-content-blocking-all-trackers" :
+                                       "websites-tracking-protection-mode",
   "proxy.settings": "proxy-config",
 };
 
 let extensionControlledIds = {};
 
 /**
   * Check if a pref is being managed by an extension.
   */
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -517,16 +517,27 @@ var gPrivacyPane = {
       }
     }
 
     // Allow turning off the "(recommended)" label using a pref
     let blockCookiesFromTrackers = document.getElementById("blockCookiesFromTrackersCB");
     if (contentBlockingRejectTrackersRecommended) {
       document.l10n.setAttributes(blockCookiesFromTrackers, "content-blocking-reject-trackers-block-trackers-option-recommended");
     }
+
+    // Reorder the privacy pane to put the Content Blocking section first and the
+    // Cookies & Site Data section right after it.
+    let trackingGroup = document.getElementById("trackingGroup");
+    let siteDataGroup = document.getElementById("siteDataGroup");
+    let browserPrivacyCategory = document.getElementById("browserPrivacyCategory");
+
+    browserPrivacyCategory.parentNode.insertBefore(siteDataGroup,
+                                                   browserPrivacyCategory.nextSibling);
+    browserPrivacyCategory.parentNode.insertBefore(trackingGroup,
+                                                   browserPrivacyCategory.nextSibling);
   },
 
   /**
    * Resets all user-exposed content blocking preferences to their default values.
    */
   async restoreContentBlockingPrefs() {
     function clearIfNotLocked(pref) {
       if (!Services.prefs.prefIsLocked(pref)) {
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -339,17 +339,17 @@
         </vbox>
         <vbox class="content-blocking-category-icon">
           <image class="fastblock-icon content-blocking-icon"/>
         </vbox>
         <vbox class="content-blocking-category-labels" flex="1">
           <label data-l10n-id="content-blocking-fastblock-slow-loading-label"
                  class="content-blocking-category-name"
                  control="contentBlockingFastBlockCheckbox"/>
-          <description data-l10n-id="content-blocking-fastblock-description" class="content-blocking-category-description"/>
+          <description data-l10n-id="content-blocking-fastblock-new-description" class="content-blocking-category-description"/>
         </vbox>
       </hbox>
       <vbox>
         <hbox id="contentBlockingTrackingProtectionExtensionContentLabel" align="center" hidden="true">
           <description control="contentBlockingDisableTrackingProtectionExtension" flex="1"/>
         </hbox>
         <hbox id="contentBlockingTrackingProtectionExtensionContentButton" hidden="true">
           <button id="contentBlockingDisableTrackingProtectionExtension"
@@ -362,29 +362,29 @@
           </vbox>
           <vbox class="content-blocking-category-icon">
             <image class="tracking-protection-icon content-blocking-icon" />
           </vbox>
           <vbox class="content-blocking-category-labels" flex="1">
             <label data-l10n-id="content-blocking-tracking-protection-all-label"
                    class="content-blocking-category-name"
                    control="contentBlockingTrackingProtectionCheckbox"/>
-            <description data-l10n-id="content-blocking-tracking-protection-description"
+            <description data-l10n-id="content-blocking-tracking-protection-new-description"
                          class="content-blocking-category-description"
                          id="trackingProtectionMenuDesc"/>
             <radiogroup id="trackingProtectionMenu"
                         aria-labelledby="trackingProtectionMenuDesc">
               <radio value="private"
                      data-l10n-id="content-blocking-tracking-protection-option-private"
                      flex="1" />
               <radio value="always"
                      data-l10n-id="content-blocking-tracking-protection-option-always"
                      flex="1" />
             </radiogroup>
-            <label id="changeBlockListLink" data-l10n-id="content-blocking-tracking-protection-change-blocklist" class="text-link"/>
+            <label id="changeBlockListLink" data-l10n-id="content-blocking-tracking-protection-change-block-list" class="text-link"/>
           </vbox>
         </hbox>
       </vbox>
       <hbox class="content-blocking-category reject-trackers-ui">
         <hbox flex="1">
           <vbox class="content-blocking-category-checkbox">
             <checkbox id="contentBlockingBlockCookiesCheckbox" class="content-blocking-checkbox" />
           </vbox>
@@ -398,23 +398,23 @@
                        class="content-blocking-category-name"
                        control="contentBlockingBlockCookiesCheckbox"/>
                 <deck id="blockCookiesCBDeck">
                   <description id="blockCookiesCBDesc"
                                data-l10n-id="content-blocking-reject-trackers-description"
                                class="content-blocking-category-description"/>
                   <hbox id="warningAllCookiesBlocked">
                     <image class="reject-trackers-warning-icon"/>
-                    <description data-l10n-id="content-blocking-reject-trackers-warning-all-cookies-blocked"
-                                 class="content-blocking-category-description"/>
+                    <description data-l10n-id="content-blocking-reject-trackers-warning-your-settings-prevent-changes"
+                                 class="content-blocking-category-description description-with-side-element"/>
                   </hbox>
                   <hbox id="warningFromVisitedCookiesBlocked">
                     <image class="reject-trackers-warning-icon"/>
-                    <description data-l10n-id="content-blocking-reject-trackers-warning-from-unvisited-cookies-blocked"
-                                 class="content-blocking-category-description"/>
+                    <description data-l10n-id="content-blocking-reject-trackers-warning-your-settings-prevent-changes"
+                                 class="content-blocking-category-description description-with-side-element"/>
                   </hbox>
                 </deck>
               </vbox>
               <hbox align="center">
                 <vbox align="center">
                   <button id="contentBlockingChangeCookieSettings"
                           class="accessory-button"
                           flex="1"
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -529,16 +529,17 @@ add_task(async function testExtensionCon
     new: "contentBlockingTrackingProtectionExtensionContentButton",
   };
   const DISABLE_BUTTON_ID = {
     old: "disableTrackingProtectionExtension",
     new: "contentBlockingDisableTrackingProtectionExtension",
   };
 
   let tpEnabledPref = () => Services.prefs.getBoolPref(TP_PREF);
+  let cbUIEnabledPref = () => Services.prefs.getBoolPref(CB_UI_PREF);
 
   await SpecialPowers.pushPrefEnv(
     {"set": [[TP_PREF, TP_DEFAULT], [CB_UI_PREF, true]]});
 
   function background() {
     browser.privacy.websites.trackingProtectionMode.set({value: "always"});
   }
 
@@ -548,17 +549,18 @@ add_task(async function testExtensionCon
     let controlledLabel = doc.getElementById(CONTROLLED_LABEL_ID[uiType]);
     let controlledButton = doc.getElementById(CONTROLLED_BUTTON_ID[uiType]);
 
     is(controlledLabel.hidden, !isControlled, "The extension controlled row's visibility is as expected.");
     is(controlledButton.hidden, !isControlled, "The disable extension button's visibility is as expected.");
     if (isControlled) {
       let controlledDesc = controlledLabel.querySelector("description");
       Assert.deepEqual(doc.l10n.getAttributes(controlledDesc), {
-        id: "extension-controlled-websites-tracking-protection-mode",
+        id: cbUIEnabledPref() ? "extension-controlled-websites-content-blocking-all-trackers" :
+                                "extension-controlled-websites-tracking-protection-mode",
         args: {
           name: "set_tp",
         },
       }, "The user is notified that an extension is controlling TP.");
     }
 
     if (uiType === "old") {
       for (let element of doc.querySelectorAll("#trackingProtectionRadioGroup > radio")) {
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -103,16 +103,20 @@ extension-controlled-default-search = An
 # This string is shown to notify the user that Container Tabs
 # are being enabled by an extension.
 extension-controlled-privacy-containers = An extension, <img data-l10n-name="icon"/> { $name }, requires Container Tabs.
 
 # This string is shown to notify the user that their tracking protection preferences
 # are being controlled by an extension.
 extension-controlled-websites-tracking-protection-mode = An extension, <img data-l10n-name="icon"/> { $name }, is controlling tracking protection.
 
+# This string is shown to notify the user that their content blocking "All Detected Trackers"
+# preferences are being controlled by an extension.
+extension-controlled-websites-content-blocking-all-trackers = An extension, <img data-l10n-name="icon"/> { $name }, is controlling this setting.
+
 # This string is shown to notify the user that their proxy configuration preferences
 # are being controlled by an extension.
 extension-controlled-proxy-config = An extension, <img data-l10n-name="icon"/> { $name }, is controlling how { -brand-short-name } connects to the internet.
 
 # This string is shown after the user disables an extension to notify the user
 # how to enable an extension that they disabled.
 #
 # <img data-l10n-name="addons-icon"/> will be replaced with Add-ons icon
@@ -806,17 +810,17 @@ addressbar-locbar-openpage-option =
 addressbar-suggestions-settings = Change preferences for search engine suggestions
 
 ## Privacy Section - Content Blocking
 
 content-blocking-header = Content Blocking
 
 content-blocking-desc = Block third-party content, like ads or code, that can slow your browsing and track you around the web. Customize your settings for the best balance of protection and performance.
 
-content-blocking-learn-more = Learn More
+content-blocking-learn-more = Learn more
 content-blocking-restore-defaults =
   .label = Restore Defaults
   .accesskey = R
 
 content-blocking-toggle-on =
   .tooltiptext = Turn Off Content Blocking
 content-blocking-toggle-off =
   .tooltiptext = Turn On Content Blocking
@@ -828,39 +832,36 @@ content-blocking-toggle-label-off = OFF
 
 content-blocking-category-label = Choose what to block
 
 # "Slow" in this instance means "slow to load on the network".
 # FastBlock is a feature that blocks requests to tracking sites if they
 # have not finished loading after a certain threshold of seconds.
 content-blocking-fastblock-slow-loading-label = Slow-Loading Trackers
   .accesskey = S
-content-blocking-fastblock-description = Blocks third-party content that takes longer than 5 seconds to load.
+content-blocking-fastblock-new-description = Block just the trackers that keep pages from loading quickly.
 content-blocking-tracking-protection-all-label = All Detected Trackers
   .accesskey = T
-content-blocking-tracking-protection-description = Blocks all known trackers (Note: may also prevent some pages from loading).
+content-blocking-tracking-protection-new-description = Block all known trackers. (May prevent some pages from loading.)
 content-blocking-tracking-protection-option-always =
   .label = Always
   .accesskey = A
 content-blocking-tracking-protection-option-private =
   .label = Only in private windows
   .accesskey = p
-content-blocking-tracking-protection-change-blocklist = Change Block List…
+content-blocking-tracking-protection-change-block-list = Change block list
 
 content-blocking-reject-trackers-label = Third-Party Cookies
   .accesskey = C
 content-blocking-reject-trackers-description = Block all third-party cookies or just those set by trackers.
 # This is a warning message shown next to a yellow warning icon when the Third-Party Cookies subsection
-# of the Content Blocking UI in Preferences has been disabled due to the "All cookies" option
-# being selected in the Cookies and Site Data section of the UI.
-content-blocking-reject-trackers-warning-all-cookies-blocked = All cookies are currently blocked.
-# This is a warning message shown next to a yellow warning icon when the Third-Party Cookies subsection
-# of the Content Blocking UI in Preferences has been disabled due to the "Cookies from unvisited websites"
-# option being selected in the Cookies and Site Data section of the UI.
-content-blocking-reject-trackers-warning-from-unvisited-cookies-blocked = Cookies from unvisited websites are currently blocked.
+# of the Content Blocking UI in Preferences has been disabled due to the either the "All cookies" option
+# or the "Cookies from unvisited websites" option being selected in the Cookies and Site Data section of
+# the UI.
+content-blocking-reject-trackers-warning-your-settings-prevent-changes = Your settings in Cookies and Site Data are preventing changes to Third-Party Cookies settings.
 content-blocking-change-cookie-settings =
   .label = Change Cookie Settings
   .accesskey = S
 content-blocking-reject-trackers-block-trackers-option-recommended =
   .label = Trackers (recommended)
   .accesskey = k
 content-blocking-reject-trackers-block-trackers-option =
   .label = Trackers
--- a/browser/modules/ThemeVariableMap.jsm
+++ b/browser/modules/ThemeVariableMap.jsm
@@ -74,16 +74,34 @@ const ThemeVariableMap = [
     lwtProperty: "popup_border",
   }],
   ["--autocomplete-popup-highlight-background", {
     lwtProperty: "popup_highlight",
   }],
   ["--autocomplete-popup-highlight-color", {
     lwtProperty: "popup_highlight_text",
   }],
+  ["--sidebar-background-color", {
+    lwtProperty: "sidebar",
+    optionalElementID: "sidebar-box",
+    processColor(rgbaChannels, element) {
+      if (!rgbaChannels) {
+        element.removeAttribute("lwt-sidebar");
+        return null;
+      }
+      const {r, g, b} = rgbaChannels;
+      element.setAttribute("lwt-sidebar", "true");
+      // Drop alpha channel
+      return `rgb(${r}, ${g}, ${b})`;
+    },
+  }],
+  ["--sidebar-text-color", {
+    lwtProperty: "sidebar_text",
+    optionalElementID: "sidebar-box",
+  }],
 ];
 
 const ThemeContentPropertyList = [
   "ntp_background",
   "ntp_text",
   "sidebar",
   "sidebar_highlight",
   "sidebar_highlight_text",
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -441,23 +441,18 @@ notification[value="translation"] menuli
 /* Bookmarking panel */
 
 %include ../shared/places/editBookmarkPanel.inc.css
 
 /* Content area */
 
 %include ../shared/sidebar.inc.css
 
-#sidebar-box {
-  background-color: -moz-Field;
-  color: -moz-FieldText;
-}
-
-#sidebar-header {
-  border-bottom: 1px solid ThreeDShadow;
+#browser {
+  --sidebar-border-color: ThreeDShadow;
 }
 
 .sidebar-splitter {
   -moz-appearance: none;
   width: 6px;
   background-color: -moz-dialog;
   border: 1px ThreeDShadow;
   border-style: none solid;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -587,30 +587,28 @@ html|input.urlbar-input {
   opacity: 1.0;
   color: #bbb;
 }
 
 /* ----- SIDEBAR ELEMENTS ----- */
 
 %include ../shared/sidebar.inc.css
 
+#browser {
+  --sidebar-border-color: hsla(240, 5%, 5%, .1);
+}
+
 #sidebar-box {
-  -moz-appearance: -moz-mac-source-list;
-  -moz-font-smoothing-background-color: -moz-mac-source-list;
   /* Default font size is 11px on mac, so this is 12px */
   font-size: 1.0909rem;
 }
 
-#sidebar-header {
-  border-bottom: 1px solid hsla(240, 5%, 5%, .1);
-  background-color: transparent;
-}
-
-.sidebar-splitter {
-  border-color: hsla(240, 5%, 5%, .1);
+#sidebar-box:not([lwt-sidebar]) {
+  -moz-appearance: -moz-mac-source-list;
+  -moz-font-smoothing-background-color: -moz-mac-source-list;
 }
 
 /* ----- CONTENT ----- */
 
 .browserContainer > findbar {
   background: @scopeBarBackground@;
   border-top: @scopeBarSeparatorBorder@;
   color: -moz-DialogText;
--- a/browser/themes/shared/sidebar.inc.css
+++ b/browser/themes/shared/sidebar.inc.css
@@ -1,27 +1,37 @@
 %if 0
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 
-.sidebar-header,
+#sidebar-box {
+  --sidebar-background-color: -moz-Field;
+  --sidebar-text-color: -moz-FieldText;
+  background-color: var(--sidebar-background-color);
+  color: var(--sidebar-text-color);
+}
+
 #sidebar-header {
   font-size: 1.333em;
   padding: 8px;
+  border-bottom: 1px solid var(--sidebar-border-color);
+  background-color: transparent;
+  color: inherit;
 }
 
 %ifndef MOZ_WIDGET_GTK
 % We don't let the splitter overlap the sidebar on Linux since the sidebar's
 % scrollbar is too narrow on Linux.
 .sidebar-splitter {
   -moz-appearance: none;
   border: 0 solid;
   border-inline-end-width: 1px;
+  border-inline-end-color: var(--sidebar-border-color);
   min-width: 1px;
   width: 4px;
   background-image: none !important;
   background-color: transparent;
   margin-inline-start: -4px;
   position: relative;
 }
 
@@ -33,17 +43,16 @@
 }
 %endif
 
 #sidebar-throbber[loading="true"] {
   list-style-image: url("chrome://global/skin/icons/loading.png");
 }
 
 @media (min-resolution: 2dppx) {
-  .sidebar-throbber[loading="true"],
   #sidebar-throbber[loading="true"] {
     list-style-image: url("chrome://global/skin/icons/loading@2x.png");
     width: 16px;
   }
 }
 
 #sidebar-title {
   margin: 0;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -653,27 +653,18 @@ html|*.urlbar-input:-moz-lwtheme::placeh
 /* bookmarking panel */
 
 %include ../shared/places/editBookmarkPanel.inc.css
 
 /* ::::: content area ::::: */
 
 %include ../shared/sidebar.inc.css
 
-#sidebar-box {
-  background-color: -moz-Field;
-  color: -moz-FieldText;
-}
-
-#sidebar-header {
-  border-bottom: 1px solid ThreeDLightShadow;
-}
-
-.sidebar-splitter {
-  border-color: ThreeDLightShadow;
+#browser {
+  --sidebar-border-color: ThreeDLightShadow;
 }
 
 .browserContainer > findbar {
   background-color: -moz-dialog;
   color: -moz-DialogText;
   text-shadow: none;
 }
 
--- a/devtools/server/actors/replay/replay.js
+++ b/devtools/server/actors/replay/replay.js
@@ -136,17 +136,21 @@ function addScript(script) {
 }
 
 // Association between Debugger.ScriptSources and their IDs. As for gScripts,
 // the indices assigned to a script source are consistent across all replays
 // and rewinding.
 const gScriptSources = new IdMap();
 
 function addScriptSource(source) {
-  gScriptSources.add(source);
+  // Tolerate redundant attempts to add the same source, as we might see
+  // onNewScript calls for different scripts with the same source.
+  if (!gScriptSources.getId(source)) {
+    gScriptSources.add(source);
+  }
 }
 
 function considerScript(script) {
   return script.url
       && !script.url.startsWith("resource:")
       && !script.url.startsWith("chrome:");
 }
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5460,16 +5460,23 @@ IonBuilder::jsop_call(uint32_t argc, boo
 }
 
 AbortReasonOr<bool>
 IonBuilder::testShouldDOMCall(TypeSet* inTypes, JSFunction* func, JSJitInfo::OpType opType)
 {
     if (!func->isNative() || !func->hasJitInfo())
         return false;
 
+    // Some DOM optimizations cause execution to skip over recorded events such
+    // as wrapper cache accesses, e.g. through GVN or loop hoisting of the
+    // expression which performs the event. Disable DOM optimizations when
+    // recording or replaying to avoid this problem.
+    if (mozilla::recordreplay::IsRecordingOrReplaying())
+        return false;
+
     // If all the DOM objects flowing through are legal with this
     // property, we can bake in a call to the bottom half of the DOM
     // accessor
     DOMInstanceClassHasProtoAtDepth instanceChecker =
         realm->runtime()->DOMcallbacks()->instanceClassMatchesProto;
 
     const JSJitInfo* jinfo = func->jitInfo();
     if (jinfo->type() != opType)
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -473,17 +473,19 @@ struct JSStructuredCloneWriter {
   public:
     explicit JSStructuredCloneWriter(JSContext* cx,
                                      JS::StructuredCloneScope scope,
                                      JS::CloneDataPolicy cloneDataPolicy,
                                      const JSStructuredCloneCallbacks* cb,
                                      void* cbClosure,
                                      const Value& tVal)
         : out(cx, scope), objs(out.context()),
-          counts(out.context()), entries(out.context()),
+          counts(out.context()),
+          objectEntries(out.context()),
+          otherEntries(out.context()),
           memory(out.context()),
           transferable(out.context(), tVal),
           transferableObjects(out.context(), TransferableObjectsSet(cx)),
           cloneDataPolicy(cloneDataPolicy)
     {
         out.setCallbacks(cb, cbClosure, OwnTransferablePolicy::NoTransferables);
     }
 
@@ -542,20 +544,22 @@ struct JSStructuredCloneWriter {
     // entered before any manipulation is performed.
     AutoValueVector objs;
 
     // counts[i] is the number of entries of objs[i] remaining to be written.
     // counts.length() == objs.length() and sum(counts) == entries.length().
     Vector<size_t> counts;
 
     // For JSObject: Property IDs as value
+    AutoIdVector objectEntries;
+
     // For Map: Key followed by value
     // For Set: Key
     // For SavedFrame: parent SavedFrame
-    AutoValueVector entries;
+    AutoValueVector otherEntries;
 
     // The "memory" list described in the HTML5 internal structured cloning
     // algorithm.  memory is a superset of objs; items are never removed from
     // Memory until a serialization operation is finished
     using CloneMemory = GCHashMap<JSObject*,
                                   uint32_t,
                                   MovableCellHasher<JSObject*>,
                                   SystemAllocPolicy>;
@@ -1213,19 +1217,19 @@ JSStructuredCloneWriter::checkStack()
     size_t limit = Min(counts.length(), MAX);
     MOZ_ASSERT(objs.length() == counts.length());
     size_t total = 0;
     for (size_t i = 0; i < limit; i++) {
         MOZ_ASSERT(total + counts[i] >= total);
         total += counts[i];
     }
     if (counts.length() <= MAX)
-        MOZ_ASSERT(total == entries.length());
+        MOZ_ASSERT(total == objectEntries.length() + otherEntries.length());
     else
-        MOZ_ASSERT(total <= entries.length());
+        MOZ_ASSERT(total <= objectEntries.length() + otherEntries.length());
 
     size_t j = objs.length();
     for (size_t i = 0; i < limit; i++) {
         --j;
         MOZ_ASSERT(memory.has(&objs[j].toObject()));
     }
 #endif
 }
@@ -1365,17 +1369,17 @@ JSStructuredCloneWriter::startObject(Han
                                   "object graph to serialize");
         return false;
     }
 
     return true;
 }
 
 static bool
-TryAppendNativeProperties(JSContext* cx, HandleObject obj, AutoValueVector& entries, size_t* properties,
+TryAppendNativeProperties(JSContext* cx, HandleObject obj, AutoIdVector& entries, size_t* properties,
                           bool* optimized)
 {
     *optimized = false;
 
     if (!obj->isNative())
         return true;
 
     HandleNativeObject nobj = obj.as<NativeObject>();
@@ -1396,60 +1400,58 @@ TryAppendNativeProperties(JSContext* cx,
     for (Shape::Range<NoGC> r(shape); !r.empty(); r.popFront()) {
         jsid id = r.front().propidRaw();
 
         // Ignore symbols and non-enumerable properties.
         if (!r.front().enumerable() || JSID_IS_SYMBOL(id))
             continue;
 
         MOZ_ASSERT(JSID_IS_STRING(id));
-        if (!entries.append(StringValue(JSID_TO_STRING(id))))
+        if (!entries.append(id))
             return false;
 
         count++;
     }
 
     // Add dense element ids in reverse order.
     for (uint32_t i = nobj->getDenseInitializedLength(); i > 0; --i) {
         if (nobj->getDenseElement(i - 1).isMagic(JS_ELEMENTS_HOLE))
             continue;
 
-        if (!entries.append(Int32Value(i - 1)))
+        if (!entries.append(INT_TO_JSID(i - 1)))
             return false;
 
         count++;
     }
 
     *properties = count;
     return true;
 }
 
 bool
 JSStructuredCloneWriter::traverseObject(HandleObject obj, ESClass cls)
 {
     size_t count;
     bool optimized = false;
-    if (!TryAppendNativeProperties(context(), obj, entries, &count, &optimized))
+    if (!TryAppendNativeProperties(context(), obj, objectEntries, &count, &optimized))
         return false;
 
     if (!optimized) {
         // Get enumerable property ids and put them in reverse order so that they
         // will come off the stack in forward order.
         AutoIdVector properties(context());
         if (!GetPropertyKeys(context(), obj, JSITER_OWNONLY, &properties))
             return false;
 
         for (size_t i = properties.length(); i > 0; --i) {
-            MOZ_ASSERT(JSID_IS_STRING(properties[i - 1]) || JSID_IS_INT(properties[i - 1]));
-
-            // JSStructuredCloneWriter::write relies on this.
-            RootedValue val(context(), IdToValue(properties[i - 1]));
-            if (!entries.append(val))
+            jsid id = properties[i - 1];
+
+            MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
+            if (!objectEntries.append(id))
                 return false;
-
         }
 
         count = properties.length();
     }
 
     // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(count))
         return false;
@@ -1486,17 +1488,17 @@ JSStructuredCloneWriter::traverseMap(Han
         JSAutoRealm ar(context(), unwrapped);
         if (!MapObject::getKeysAndValuesInterleaved(unwrapped, &newEntries))
             return false;
     }
     if (!context()->compartment()->wrap(context(), &newEntries))
         return false;
 
     for (size_t i = newEntries.length(); i > 0; --i) {
-        if (!entries.append(newEntries[i - 1]))
+        if (!otherEntries.append(newEntries[i - 1]))
             return false;
     }
 
     // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(newEntries.length()))
         return false;
 
     checkStack();
@@ -1516,17 +1518,17 @@ JSStructuredCloneWriter::traverseSet(Han
         JSAutoRealm ar(context(), unwrapped);
         if (!SetObject::keys(context(), unwrapped, &keys))
             return false;
     }
     if (!context()->compartment()->wrap(context(), &keys))
         return false;
 
     for (size_t i = keys.length(); i > 0; --i) {
-        if (!entries.append(keys[i - 1]))
+        if (!otherEntries.append(keys[i - 1]))
             return false;
     }
 
     // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(keys.length()))
         return false;
 
     checkStack();
@@ -1562,17 +1564,17 @@ JSStructuredCloneWriter::traverseSavedFr
 
     RootedSavedFrame savedFrame(context(), &unwrapped->as<SavedFrame>());
 
     RootedObject parent(context(), savedFrame->getParent());
     if (!context()->compartment()->wrap(context(), &parent))
         return false;
 
     if (!objs.append(ObjectValue(*obj)) ||
-        !entries.append(parent ? ObjectValue(*parent) : NullValue()) ||
+        !otherEntries.append(parent ? ObjectValue(*parent) : NullValue()) ||
         !counts.append(1))
     {
         return false;
     }
 
     checkStack();
 
     // Write the SavedFrame tag and the SavedFrame's principals.
@@ -1941,42 +1943,41 @@ JSStructuredCloneWriter::write(HandleVal
     RootedValue val(context());
     RootedId id(context());
 
     while (!counts.empty()) {
         obj = &objs.back().toObject();
         context()->check(obj);
         if (counts.back()) {
             counts.back()--;
-            key = entries.back();
-            entries.popBack();
-            checkStack();
 
             ESClass cls;
             if (!GetBuiltinClass(context(), obj, &cls))
                 return false;
 
             if (cls == ESClass::Map) {
+                key = otherEntries.popCopy();
+                checkStack();
+
                 counts.back()--;
-                val = entries.back();
-                entries.popBack();
+                val = otherEntries.popCopy();
                 checkStack();
 
                 if (!startWrite(key) || !startWrite(val))
                     return false;
             } else if (cls == ESClass::Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
+                key = otherEntries.popCopy();
+                checkStack();
+
                 if (!startWrite(key))
                     return false;
             } else {
-                // This relies on the way JSStructuredCloneWriter::traverseObject
-                // converts JSIDs to Value.
-                if (key.isString())
-                    id = AtomToId(&key.toString()->asAtom());
-                else
-                    id = INT_TO_JSID(key.toInt32());
+                id = objectEntries.popCopy();
+                key = IdToValue(id);
+                checkStack();
 
                 // If obj still has an own property named id, write it out.
                 bool found;
                 if (GetOwnPropertyPure(context(), obj, id, val.address(), &found)) {
                     if (found) {
                         if (!startWrite(key) || !startWrite(val))
                             return false;
                     }
--- a/testing/webdriver/src/command.rs
+++ b/testing/webdriver/src/command.rs
@@ -89,18 +89,18 @@ pub struct WebDriverMessage<U: WebDriver
 }
 
 impl<U: WebDriverExtensionRoute> WebDriverMessage<U> {
     pub fn new(
         session_id: Option<String>,
         command: WebDriverCommand<U::Command>,
     ) -> WebDriverMessage<U> {
         WebDriverMessage {
-            session_id: session_id,
-            command: command,
+            session_id,
+            command,
         }
     }
 
     pub fn from_http(
         match_type: Route<U>,
         params: &Captures,
         raw_body: &str,
         requires_body: bool,
--- a/testing/webdriver/src/common.rs
+++ b/testing/webdriver/src/common.rs
@@ -58,17 +58,17 @@ pub enum LocatorStrategy {
 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub struct WebElement {
     #[serde(rename = "element-6066-11e4-a52e-4f735466cecf")]
     pub id: String,
 }
 
 impl WebElement {
     pub fn new(id: String) -> WebElement {
-        WebElement { id: id }
+        WebElement { id }
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use serde_json;
     use test::{check_serialize, check_serialize_deserialize};
--- a/testing/webdriver/src/error.rs
+++ b/testing/webdriver/src/error.rs
@@ -287,29 +287,29 @@ impl Serialize for WebDriverError {
 }
 
 impl WebDriverError {
     pub fn new<S>(error: ErrorStatus, message: S) -> WebDriverError
     where
         S: Into<Cow<'static, str>>,
     {
         WebDriverError {
-            error: error,
+            error,
             message: message.into(),
             stack: "".into(),
             delete_session: false,
         }
     }
 
     pub fn new_with_stack<S>(error: ErrorStatus, message: S, stack: S) -> WebDriverError
     where
         S: Into<Cow<'static, str>>,
     {
         WebDriverError {
-            error: error,
+            error,
             message: message.into(),
             stack: stack.into(),
             delete_session: false,
         }
     }
 
     pub fn error_code(&self) -> &'static str {
         self.error.error_code()
--- a/testing/webdriver/src/httpapi.rs
+++ b/testing/webdriver/src/httpapi.rs
@@ -312,19 +312,19 @@ struct RequestMatcher<U: WebDriverExtens
     path_regexp: Regex,
     match_type: Route<U>,
 }
 
 impl<U: WebDriverExtensionRoute> RequestMatcher<U> {
     pub fn new(method: Method, path: &str, match_type: Route<U>) -> RequestMatcher<U> {
         let path_regexp = RequestMatcher::<U>::compile_path(path);
         RequestMatcher {
-            method: method,
-            path_regexp: path_regexp,
-            match_type: match_type,
+            method,
+            path_regexp,
+            match_type,
         }
     }
 
     pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
         let captures = self.path_regexp.captures(path);
         (method == self.method, captures)
     }
 
--- a/testing/webdriver/src/server.rs
+++ b/testing/webdriver/src/server.rs
@@ -29,17 +29,17 @@ enum DispatchMessage<U: WebDriverExtensi
 
 #[derive(Clone, Debug, PartialEq)]
 pub struct Session {
     pub id: String,
 }
 
 impl Session {
     fn new(id: String) -> Session {
-        Session { id: id }
+        Session { id }
     }
 }
 
 pub trait WebDriverHandler<U: WebDriverExtensionRoute = VoidWebDriverExtensionRoute>: Send {
     fn handle_command(
         &mut self,
         session: &Option<Session>,
         msg: WebDriverMessage<U>,
@@ -52,17 +52,17 @@ struct Dispatcher<T: WebDriverHandler<U>
     handler: T,
     session: Option<Session>,
     extension_type: PhantomData<U>,
 }
 
 impl<T: WebDriverHandler<U>, U: WebDriverExtensionRoute> Dispatcher<T, U> {
     fn new(handler: T) -> Dispatcher<T, U> {
         Dispatcher {
-            handler: handler,
+            handler,
             session: None,
             extension_type: PhantomData,
         }
     }
 
     fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
         loop {
             match msg_chan.recv() {
@@ -152,21 +152,24 @@ impl<T: WebDriverHandler<U>, U: WebDrive
 }
 
 #[derive(Debug, Clone)]
 struct HttpHandler<U: WebDriverExtensionRoute> {
     chan: Arc<Mutex<Sender<DispatchMessage<U>>>>,
     api: Arc<Mutex<WebDriverHttpApi<U>>>,
 }
 
-impl <U: WebDriverExtensionRoute> HttpHandler<U> {
-    fn new(api: Arc<Mutex<WebDriverHttpApi<U>>>, chan: Sender<DispatchMessage<U>>) -> HttpHandler<U> {
+impl<U: WebDriverExtensionRoute> HttpHandler<U> {
+    fn new(
+        api: Arc<Mutex<WebDriverHttpApi<U>>>,
+        chan: Sender<DispatchMessage<U>>,
+    ) -> HttpHandler<U> {
         HttpHandler {
             chan: Arc::new(Mutex::new(chan)),
-            api: api,
+            api,
         }
     }
 }
 
 impl<U: WebDriverExtensionRoute + 'static> Service for HttpHandler<U> {
     type ReqBody = Body;
     type ResBody = Body;
 
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_sidebars.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_sidebars.js
@@ -9,19 +9,22 @@
  */
 async function test_sidebar_theme(theme, isBrightText) {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       theme,
     },
   });
 
+  const sidebarBox = document.getElementById("sidebar-box");
   const content = SidebarUI.browser.contentWindow;
   const root = content.document.documentElement;
 
+  ok(!sidebarBox.hasAttribute("lwt-sidebar"),
+     "Sidebar box should not have lwt-sidebar attribute");
   ok(!root.hasAttribute("lwt-sidebar"),
      "Sidebar should not have lwt-sidebar attribute");
   ok(!root.hasAttribute("lwt-sidebar-brighttext"),
      "Sidebar should not have lwt-sidebar-brighttext attribute");
   ok(!root.hasAttribute("lwt-sidebar-highlight"),
      "Sidebar should not have lwt-sidebar-highlight attribute");
 
   const rootCS = content.getComputedStyle(root);
@@ -56,35 +59,45 @@ async function test_sidebar_theme(theme,
 
   const actualBackground = hexToCSS(theme.colors.sidebar) || originalBackground;
   const actualColor = hexToCSS(theme.colors.sidebar_text) || originalColor;
   const actualHighlightBackground = hexToCSS(theme.colors.sidebar_highlight) || originalHighlightBackground;
   const actualHighlightColor = hexToCSS(theme.colors.sidebar_highlight_text) || originalHighlightColor;
   const isCustomHighlight = !!theme.colors.sidebar_highlight_text;
   const isCustomSidebar = !!theme.colors.sidebar_text;
 
+  is(sidebarBox.hasAttribute("lwt-sidebar"), isCustomSidebar,
+     `Sidebar box should${!isCustomSidebar ? " not" : ""} have lwt-sidebar attribute`);
   is(root.hasAttribute("lwt-sidebar"), isCustomSidebar,
      `Sidebar should${!isCustomSidebar ? " not" : ""} have lwt-sidebar attribute`);
   is(root.hasAttribute("lwt-sidebar-brighttext"), isBrightText,
      `Sidebar should${!isBrightText ? " not" : ""} have lwt-sidebar-brighttext attribute`);
   is(root.hasAttribute("lwt-sidebar-highlight"), isCustomHighlight,
      `Sidebar should${!isCustomHighlight ? " not" : ""} have lwt-sidebar-highlight attribute`);
 
+  if (isCustomSidebar) {
+    const sidebarBoxCS = window.getComputedStyle(sidebarBox);
+    is(sidebarBoxCS.backgroundColor, actualBackground, "Sidebar box background should be set.");
+    is(sidebarBoxCS.color, actualColor, "Sidebar box text color should be set.");
+  }
+
   is(rootCS.backgroundColor, actualBackground, "Sidebar background should be set.");
   is(rootCS.color, actualColor, "Sidebar text color should be set.");
 
   is(highlightCS.backgroundColor, actualHighlightBackground,
      "Sidebar highlight background color should be set.");
   is(highlightCS.color, actualHighlightColor,
      "Sidebar highlight text color should be set.");
 
   await extension.unload();
 
   Services.ppmm.sharedData.flush();
 
+  ok(!sidebarBox.hasAttribute("lwt-sidebar"),
+     "Sidebar box should not have lwt-sidebar attribute");
   ok(!root.hasAttribute("lwt-sidebar"),
      "Sidebar should not have lwt-sidebar attribute");
   ok(!root.hasAttribute("lwt-sidebar-brighttext"),
      "Sidebar should not have lwt-sidebar-brighttext attribute");
   ok(!root.hasAttribute("lwt-sidebar-highlight"),
      "Sidebar should not have lwt-sidebar-highlight attribute");
 
   is(rootCS.backgroundColor, originalBackground,
--- a/toolkit/recordreplay/ipc/ChildProcess.cpp
+++ b/toolkit/recordreplay/ipc/ChildProcess.cpp
@@ -631,17 +631,17 @@ ChildProcessInfo::MaybeProcessPendingMes
     }
   }
 
   return false;
 }
 
 // How many seconds to wait without hearing from an unpaused child before
 // considering that child to be hung.
-static const size_t HangSeconds = 5;
+static const size_t HangSeconds = 30;
 
 void
 ChildProcessInfo::WaitUntil(const std::function<bool()>& aCallback)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   bool sentTerminateMessage = false;
   while (!aCallback()) {