Merge m-c to oak
authorRobert Strong <robert.bugzilla@gmail.com>
Wed, 26 Jul 2017 12:02:40 -0700
changeset 1476412 5f8b9ae0f5e2326c6337d4fb1e9592ac281d1bb1
parent 1476411 bbecb575c15f4f99b63362f5016e180ef437ffa7 (current diff)
parent 1197386 388d81ed93fa640f91d155f36254667c734157cf (diff)
child 1476413 0dd5304b11eabd19cd76f63ddb344c8d76d48730
push id263306
push usercatlee@mozilla.com
push dateFri, 06 Apr 2018 15:43:50 +0000
treeherdertry@a0bfb6549eeb [default view] [failures only]
milestone56.0a1
Merge m-c to oak
.cron.yml
browser/components/customizableui/content/panelUI.inc.xul
browser/config/mozconfigs/linux32/debug
browser/config/mozconfigs/linux32/devedition
browser/config/mozconfigs/linux32/nightly
browser/config/mozconfigs/linux64/debug
browser/config/mozconfigs/linux64/devedition
browser/config/mozconfigs/linux64/nightly
browser/config/mozconfigs/macosx64/beta
browser/config/mozconfigs/macosx64/debug
browser/config/mozconfigs/macosx64/devedition
browser/config/mozconfigs/macosx64/nightly
browser/config/mozconfigs/macosx64/release
browser/config/mozconfigs/whitelist
browser/config/mozconfigs/win32/debug
browser/config/mozconfigs/win32/devedition
browser/config/mozconfigs/win32/nightly
browser/config/mozconfigs/win64/debug
browser/config/mozconfigs/win64/devedition
browser/config/mozconfigs/win64/nightly
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/shared/customizableui/panelUI.inc.css
ipc/glue/GeckoChildProcessHost.cpp
js/src/jit-test/tests/ion/bailoutStaticObject.js
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoViewFragment.java
old-configure.in
taskcluster/ci/build/windows.yml
taskcluster/ci/test/test-platforms.yml
taskcluster/ci/test/test-sets.yml
taskcluster/ci/test/tests.yml
taskcluster/taskgraph/transforms/gecko_v2_whitelist.py
taskcluster/taskgraph/transforms/job/mozharness_test.py
taskcluster/taskgraph/transforms/signing.py
taskcluster/taskgraph/transforms/tests.py
testing/mozharness/mozharness/mozilla/building/buildbase.py
testing/mozharness/scripts/desktop_l10n.py
testing/talos/talos/config.py
toolkit/components/telemetry/Histograms.json
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/mozapps/installer/upload-files.mk
--- a/.cron.yml
+++ b/.cron.yml
@@ -38,18 +38,24 @@ jobs:
             # No default
 
     - name: nightly-desktop-win
       job:
           type: decision-task
           treeherder-symbol: Nd-Win
           target-tasks-method: nightly_win
       run-on-projects:
+          - mozilla-central
           - date
-      when: [] # never (hook only)
+      when:
+          by-project:
+            # Match buildbot starts for now
+            date: [{hour: 15, minute: 0}]
+            mozilla-central: [{hour: 10, minute: 0}]
+            # No default
 
     - name: nightly-android
       job:
           type: decision-task
           treeherder-symbol: Na
           target-tasks-method: nightly_fennec
       run-on-projects:
           - mozilla-central
--- a/Makefile.in
+++ b/Makefile.in
@@ -243,20 +243,22 @@ default all::
 include $(topsrcdir)/config/rules.mk
 
 ifdef SCCACHE_VERBOSE_STATS
 default::
 	-$(CCACHE) --show-stats --stats-format=json > sccache-stats.json
 	@echo "===SCCACHE STATS==="
 	-$(CCACHE) --show-stats
 	@echo "==================="
+ifndef MOZ_PROFILE_GENERATE
 # Ideally we'd do that in the same file as we set the sccache.log location for
 # sccache, but it's too late in the build.
 	-gzip -9 $(DIST)/sccache.log
 endif
+endif
 
 distclean::
 	$(RM) $(DIST_GARBAGE)
 
 ifdef MOZ_CRASHREPORTER
 include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
 endif
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -2102,21 +2102,41 @@ DocAccessible::DoARIAOwnsRelocation(Acce
     }
 
 #ifdef A11Y_LOG
   logging::TreeInfo("aria owns traversal", logging::eVerbose,
                     "candidate", child, nullptr);
 #endif
 
     // Same child on same position, no change.
-    if (child->Parent() == aOwner &&
-        child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
-      MOZ_ASSERT(owned->ElementAt(idx) == child, "Not in sync!");
-      idx++;
-      continue;
+    if (child->Parent() == aOwner) {
+      int32_t indexInParent = child->IndexInParent();
+
+      // The child is being placed in its current index,
+      // eg. aria-owns='id1 id2 id3' is changed to aria-owns='id3 id2 id1'.
+      if (indexInParent == static_cast<int32_t>(insertIdx)) {
+        MOZ_ASSERT(child->IsRelocated(),
+                   "A child, having an index in parent from aria ownded indices range, has to be aria owned");
+        MOZ_ASSERT(owned->ElementAt(idx) == child,
+                   "Unexpected child in ARIA owned array");
+        idx++;
+        continue;
+      }
+
+      // The child is being inserted directly after its current index,
+      // resulting in a no-move case. This will happen when a parent aria-owns
+      // its last ordinal child:
+      // <ul aria-owns='id2'><li id='id1'></li><li id='id2'></li></ul>
+      if (indexInParent == static_cast<int32_t>(insertIdx) - 1) {
+        MOZ_ASSERT(!child->IsRelocated(), "Child should be in its ordinal position");
+        child->SetRelocated(true);
+        owned->InsertElementAt(idx, child);
+        idx++;
+        continue;
+      }
     }
 
     MOZ_ASSERT(owned->SafeElementAt(idx) != child, "Already in place!");
 
     if (owned->IndexOf(child) < idx) {
       continue; // ignore second entry of same ID
     }
 
@@ -2185,17 +2205,33 @@ DocAccessible::PutChildrenBack(nsTArray<
           MOZ_DIAGNOSTIC_ASSERT(origContainer == prevChild->Parent(), "Broken tree");
           origContainer = prevChild->Parent();
         }
         else {
           idxInParent = 0;
         }
       }
     }
-    MoveChild(child, origContainer, idxInParent);
+
+    // The child may have already be in its ordinal place for 2 reasons:
+    // 1. It was the last ordinal child, and the first aria-owned child.
+    //    given:      <ul id="list" aria-owns="b"><li id="a"></li><li id="b"></li></ul>
+    //    after load: $("list").setAttribute("aria-owns", "");
+    // 2. The preceding adopted children were just reclaimed, eg:
+    //    given:      <ul id="list"><li id="b"></li></ul>
+    //    after load: $("list").setAttribute("aria-owns", "a b");
+    //    later:      $("list").setAttribute("aria-owns", "");
+    if (origContainer != owner || child->IndexInParent() != idxInParent) {
+      MoveChild(child, origContainer, idxInParent);
+    } else {
+      MOZ_ASSERT(!child->PrevSibling() || !child->PrevSibling()->IsRelocated(),
+                 "No relocated child should appear before this one");
+      MOZ_ASSERT(!child->NextSibling() || child->NextSibling()->IsRelocated(),
+                 "No ordinal child should appear after this one");
+    }
   }
 
   aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
 }
 
 bool
 DocAccessible::MoveChild(Accessible* aChild, Accessible* aNewParent,
                          int32_t aIdxInParent)
--- a/accessible/moz.build
+++ b/accessible/moz.build
@@ -31,13 +31,14 @@ if CONFIG['MOZ_XUL']:
 TEST_DIRS += ['tests/mochitest']
 
 BROWSER_CHROME_MANIFESTS += [
   'tests/browser/bounds/browser.ini',
   'tests/browser/browser.ini',
   'tests/browser/e10s/browser.ini',
   'tests/browser/events/browser.ini',
   'tests/browser/scroll/browser.ini',
-  'tests/browser/states/browser.ini'
+  'tests/browser/states/browser.ini',
+  'tests/browser/tree/browser.ini'
 ]
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "Disability Access APIs")
--- a/accessible/tests/browser/events.js
+++ b/accessible/tests/browser/events.js
@@ -155,32 +155,34 @@ class UnexpectedEvents {
 }
 
 /**
  * A helper function that waits for a sequence of accessible events in
  * specified order.
  * @param {Array} events        a list of events to wait (same format as
  *                              waitForEvent arguments)
  */
-function waitForEvents(events, unexpected = [], ordered = false) {
+function waitForEvents(events, ordered = false) {
+  let expected = events.expected || events;
+  let unexpected = events.unexpected || [];
   // Next expected event index.
   let currentIdx = 0;
 
   let unexpectedListener = new UnexpectedEvents(unexpected);
 
-  return Promise.all(events.map((evt, idx) => {
+  return Promise.all(expected.map((evt, idx) => {
     let promise = evt instanceof Array ? waitForEvent(...evt) : evt;
     return promise.then(result => {
       if (ordered) {
         is(idx, currentIdx++,
           `Unexpected event order: ${result}`);
       }
       return result;
     });
   })).then(results => {
     unexpectedListener.stop();
     return results;
   });
 }
 
-function waitForOrderedEvents(events, unexpected = []) {
-  return waitForEvents(events, unexpected, true);
+function waitForOrderedEvents(events) {
+  return waitForEvents(events, true);
 }
--- a/accessible/tests/browser/shared-head.js
+++ b/accessible/tests/browser/shared-head.js
@@ -6,17 +6,17 @@
 
 /* import-globals-from ../mochitest/common.js */
 /* import-globals-from events.js */
 
 /* exported Logger, MOCHITESTS_DIR, invokeSetAttribute, invokeFocus,
             invokeSetStyle, getAccessibleDOMNodeID, getAccessibleTagName,
             addAccessibleTask, findAccessibleChildByID, isDefunct,
             CURRENT_CONTENT_DIR, loadScripts, loadFrameScripts, snippetToURL,
-            Cc, Cu */
+            Cc, Cu, arrayFromChildren */
 
 const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
 
 /**
  * Current browser test directory path used to load subscripts.
  */
 const CURRENT_DIR =
   'chrome://mochitests/content/browser/accessible/tests/browser/';
@@ -353,8 +353,13 @@ function queryInterfaces(accessible, int
       accessible.QueryInterface(iface);
     } catch (e) {
       ok(false, "Can't query " + iface);
     }
   }
 
   return accessible;
 }
+
+function arrayFromChildren(accessible) {
+  return Array.from({ length: accessible.childCount }, (c, i) =>
+    accessible.getChildAt(i));
+}
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/tree/browser.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+skip-if = e10s && os == 'win' && release_or_beta
+support-files =
+  head.js
+  !/accessible/tests/browser/events.js
+  !/accessible/tests/browser/shared-head.js
+  !/accessible/tests/mochitest/*.js
+
+[browser_test_aria_owns.js]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/tree/browser_test_aria_owns.js
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+function testChildrenIds(acc, expectedIds) {
+  let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
+  Assert.deepEqual(ids, expectedIds,
+    `Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
+}
+
+async function runTests(browser, accDoc) {
+  let one = findAccessibleChildByID(accDoc, "one");
+  let two = findAccessibleChildByID(accDoc, "two");
+  let three = findAccessibleChildByID(accDoc, "three");
+  let four = findAccessibleChildByID(accDoc, "four");
+
+  testChildrenIds(one, ["a"]);
+  testChildrenIds(two, ["b", "c", "d"]);
+  testChildrenIds(three, []);
+
+  let onReorders = waitForEvents({
+    expected: [
+      [EVENT_REORDER, "two"]], // children will be reordered via aria-owns
+    unexpected: [
+      [EVENT_REORDER, "one"],  // child will remain in place
+      [EVENT_REORDER, "three"], // none of its children will be reclaimed
+      [EVENT_REORDER, "four"]] // child will remain in place
+  });
+
+  await ContentTask.spawn(browser, null, async function() {
+    // aria-own ordinal child in place, should be a no-op.
+    document.getElementById("one").setAttribute("aria-owns", "a");
+    // remove aria-owned child that is already ordinal, should be no-op.
+    document.getElementById("four").removeAttribute("aria-owns");
+    // shuffle aria-owns with markup child.
+    document.getElementById("two").setAttribute("aria-owns", "d c");
+  });
+
+  await onReorders;
+
+  testChildrenIds(one, ["a"]);
+  testChildrenIds(two, ["b", "d", "c"]);
+  testChildrenIds(three, []);
+  testChildrenIds(four, ["e"]);
+
+  onReorders = waitForEvent(EVENT_REORDER, "one");
+
+  await ContentTask.spawn(browser, null, async function() {
+    let aa = document.createElement("li");
+    aa.id = "aa";
+    document.getElementById("one").appendChild(aa);
+  });
+
+  await onReorders;
+
+  testChildrenIds(one, ["aa", "a"]);
+
+  onReorders = waitForEvents([
+      [EVENT_REORDER, "two"],    // "b" will go to "three"
+      [EVENT_REORDER, "three"], // some children will be reclaimed and acquired
+      [EVENT_REORDER, "one"]]); // removing aria-owns will reorder native children
+
+  await ContentTask.spawn(browser, null, async function() {
+    // removing aria-owns should reorder the children
+    document.getElementById("one").removeAttribute("aria-owns");
+    // child order will be overridden by aria-owns
+    document.getElementById("three").setAttribute("aria-owns", "b d");
+  });
+
+  await onReorders;
+
+  testChildrenIds(one, ["a", "aa"]);
+  testChildrenIds(two, ["c"]);
+  testChildrenIds(three, ["b", "d"]);
+}
+
+/**
+ * Test caching of accessible object states
+ */
+addAccessibleTask(`
+    <ul id="one">
+      <li id="a">Test</li>
+    </ul>
+    <ul id="two" aria-owns="d">
+      <li id="b">Test 2</li>
+      <li id="c">Test 3</li>
+    </ul>
+    <ul id="three">
+      <li id="d">Test 4</li>
+    </ul>
+    <ul id="four" aria-owns="e">
+      <li id="e">Test 5</li>
+    </ul>
+    `, runTests);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/tree/head.js
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+// Load the shared-head file first.
+/* import-globals-from ../shared-head.js */
+Services.scriptloader.loadSubScript(
+  'chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js',
+  this);
+
+// Loading and common.js from accessible/tests/mochitest/ for all tests, as
+// well as events.js.
+loadScripts({ name: 'common.js', dir: MOCHITESTS_DIR }, 'events.js', 'layout.js');
--- a/accessible/tests/mochitest/elm/a11y.ini
+++ b/accessible/tests/mochitest/elm/a11y.ini
@@ -9,8 +9,9 @@ skip-if = buildapp == 'mulet'
 [test_figure.html]
 [test_listbox.xul]
 [test_MathMLSpec.html]
 [test_nsApplicationAcc.html]
 [test_plugin.html]
 skip-if = buildapp == 'mulet'
 [test_canvas.html]
 [test_shadowroot.html]
+skip-if = stylo # bug 1293844
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -1440,18 +1440,16 @@ AccessibleWrap::GetIAccessibleFor(const 
   // If the MSAA ID is not a chrome id then we already know that we won't
   // find it here and should look remotely instead. This handles the case when
   // accessible is part of the chrome process and is part of the xul browser
   // window and the child id points in the content documents. Thus we need to
   // make sure that it is never called on proxies.
   if (XRE_IsParentProcess() && !IsProxy() && !sIDGen.IsChromeID(varChild.lVal)) {
     return GetRemoteIAccessibleFor(varChild);
   }
-  MOZ_ASSERT(XRE_IsParentProcess() ||
-             sIDGen.IsIDForThisContentProcess(varChild.lVal));
 
   if (varChild.lVal > 0) {
     // Gecko child indices are 0-based in contrast to indices used in MSAA.
     MOZ_ASSERT(!IsProxy());
     Accessible* xpAcc = GetChildAt(varChild.lVal - 1);
     if (!xpAcc) {
       return nullptr;
     }
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -906,16 +906,17 @@ var RefreshBlocker = {
       }
     }
   },
 
   enable() {
     this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
                      .createInstance(Ci.nsIWebProgress);
     this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
+    this._filter.target = tabEventTarget;
 
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     webProgress.addProgressListener(this._filter, Ci.nsIWebProgress.NOTIFY_ALL);
 
     addMessageListener("RefreshBlocker:Refresh", this);
   },
 
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -38,20 +38,16 @@ var whitelist = [
   {file: "chrome://pdf.js/locale/viewer.properties"},
 
   // security/manager/pki/resources/content/device_manager.js
   {file: "chrome://pippki/content/load_device.xul"},
 
   // Used by setting this url as a pref in about:config
   {file: "chrome://browser/content/newtab/alternativeDefaultSites.json"},
 
-  // Temporary whitelisted while WebPayments in construction
-  // See Bug 1381141
-  {file: "chrome://payments/content/paymentRequest.xhtml"},
-
   // Add-on compat
   {file: "chrome://browser/skin/devtools/common.css"},
   {file: "chrome://global/content/XPCNativeWrapper.js"},
   {file: "chrome://global/locale/brand.dtd"},
 
   // The l10n build system can't package string files only for some platforms.
   // See bug 1339424 for why this is hard to fix.
   {file: "chrome://global/locale/fallbackMenubar.properties",
@@ -170,16 +166,24 @@ var whitelist = [
   {file: "resource://gre/modules/Manifest.jsm"},
   // Bug 1351097
   {file: "resource://gre/modules/accessibility/AccessFu.jsm"},
   // Bug 1351637
   {file: "resource://gre/modules/sdk/bootstrap.js"},
 
 ];
 
+// Temporary whitelisted while WebPayments in construction
+// See Bug 1381141
+if (AppConstants.NIGHTLY_BUILD && AppConstants.MOZ_BUILD_APP == "browser") {
+  whitelist.push(
+    {file: "chrome://payments/content/paymentRequest.xhtml"}
+  );
+}
+
 if (!AppConstants.MOZ_PHOTON_THEME) {
   whitelist.push(
     // Bug 1343824
     {file: "chrome://browser/skin/customizableui/customize-illustration-rtl@2x.png",
      platforms: ["linux", "win"]},
     {file: "chrome://browser/skin/customizableui/customize-illustration@2x.png",
      platforms: ["linux", "win"]},
     {file: "chrome://browser/skin/customizableui/info-icon-customizeTip@2x.png",
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -446,24 +446,31 @@
        context="toolbar-context-menu"
 #endif
        hidden="true">
 #ifdef MOZ_PHOTON_THEME
   <photonpanelmultiview mainViewId="widget-overflow-mainView">
     <panelview id="widget-overflow-mainView"
                context="toolbar-context-menu">
 #endif
-      <vbox id="widget-overflow-scroller">
-        <vbox id="widget-overflow-list" class="widget-overflow-list"
-              overflowfortoolbar="nav-bar"/>
-        <toolbarseparator id="widget-overflow-fixed-separator" hidden="true"/>
-        <vbox id="widget-overflow-fixed-list" class="widget-overflow-list" hidden="true"
-              emptylabel="&customizeMode.emptyOverflowList.description;"/>
+      <vbox class="panel-subview-body">
+        <vbox id="widget-overflow-scroller">
+          <vbox id="widget-overflow-list" class="widget-overflow-list"
+                overflowfortoolbar="nav-bar"/>
+          <toolbarseparator id="widget-overflow-fixed-separator" hidden="true"/>
+          <vbox id="widget-overflow-fixed-list" class="widget-overflow-list" hidden="true"
+                emptylabel="&customizeMode.emptyOverflowList.description;"/>
+        </vbox>
       </vbox>
 #ifdef MOZ_PHOTON_THEME
+      <toolbarbutton command="cmd_CustomizeToolbars"
+                      id="overflowMenu-customize-button"
+                      class="subviewbutton panel-subview-footer"
+                      accesskey="&overflowCustomizeToolbar.accesskey;"
+                      label="&overflowCustomizeToolbar.label;"/>
     </panelview>
   </photonpanelmultiview>
 #endif
 </panel>
 
 <panel id="customization-tipPanel"
        type="arrow"
        flip="none"
--- a/browser/components/extensions/ext-history.js
+++ b/browser/components/extensions/ext-history.js
@@ -60,19 +60,19 @@ const convertNodeToHistoryItem = node =>
 /*
  * Converts a nsINavHistoryResultNode into a VisitItem
  *
  * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
  */
 const convertNodeToVisitItem = node => {
   return {
     id: node.pageGuid,
-    visitId: node.visitId,
+    visitId: String(node.visitId),
     visitTime: PlacesUtils.toDate(node.time).getTime(),
-    referringVisitId: node.fromVisitId,
+    referringVisitId: String(node.fromVisitId),
     transition: getTransition(node.visitType),
   };
 };
 
 /*
  * Converts a nsINavHistoryContainerResultNode into an array of objects
  *
  * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryContainerResultNode
--- a/browser/components/extensions/schemas/devtools_inspected_window.json
+++ b/browser/components/extensions/schemas/devtools_inspected_window.json
@@ -131,23 +131,23 @@
           {
             "name": "callback",
             "type": "function",
             "description": "A function called when evaluation completes.",
             "optional": true,
             "parameters": [
               {
                 "name": "result",
-                "type": "object",
-                "additionalProperties": {"type": "any"},
+                "type": "any",
                 "description": "The result of evaluation."
               },
               {
                 "name": "exceptionInfo",
                 "type": "object",
+                "optional": true,
                 "description": "An object providing details if an exception occurred while evaluating the expression.",
                 "properties": {
                   "isError": {
                     "type": "boolean",
                     "description": "Set if the error occurred on the DevTools side before the expression is evaluated."
                   },
                   "code": {
                     "type": "string",
--- a/browser/components/extensions/schemas/tabs.json
+++ b/browser/components/extensions/schemas/tabs.json
@@ -53,34 +53,34 @@
         }
       },
       {
         "id": "Tab",
         "type": "object",
         "properties": {
           "id": {"type": "integer", "minimum": -1, "optional": true, "description": "The ID of the tab. Tab IDs are unique within a browser session. Under some circumstances a Tab may not be assigned an ID, for example when querying foreign tabs using the $(ref:sessions) API, in which case a session ID may be present. Tab ID can also be set to $(ref:tabs.TAB_ID_NONE) for apps and devtools windows."},
           "index": {"type": "integer", "minimum": -1, "description": "The zero-based index of the tab within its window."},
-          "windowId": {"type": "integer", "minimum": 0, "description": "The ID of the window the tab is contained within."},
+          "windowId": {"type": "integer", "optional": true, "minimum": 0, "description": "The ID of the window the tab is contained within."},
           "openerTabId": {"unsupported": true, "type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab that opened this tab, if any. This property is only present if the opener tab still exists."},
           "selected": {"type": "boolean", "description": "Whether the tab is selected.", "deprecated": "Please use $(ref:tabs.Tab.highlighted).", "unsupported": true},
           "highlighted": {"type": "boolean", "description": "Whether the tab is highlighted. Works as an alias of active"},
           "active": {"type": "boolean", "description": "Whether the tab is active in its window. (Does not necessarily mean the window is focused.)"},
           "pinned": {"type": "boolean", "description": "Whether the tab is pinned."},
           "lastAccessed": {"type": "integer", "optional": true, "description": "The last time the tab was accessed as the number of milliseconds since epoch."},
           "audible": {"type": "boolean", "optional": true, "description": "Whether the tab has produced sound over the past couple of seconds (but it might not be heard if also muted). Equivalent to whether the speaker audio indicator is showing."},
           "mutedInfo": {"$ref": "MutedInfo", "optional": true, "description": "Current tab muted state and the reason for the last state change."},
           "url": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL the tab is displaying. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
           "title": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The title of the tab. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
           "favIconUrl": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL of the tab's favicon. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission. It may also be an empty string if the tab is loading."},
           "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."},
           "incognito": {"type": "boolean", "description": "Whether the tab is in an incognito window."},
           "width": {"type": "integer", "optional": true, "description": "The width of the tab in pixels."},
           "height": {"type": "integer", "optional": true, "description": "The height of the tab in pixels."},
-          "sessionId": {"unsupported": true, "type": "string", "optional": true, "description": "The session ID used to uniquely identify a Tab obtained from the $(ref:sessions) API."},
-          "cookieStoreId": {"type": "string", "description": "The CookieStoreId used for the tab."}
+          "sessionId": {"type": "string", "optional": true, "description": "The session ID used to uniquely identify a Tab obtained from the $(ref:sessions) API."},
+          "cookieStoreId": {"type": "string", "optional": true, "description": "The CookieStoreId used for the tab."}
         }
       },
       {
         "id": "ZoomSettingsMode",
         "type": "string",
         "description": "Defines how zoom changes are handled, i.e. which entity is responsible for the actual scaling of the page; defaults to <code>automatic</code>.",
         "enum": [
           {
@@ -501,16 +501,17 @@
           {
             "type": "function",
             "name": "callback",
             "optional": true,
             "parameters": [
               {
                 "name": "tab",
                 "$ref": "Tab",
+                "optional": true,
                 "description": "Details about the created tab. Will contain the ID of the new tab."
               }
             ]
           }
         ]
       },
       {
         "name": "duplicate",
--- a/browser/components/preferences/in-content-new/main.xul
+++ b/browser/components/preferences/in-content-new/main.xul
@@ -384,18 +384,16 @@
                 label="&restoreDefault.label;"
                 accesskey="&restoreDefault.accesskey;"
                 preference="pref.browser.homepage.disable_button.restore_default"/>
       </html:td>
     </html:tr>
   </html:table>
 </groupbox>
 
-  <caption><label>&defaultSearchEngine.label;</label></caption>
-  <caption><label>&oneClickSearchEngines.label;</label></caption>
 <!-- Tab preferences -->
 <groupbox data-category="paneGeneral"
           hidden="true">
     <caption><label>&tabsGroup.label;</label></caption>
 
     <checkbox id="ctrlTabRecentlyUsedOrder" label="&ctrlTabRecentlyUsedOrder.label;"
               accesskey="&ctrlTabRecentlyUsedOrder.accesskey;"
               preference="browser.ctrlTab.previews"/>
@@ -452,19 +450,19 @@
 </hbox>
 
 <!-- Fonts and Colors -->
 <groupbox id="fontsGroup" data-category="paneGeneral" hidden="true">
   <caption><label>&fontsAndColors.label;</label></caption>
 
   <vbox>
     <hbox id="fontSettings">
-      <hbox align="center">
+      <hbox align="center" flex="1">
         <label control="defaultFont" accesskey="&defaultFont2.accesskey;">&defaultFont2.label;</label>
-        <menulist id="defaultFont" delayprefsave="true" onsyncfrompreference="return FontBuilder.readFontSelection(this);"/>
+        <menulist id="defaultFont" flex="1" delayprefsave="true" onsyncfrompreference="return FontBuilder.readFontSelection(this);"/>
         <label id="defaultFontSizeLabel" control="defaultFontSize" accesskey="&defaultSize2.accesskey;">&defaultSize2.label;</label>
         <menulist id="defaultFontSize" delayprefsave="true">
           <menupopup>
             <menuitem value="9" label="9"/>
             <menuitem value="10" label="10"/>
             <menuitem value="11" label="11"/>
             <menuitem value="12" label="12"/>
             <menuitem value="13" label="13"/>
@@ -729,16 +727,18 @@
       class="subcategory"
       hidden="true"
       data-category="paneGeneral">
   <label class="header-name" flex="1">&updateApplication.label;</label>
 </hbox>
 
 <!-- Update -->
 <groupbox id="updateApp" data-category="paneGeneral" hidden="true">
+  <label>&updateApplicationDescription.label;</label>
+  <separator/>
   <hbox align="start">
     <vbox flex="1">
       <description>
         &updateApplication.version.pre;<label id="version"/>&updateApplication.version.post;
         <label id="releasenotes" class="learnMore text-link" hidden="true">&releaseNotes.link;</label>
       </description>
       <description id="distribution" class="text-blurb" hidden="true"/>
       <description id="distributionId" class="text-blurb" hidden="true"/>
@@ -822,17 +822,19 @@
       <hbox id="manualUpdate" align="center">
         <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
         <spacer flex="1"/>
         <button label="&update.checkForUpdatesButton.label;"
                 accesskey="&update.checkForUpdatesButton.accesskey;"
                 disabled="true"/>
       </hbox>
       <hbox id="unsupportedSystem" align="center">
-        <label>&update.unsupported.start;</label><label id="unsupportedLink" class="text-link">&update.unsupported.linkText;</label><label>&update.unsupported.end;</label>
+        <description flex="1">
+          <label>&update.unsupported.start;</label><label id="unsupportedLink" class="text-link">&update.unsupported.linkText;</label><label>&update.unsupported.end;</label>
+        </description>
         <spacer flex="1"/>
         <button label="&update.checkForUpdatesButton.label;"
                 accesskey="&update.checkForUpdatesButton.accesskey;"
                 disabled="true"/>
       </hbox>
       <hbox id="restarting" align="center">
         <image class="update-throbber"/><label>&update.restarting;</label>
         <spacer flex="1"/>
@@ -845,18 +847,18 @@
 #endif
 
   <separator/>
 #ifdef MOZ_UPDATER
   <description>&updateApplication.description;</description>
   <radiogroup id="updateRadioGroup">
     <radio id="autoDesktop"
            value="auto"
-           label="&updateAuto2.label;"
-           accesskey="&updateAuto2.accesskey;"/>
+           label="&updateAuto3.label;"
+           accesskey="&updateAuto3.accesskey;"/>
     <radio value="checkOnly"
           label="&updateCheckChoose2.label;"
           accesskey="&updateCheckChoose2.accesskey;"/>
     <radio value="manual"
           label="&updateManual2.label;"
           accesskey="&updateManual2.accesskey;"/>
   </radiogroup>
 #ifdef MOZ_MAINTENANCE_SERVICE
--- a/browser/components/preferences/in-content-new/privacy.js
+++ b/browser/components/preferences/in-content-new/privacy.js
@@ -1217,26 +1217,26 @@ var gPrivacyPane = {
     this.observer = {
       onNetworkCacheDiskConsumption(consumption) {
         var size = DownloadUtils.convertByteUnits(consumption);
         // The XBL binding for the string bundle may have been destroyed if
         // the page was closed before this callback was executed.
         if (!prefStrBundle.getFormattedString) {
           return;
         }
-        actualSizeLabel.value = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
+        actualSizeLabel.textContent = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
       },
 
       QueryInterface: XPCOMUtils.generateQI([
         Components.interfaces.nsICacheStorageConsumptionObserver,
         Components.interfaces.nsISupportsWeakReference
       ])
     };
 
-    actualSizeLabel.value = prefStrBundle.getString("actualDiskCacheSizeCalculated");
+    actualSizeLabel.textContent = prefStrBundle.getString("actualDiskCacheSizeCalculated");
 
     try {
       var cacheService =
         Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
                   .getService(Components.interfaces.nsICacheStorageService);
       cacheService.asyncGetDiskConsumption(this.observer);
     } catch (e) {}
   },
--- a/browser/components/preferences/in-content-new/privacy.xul
+++ b/browser/components/preferences/in-content-new/privacy.xul
@@ -370,17 +370,17 @@
             accesskey="&locbar.history.accesskey;"
             preference="browser.urlbar.suggest.history"/>
   <checkbox id="bookmarkSuggestion" label="&locbar.bookmarks.label;"
             accesskey="&locbar.bookmarks.accesskey;"
             preference="browser.urlbar.suggest.bookmark"/>
   <checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
             accesskey="&locbar.openpage.accesskey;"
             preference="browser.urlbar.suggest.openpage"/>
-  <label class="text-link" onclick="gotoPref('general')">
+  <label class="text-link" onclick="gotoPref('search')">
     &suggestionSettings2.label;
   </label>
 </groupbox>
 
 <!-- Cache -->
 <groupbox id="cacheGroup" data-category="panePrivacy" hidden="true">
   <caption><label>&httpCache.label;</label></caption>
 
@@ -407,34 +407,37 @@
   </hbox>
 </groupbox>
 
 <!-- Site Data -->
 <groupbox id="siteDataGroup" hidden="true" data-category="panePrivacy" data-hidden-from-search="true">
   <caption><label>&siteData.label;</label></caption>
 
   <hbox align="baseline">
-    <label id="totalSiteDataSize"></label>
-    <label id="siteDataLearnMoreLink" class="learnMore text-link" value="&siteDataLearnMoreLink.label;"></label>
-    <spacer flex="1" />
-    <button id="clearSiteDataButton"
-            class="accessory-button"
-            icon="clear"
-            label="&clearSiteData.label;" accesskey="&clearSiteData.accesskey;"/>
+    <vbox flex="1">
+      <description flex="1">
+        <label id="totalSiteDataSize"></label>
+        <label id="siteDataLearnMoreLink" class="learnMore text-link" value="&siteDataLearnMoreLink.label;"></label>
+      </description>
+    </vbox>
+    <vbox align="end">
+      <button id="siteDataSettings"
+              class="accessory-button"
+              label="&siteDataSettings.label;"
+              accesskey="&siteDataSettings.accesskey;"
+              searchkeywords="&window.title;
+                              &hostCol.label;
+                              &statusCol.label;
+                              &usageCol.label;"/>
+      <button id="clearSiteDataButton"
+          class="accessory-button"
+          icon="clear"
+          label="&clearSiteData.label;" accesskey="&clearSiteData.accesskey;"/>
+    </vbox>
   </hbox>
-  <vbox align="end">
-    <button id="siteDataSettings"
-            class="accessory-button"
-            label="&siteDataSettings.label;"
-            accesskey="&siteDataSettings.accesskey;"
-            searchkeywords="&window.title;
-                            &hostCol.label;
-                            &statusCol.label;
-                            &usageCol.label;"/>
-  </vbox>
 </groupbox>
 
 <!-- Tracking -->
 <groupbox id="trackingGroup" data-category="panePrivacy" hidden="true">
   <caption><label>&trackingProtectionHeader2.label;</label></caption>
   <vbox>
     <hbox align="start">
       <vbox flex="1">
@@ -515,21 +518,21 @@
 <groupbox id="permissionsGroup" data-category="panePrivacy" hidden="true">
   <grid>
     <columns>
       <column flex="1"/>
       <column/>
     </columns>
     <rows>
       <row id="notificationsPolicyRow" align="center">
-        <hbox flex="1">
+        <description flex="1">
           <label id="notificationsPolicy">&notificationsPolicyDesc3.label;</label>
           <label id="notificationsPolicyLearnMore"
                  class="learnMore text-link">&notificationsPolicyLearnMore.label;</label>
-        </hbox>
+        </description>
         <hbox pack="end">
           <button id="notificationsPolicyButton"
                   class="accessory-button"
                   label="&notificationsPolicyButton.label;"
                   accesskey="&notificationsPolicyButton.accesskey;"
                   searchkeywords="&removepermission.label;
                                   &removeallpermissions.label;
                                   &button.cancel.label;
@@ -588,32 +591,32 @@
 <!-- Firefox Data Collection and Use -->
 #ifdef MOZ_DATA_REPORTING
 <groupbox id="dataCollectionGroup" data-category="panePrivacy" data-subcategory="reports" hidden="true">
   <description>
     &dataCollectionDesc.label;<label id="dataCollectionPrivacyNotice" class="learnMore text-link">&dataCollectionPrivacyNotice.label;</label>
   </description>
 
   <vbox>
-    <hbox align="center">
+    <description flex="1">
       <checkbox id="submitHealthReportBox" label="&enableHealthReport1.label;"
-                accesskey="&enableHealthReport1.accesskey;"/>
+                accesskey="&enableHealthReport1.accesskey;" flex="1" />
       <label id="FHRLearnMore"
              class="learnMore text-link">&healthReportLearnMore.label;</label>
-    </hbox>
+    </description>
 #ifndef MOZ_TELEMETRY_REPORTING
     <description id="TelemetryDisabledDesc" class="indent" control="telemetryGroup">&healthReportingDisabled.label;</description>
 #endif
   </vbox>
 #ifdef MOZ_CRASHREPORTER
   <hbox align="center">
     <checkbox id="automaticallySubmitCrashesBox"
               preference="browser.crashReports.unsubmittedCheck.autoSubmit"
               label="&alwaysSubmitCrashReports1.label;"
-              accesskey="&alwaysSubmitCrashReports1.accesskey;"/>
+              accesskey="&alwaysSubmitCrashReports1.accesskey;" flex="1" />
     <label id="crashReporterLearnMore"
            class="learnMore text-link">&crashReporterLearnMore.label;</label>
   </hbox>
 #endif
 </groupbox>
 #endif
 
 <hbox id="securityCategory"
--- a/browser/components/preferences/in-content-new/search.xul
+++ b/browser/components/preferences/in-content-new/search.xul
@@ -22,17 +22,17 @@
     <hbox id="searchCategory"
           class="subcategory"
           hidden="true"
           data-category="paneSearch">
       <label class="header-name" flex="1">&paneSearch.title;</label>
     </hbox>
 
     <!-- Default Search Engine -->
-    <groupbox id="defaultEngineGroup" align="start" data-category="paneSearch">
+    <groupbox id="defaultEngineGroup" data-category="paneSearch">
       <caption label="&defaultSearchEngine.label;"/>
       <label>&chooseYourDefaultSearchEngine2.label;</label>
       <menulist id="defaultEngine">
         <menupopup/>
       </menulist>
       <checkbox id="suggestionsInSearchFieldsCheckbox"
                 label="&provideSearchSuggestions.label;"
                 accesskey="&provideSearchSuggestions.accesskey;"
--- a/browser/components/preferences/in-content-new/sync.xul
+++ b/browser/components/preferences/in-content-new/sync.xul
@@ -152,31 +152,31 @@
               </vbox>
             </hbox>
           </deck>
         </groupbox>
         <groupbox id="syncOptions">
           <caption><label>&signedIn.settings.label;</label></caption>
           <description>&signedIn.settings.description;</description>
           <hbox id="fxaSyncEngines">
-            <vbox align="start" flex="1">
+            <vbox flex="1">
               <checkbox label="&engine.tabs.label2;"
                         accesskey="&engine.tabs.accesskey;"
                         preference="engine.tabs"/>
               <checkbox label="&engine.bookmarks.label;"
                         accesskey="&engine.bookmarks.accesskey;"
                         preference="engine.bookmarks"/>
               <checkbox label="&engine.logins.label;"
                         accesskey="&engine.logins.accesskey;"
                         preference="engine.passwords"/>
               <checkbox label="&engine.history.label;"
                         accesskey="&engine.history.accesskey;"
                         preference="engine.history"/>
             </vbox>
-            <vbox align="start" flex="1">
+            <vbox flex="1">
               <checkbox label="&engine.addons.label;"
                         accesskey="&engine.addons.accesskey;"
                         preference="engine.addons"/>
               <checkbox label="&engine.prefs.label;"
                         accesskey="&engine.prefs.accesskey;"
                         preference="engine.prefs"/>
               <checkbox label="&engine.addresses.label;"
                         accesskey="&engine.addresses.accesskey;"
--- a/browser/config/mozconfigs/linux32/debug
+++ b/browser/config/mozconfigs/linux32/debug
@@ -15,9 +15,8 @@ export MOZ_TELEMETRY_REPORTING=1
 #Use ccache
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux32/devedition
+++ b/browser/config/mozconfigs/linux32/devedition
@@ -15,9 +15,8 @@ ac_add_options --enable-verify-mar
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 ac_add_options --with-branding=browser/branding/aurora
 
 mk_add_options MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig
@@ -1,10 +1,8 @@
-no_sccache=1
-
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.no-compile"
 
 if test `uname -m` = "x86_64"; then
   ac_add_options --target=i686-pc-linux
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig-devedition
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig-devedition
@@ -1,10 +1,8 @@
-no_sccache=1
-
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-branding=browser/branding/aurora
 
 . "$topsrcdir/build/mozconfig.no-compile"
 
 if test `uname -m` = "x86_64"; then
   ac_add_options --target=i686-pc-linux
--- a/browser/config/mozconfigs/linux32/nightly
+++ b/browser/config/mozconfigs/linux32/nightly
@@ -6,9 +6,8 @@ ac_add_options --enable-verify-mar
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux64/debug
+++ b/browser/config/mozconfigs/linux64/debug
@@ -15,9 +15,8 @@ export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux64/debug-static-analysis-clang
+++ b/browser/config/mozconfigs/linux64/debug-static-analysis-clang
@@ -19,9 +19,8 @@ export CXX="$topsrcdir/clang/bin/clang++
 ac_add_options --enable-clang-plugin
 
 . "$topsrcdir/build/unix/mozconfig.stdcxx"
 
 export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
 . $topsrcdir/build/unix/mozconfig.gtk
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux64/devedition
+++ b/browser/config/mozconfigs/linux64/devedition
@@ -15,9 +15,8 @@ ac_add_options --enable-verify-mar
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 ac_add_options --with-branding=browser/branding/aurora
 
 mk_add_options MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig
@@ -1,10 +1,8 @@
-no_sccache=1
-
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.no-compile"
 
 export MOZILLA_OFFICIAL=1
 
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig-devedition
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig-devedition
@@ -1,10 +1,8 @@
-no_sccache=1
-
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --with-branding=browser/branding/aurora
 
 . "$topsrcdir/build/mozconfig.no-compile"
 
 export MOZILLA_OFFICIAL=1
 
--- a/browser/config/mozconfigs/linux64/nightly
+++ b/browser/config/mozconfigs/linux64/nightly
@@ -6,9 +6,8 @@ ac_add_options --enable-verify-mar
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux64/opt-static-analysis-clang
+++ b/browser/config/mozconfigs/linux64/opt-static-analysis-clang
@@ -18,9 +18,8 @@ CXX="$topsrcdir/clang/bin/clang++"
 ac_add_options --enable-clang-plugin
 
 . "$topsrcdir/build/unix/mozconfig.stdcxx"
 
 export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
 . $topsrcdir/build/unix/mozconfig.gtk
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx64/beta
+++ b/browser/config/mozconfigs/macosx64/beta
@@ -4,9 +4,8 @@ if [ -n "$ENABLE_RELEASE_PROMOTION" ]; t
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64/debug
@@ -15,9 +15,8 @@ ac_add_options --with-macbundlename-pref
 fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx64/debug-static-analysis
+++ b/browser/config/mozconfigs/macosx64/debug-static-analysis
@@ -5,9 +5,8 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 
 ac_add_options --enable-clang-plugin
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx64/devedition
+++ b/browser/config/mozconfigs/macosx64/devedition
@@ -20,9 +20,8 @@ fi
 
 if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
 ac_add_options --with-macbundlename-prefix=Firefox
 fi
 
 ac_add_options --with-branding=browser/branding/aurora
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx64/nightly
+++ b/browser/config/mozconfigs/macosx64/nightly
@@ -12,9 +12,8 @@ fi
 
 if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
 ac_add_options --with-macbundlename-prefix=Firefox
 fi
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx64/opt-static-analysis
+++ b/browser/config/mozconfigs/macosx64/opt-static-analysis
@@ -6,10 +6,9 @@ MOZ_AUTOMATION_L10N_CHECK=0
 
 ac_add_options --disable-debug
 ac_add_options --enable-optimize
 ac_add_options --enable-dmd
 
 ac_add_options --enable-clang-plugin
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
 
--- a/browser/config/mozconfigs/macosx64/release
+++ b/browser/config/mozconfigs/macosx64/release
@@ -11,9 +11,8 @@ fi
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
 # defines.sh during the beta cycle
 export BUILDING_RELEASE=1
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -21,56 +21,51 @@ for platform in ['linux32', 'linux64', '
     ]
 
 whitelist['nightly']['linux32'] += [
     'CXX=$REAL_CXX',
     'CXX="ccache $REAL_CXX"',
     'CC="ccache $REAL_CC"',
     'mk_add_options PROFILE_GEN_SCRIPT=@TOPSRCDIR@/build/profile_pageloader.pl',
     'ac_add_options --with-ccache=/usr/bin/ccache',
-    '. "$topsrcdir/build/mozconfig.cache"',
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
     'STRIP_FLAGS="--strip-debug"',
 ]
 
 whitelist['nightly']['linux64'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
     'STRIP_FLAGS="--strip-debug"',
     'ac_add_options --with-ccache=/usr/bin/ccache',
-    '. "$topsrcdir/build/mozconfig.cache"',
 ]
 
 whitelist['nightly']['macosx64'] += [
     'if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then',
     'ac_add_options --with-macbundlename-prefix=Firefox',
     'fi',
     'mk_add_options MOZ_MAKE_FLAGS="-j12"',
     'ac_add_options --with-ccache',
-    '. "$topsrcdir/build/mozconfig.cache"',
     'ac_add_options --disable-install-strip',
     'ac_add_options --enable-instruments',
     'ac_add_options --enable-dtrace',
     'if test `uname -s` != Linux; then',
 ]
 
 whitelist['nightly']['win32'] += [
     '. $topsrcdir/configs/mozilla2/win32/include/choose-make-flags',
     'mk_add_options MOZ_MAKE_FLAGS=-j1',
-    '. "$topsrcdir/build/mozconfig.cache"',
     'if test "$IS_NIGHTLY" != ""; then',
     'ac_add_options --disable-auto-deps',
     'fi',
 ]
 whitelist['nightly']['win64'] += [
     '. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"',
-    '. "$topsrcdir/build/mozconfig.cache"',
 ]
 
 for platform in all_platforms:
     whitelist['release'][platform] = [
         'ac_add_options --enable-update-channel=release',
         'ac_add_options --enable-official-branding',
         'mk_add_options MOZ_MAKE_FLAGS="-j4"',
         'export BUILDING_RELEASE=1',
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -18,9 +18,8 @@ export MOZ_TELEMETRY_REPORTING=1
 . $topsrcdir/build/win32/mozconfig.vs-latest
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win32/devedition
+++ b/browser/config/mozconfigs/win32/devedition
@@ -11,9 +11,8 @@ MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --enable-verify-mar
 
 ac_add_options --with-branding=browser/branding/aurora
 
 mk_add_options MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win32/nightly
+++ b/browser/config/mozconfigs/win32/nightly
@@ -2,9 +2,8 @@
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 ac_add_options --enable-profiling
 ac_add_options --enable-verify-mar
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -21,9 +21,8 @@ export MOZ_TELEMETRY_REPORTING=1
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win64/devedition
+++ b/browser/config/mozconfigs/win64/devedition
@@ -12,9 +12,8 @@ MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --enable-verify-mar
 
 ac_add_options --with-branding=browser/branding/aurora
 
 mk_add_options MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win64/nightly
+++ b/browser/config/mozconfigs/win64/nightly
@@ -3,9 +3,8 @@
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 ac_add_options --enable-profiling
 ac_add_options --enable-verify-mar
 
 ac_add_options --with-branding=browser/branding/nightly
 
 . "$topsrcdir/build/mozconfig.common.override"
-. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -11,19 +11,19 @@
     "size": 11189216,
     "digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
     "algorithm": "sha512",
     "filename": "gtk3.tar.xz",
     "setup": "setup.sh",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/linux64/asan.manifest
+++ b/browser/config/tooltool-manifests/linux64/asan.manifest
@@ -11,19 +11,28 @@
     "version": "clang 3.9.0, libgcc 4.9.4",
     "size": 166261192,
     "digest": "52f3fc23f0f5c98050f8b0ac7c92a6752d067582a16f712a5a58074be98975d594f9e36249fc2be7f1cc2ca6d509c663faaf2bea66f949243cc1f41651638ba6",
     "algorithm": "sha512",
     "filename": "clang.tar.xz",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
+    "algorithm": "sha512",
+    "visibility": "public",
+    "filename": "sccache2.tar.xz",
+    "unpack": true,
+    "digest": "7bbe53cda3f608826dc6a0266e648cd2ea09c88ef93edf87d582b41185b72740667e2c7bf6e9b2b911fb2915cbfb985e528598c7b3153092ad27d5e937342df7",
+    "size": 2191380
+  },
+  {
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "size": 12072532,
     "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
     "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -11,19 +11,19 @@
     "size": 12072532,
     "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
     "algorithm": "sha512",
     "filename": "gtk3.tar.xz",
     "setup": "setup.sh",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/linux64/clang.manifest.centos6
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest.centos6
@@ -11,19 +11,19 @@
     "size": 12072532,
     "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
     "algorithm": "sha512",
     "filename": "gtk3.tar.xz",
     "setup": "setup.sh",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/linux64/fuzzing.manifest
+++ b/browser/config/tooltool-manifests/linux64/fuzzing.manifest
@@ -12,16 +12,25 @@
     "size": 215309284,
     "visibility": "public",
     "digest": "8f6d386ca1d4606526dd24f366b1dbc1914c6c6d7f54c69c2a2ca0e7cfabe641c1168952d606295feffa9f38ad687084de5efb1e80be3ed2f431ac91de80039b",
     "algorithm": "sha512",
     "filename": "clang.tar.xz",
     "unpack": true
   },
   {
+    "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
+    "algorithm": "sha512",
+    "visibility": "public",
+    "filename": "sccache2.tar.xz",
+    "unpack": true,
+    "digest": "7bbe53cda3f608826dc6a0266e648cd2ea09c88ef93edf87d582b41185b72740667e2c7bf6e9b2b911fb2915cbfb985e528598c7b3153092ad27d5e937342df7",
+    "size": 2191380
+  },
+  {
     "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
     "size": 146886764,
     "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
--- a/browser/config/tooltool-manifests/linux64/hazard.manifest
+++ b/browser/config/tooltool-manifests/linux64/hazard.manifest
@@ -19,19 +19,19 @@
     "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
     "unpack": true,
     "setup": "setup.sh",
     "algorithm": "sha512",
     "filename": "gtk3.tar.xz",
     "size": 12072532
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/linux64/msan.manifest
+++ b/browser/config/tooltool-manifests/linux64/msan.manifest
@@ -11,19 +11,19 @@
     "version": "clang 3.9.0, libgcc 4.9.4",
     "size": 166261192,
     "digest": "52f3fc23f0f5c98050f8b0ac7c92a6752d067582a16f712a5a58074be98975d594f9e36249fc2be7f1cc2ca6d509c663faaf2bea66f949243cc1f41651638ba6",
     "algorithm": "sha512",
     "filename": "clang.tar.xz",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "size": 12072532,
     "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
     "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -11,19 +11,19 @@
     "size": 12072532,
     "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
     "algorithm": "sha512",
     "filename": "gtk3.tar.xz",
     "setup": "setup.sh",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 146886764,
-    "digest": "e03eeebd4acc593369d5635a059f55a6beed2d2fb839a8c196ccc735a246620d3285a15c17ab34fa8bcf9dd57dd25f735d4ef3eb2fc3be672bbde62342823f1e",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 161014632,
+    "digest": "65bebcf94fc66ea618c58c9ac33f0f206095ecfe3931cc6edb301f4b40480e3b44b0f39aea7a25fed8eef47e63523e7e670082947a3662cdc04c68ebbe5dfc89",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/macosx64/clang.manifest
+++ b/browser/config/tooltool-manifests/macosx64/clang.manifest
@@ -3,19 +3,19 @@
     "version": "clang 3.9.0",
     "size": 185632474,
     "digest": "0e1a556b65d6398fa812b9ceb5ce5e2dec3eda77d4a032a818182b34fc8ce602412f42388bb1fda6bea265d35c1dde3847a730b264fec01cd7e3dcfd39941660",
     "algorithm": "sha512",
     "filename": "clang.tar.bz2",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 97110232,
-    "digest": "7df456b9f86a0f11b81700b6bbb9451137beb5a4035fe2330dc507c804fe8230573636720dba60308eee5305b7c04bc041c025ca0ca98bef54f98f98b48dd8d7",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 109162660,
+    "digest": "3335320fe950c75fd02c0828d062f633a0eadd77482c5c5f096d5faddc1826e500a557129ef89f5cdb0b5f1778b74bd0b569c996b9f54bdb105ef2bff7e628eb",
     "algorithm": "sha512",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest
@@ -37,19 +37,19 @@
     "size": 57060,
     "visibility": "public",
     "digest": "0c96f0d3ace71c4110abec6f7ead013600b0a73c89465d840276090d849279e555d977fb2aa6bbabb7891d7191fc8cc8a4e8242be888114be52346b77a512fcc",
     "algorithm": "sha512",
     "unpack": true,
     "filename": "dmg.tar.xz"
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 141005088,
-    "digest": "8c915059da3df885c4b26efa25431719a41a108adbc900f49ca51419fee30480e32ac99aeb398954722c10b72dea6d1d39fc122846c86194b12063c9b85da47d",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 155690216,
+    "digest": "379f542ea16c775e7bcad36823f0068ca6a1f17c2b25e42ef978d51865298ba4207dc89bbb614805f81a123d12e339209a447afbd12c1122e16f4c7c41e7d92b",
     "algorithm": "sha512",
     "filename": "rustc.tar.xz",
     "unpack": true
   },
   {
     "size": 281576,
     "visibility": "public",
     "digest": "71616564533d138fb12f08e761c2638d054814fdf9c9439638ec57b201e100445c364d73d8d7a4f0e3b784898d5fe6264e8242863fc5ac40163f1791468bbc46",
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -3,19 +3,19 @@
     "version": "clang 3.9.0",
     "size": 185632474,
     "digest": "0e1a556b65d6398fa812b9ceb5ce5e2dec3eda77d4a032a818182b34fc8ce602412f42388bb1fda6bea265d35c1dde3847a730b264fec01cd7e3dcfd39941660",
     "algorithm": "sha512",
     "filename": "clang.tar.bz2",
     "unpack": true
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 97110232,
-    "digest": "7df456b9f86a0f11b81700b6bbb9451137beb5a4035fe2330dc507c804fe8230573636720dba60308eee5305b7c04bc041c025ca0ca98bef54f98f98b48dd8d7",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 109162660,
+    "digest": "3335320fe950c75fd02c0828d062f633a0eadd77482c5c5f096d5faddc1826e500a557129ef89f5cdb0b5f1778b74bd0b569c996b9f54bdb105ef2bff7e628eb",
     "algorithm": "sha512",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "cctools port from commit hash 8e9c3f2506b51",
     "size": 2233376,
     "digest": "d632ef587f0253f016aa5323999a3d9576284c04e66b5243a5780af9a55f474ac91ad8dee5bd86a6ee4e2593e2b345e2fd0aa4e8838b3686f84c5c5ac5c9c418",
--- a/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
+++ b/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
@@ -1,19 +1,19 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 90954208,
-    "digest": "6ee6ab72521c1f476fd15a3f2787f3046a1648f34cbc43380c2ba3915c2207b29c942fefe4b56426f5bafe47937c6a8074201d61a79d02ad366dace41d5cb717",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 97017057,
+    "digest": "b726645f9d26c5a3048720b3839166021c1cf91a02d2ff2f10c49adced7455c7352e18b5052084d80bf9d1c40ec1bf72d0397921b8cd23262f89fdbd10def58f",
     "algorithm": "sha512",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/win32/clang.manifest
+++ b/browser/config/tooltool-manifests/win32/clang.manifest
@@ -1,19 +1,19 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 90954208,
-    "digest": "6ee6ab72521c1f476fd15a3f2787f3046a1648f34cbc43380c2ba3915c2207b29c942fefe4b56426f5bafe47937c6a8074201d61a79d02ad366dace41d5cb717",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 97017057,
+    "digest": "b726645f9d26c5a3048720b3839166021c1cf91a02d2ff2f10c49adced7455c7352e18b5052084d80bf9d1c40ec1bf72d0397921b8cd23262f89fdbd10def58f",
     "algorithm": "sha512",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/win32/releng.manifest
+++ b/browser/config/tooltool-manifests/win32/releng.manifest
@@ -1,19 +1,19 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 90954208,
-    "digest": "6ee6ab72521c1f476fd15a3f2787f3046a1648f34cbc43380c2ba3915c2207b29c942fefe4b56426f5bafe47937c6a8074201d61a79d02ad366dace41d5cb717",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 97017057,
+    "digest": "b726645f9d26c5a3048720b3839166021c1cf91a02d2ff2f10c49adced7455c7352e18b5052084d80bf9d1c40ec1bf72d0397921b8cd23262f89fdbd10def58f",
     "algorithm": "sha512",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
     "visibility": "public",
--- a/browser/config/tooltool-manifests/win64/clang.manifest
+++ b/browser/config/tooltool-manifests/win64/clang.manifest
@@ -1,19 +1,19 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 98336380,
-    "digest": "92091d92ce135ee52486c31ae670735dd140ab5b1389f14582c4d9b14cbb393f7180399b9232564a3eb96443b568323070a3c1329deb07b145b28476e8271175",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 103602526,
+    "digest": "558d2d18991ad8b250a5d6b46a55e1ffdffc50d6bdd9cb4b3a945dd3d1143836b32e47f1df612bfea97ca2c02333ed43055b6c3030ecb1632385fb6940c1d246",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/win64/releng.manifest
+++ b/browser/config/tooltool-manifests/win64/releng.manifest
@@ -1,19 +1,19 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
   },
   {
-    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
-    "size": 98336380,
-    "digest": "92091d92ce135ee52486c31ae670735dd140ab5b1389f14582c4d9b14cbb393f7180399b9232564a3eb96443b568323070a3c1329deb07b145b28476e8271175",
+    "version": "rustc 1.19.0 (0ade33941 2017-07-17) repack",
+    "size": 103602526,
+    "digest": "558d2d18991ad8b250a5d6b46a55e1ffdffc50d6bdd9cb4b3a945dd3d1143836b32e47f1df612bfea97ca2c02333ed43055b6c3030ecb1632385fb6940c1d246",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "rustc.tar.bz2",
     "unpack": true
   },
   {
     "version": "sccache rev 69334a26ba65fc88e3934271a2ce6781c51b445e",
     "algorithm": "sha512",
new file mode 100644
--- /dev/null
+++ b/browser/config/tooltool-manifests/win64/sccache-build.manifest
@@ -0,0 +1,27 @@
+[
+  {
+    "version": "rustc 1.18.0 (03fc9d622 2017-06-06) repack",
+    "size": 98336380,
+    "digest": "92091d92ce135ee52486c31ae670735dd140ab5b1389f14582c4d9b14cbb393f7180399b9232564a3eb96443b568323070a3c1329deb07b145b28476e8271175",
+    "algorithm": "sha512",
+    "visibility": "public",
+    "filename": "rustc.tar.bz2",
+    "unpack": true
+  },
+  {
+    "version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
+    "size": 326656969,
+    "digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
+    "algorithm": "sha512",
+    "filename": "vs2015u3.zip",
+    "unpack": true
+  },
+  {
+    "version": "MinGit-2.13.3-64-bit",
+    "size": 21482885,
+    "digest": "929bb3c07be8487ee519422a312bdbfeec8f4db4b62c49d02f9aad9fd2a66c0ee5fad63d2b06c8744c336dc9d50446fa4457897333ad17ffd783ecabd1e2ddbb",
+    "algorithm": "sha512",
+    "filename": "git.zip",
+    "unpack": true
+  }
+]
--- a/browser/extensions/formautofill/test/browser/browser.ini
+++ b/browser/extensions/formautofill/test/browser/browser.ini
@@ -1,14 +1,16 @@
 [DEFAULT]
 head = head.js
 
 support-files =
   ../fixtures/autocomplete_basic.html
 
 [browser_autocomplete_footer.js]
+[browser_autocomplete_marked_back_forward.js]
+[browser_autocomplete_marked_detached_tab.js]
 [browser_check_installed.js]
 [browser_editProfileDialog.js]
 [browser_first_time_use_doorhanger.js]
 [browser_privacyPreferences.js]
 [browser_manageProfilesDialog.js]
 [browser_submission_in_private_mode.js]
 [browser_update_doorhanger.js]
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/browser/browser_autocomplete_marked_back_forward.js
@@ -0,0 +1,61 @@
+/**
+ * Test that autofill autocomplete works after back/forward navigation
+ */
+
+"use strict";
+
+const URL = BASE_URL + "autocomplete_basic.html";
+
+function checkPopup(autoCompletePopup) {
+  let first = autoCompletePopup.view.results[0];
+  const {primary, secondary} = JSON.parse(first.label);
+  ok(primary.startsWith(TEST_ADDRESS_1["street-address"].split("\n")[0]),
+     "Check primary label is street address");
+  is(secondary, TEST_ADDRESS_1["address-level2"], "Check secondary label is address-level2");
+}
+
+add_task(async function setup_storage() {
+  await saveAddress(TEST_ADDRESS_1);
+  await saveAddress(TEST_ADDRESS_2);
+  await saveAddress(TEST_ADDRESS_3);
+});
+
+add_task(async function test_back_forward() {
+  await BrowserTestUtils.withNewTab({gBrowser, url: URL}, async function(browser) {
+    const {autoCompletePopup} = browser;
+
+    // Check the page after the initial load
+    await openPopupOn(browser, "#street-address");
+    checkPopup(autoCompletePopup);
+
+    // Now navigate forward and make sure autofill autocomplete results are still attached
+    let loadPromise = BrowserTestUtils.browserLoaded(browser);
+    await BrowserTestUtils.loadURI(browser, `${URL}?load=2`);
+    await loadPromise;
+
+    // Check the second page
+    await openPopupOn(browser, "#street-address");
+    checkPopup(autoCompletePopup);
+
+    // Check after hitting back to the first page
+    let stoppedPromise = BrowserTestUtils.browserStopped(browser);
+    browser.goBack();
+    await stoppedPromise;
+    await openPopupOn(browser, "#street-address");
+    checkPopup(autoCompletePopup);
+
+    // Check after hitting forward to the second page
+    stoppedPromise = BrowserTestUtils.browserStopped(browser);
+    browser.goForward();
+    await stoppedPromise;
+    await openPopupOn(browser, "#street-address");
+    checkPopup(autoCompletePopup);
+
+    // Ensure the popup is closed before entering the next test.
+    await ContentTask.spawn(browser, {}, async function() {
+      content.document.getElementById("street-address").blur();
+    });
+    await BrowserTestUtils.waitForCondition(() => !autoCompletePopup.popupOpen,
+                                            "popup should have closed");
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/browser/browser_autocomplete_marked_detached_tab.js
@@ -0,0 +1,54 @@
+/**
+ * Test that autofill autocomplete works after detaching a tab
+ */
+
+"use strict";
+
+const URL = BASE_URL + "autocomplete_basic.html";
+
+function checkPopup(autoCompletePopup) {
+  let first = autoCompletePopup.view.results[0];
+  const {primary, secondary} = JSON.parse(first.label);
+  ok(primary.startsWith(TEST_ADDRESS_1["street-address"].split("\n")[0]),
+     "Check primary label is street address");
+  is(secondary, TEST_ADDRESS_1["address-level2"], "Check secondary label is address-level2");
+}
+
+add_task(async function setup_storage() {
+  await saveAddress(TEST_ADDRESS_1);
+  await saveAddress(TEST_ADDRESS_2);
+  await saveAddress(TEST_ADDRESS_3);
+});
+
+add_task(async function test_detach_tab_marked() {
+  await BrowserTestUtils.withNewTab({gBrowser, url: URL}, async function(browser) {
+    const {autoCompletePopup} = browser;
+
+    // Check the page after the initial load
+    await openPopupOn(browser, "#street-address");
+    checkPopup(autoCompletePopup);
+
+    // Detach the tab to a new window
+    let newWin = gBrowser.replaceTabWithWindow(gBrowser.getTabForBrowser(browser));
+    await TestUtils.topicObserved("browser-delayed-startup-finished", subject => {
+      return subject == newWin;
+    });
+
+    info("tab was detached");
+    let newBrowser = newWin.gBrowser.selectedBrowser;
+    ok(newBrowser, "Found new <browser>");
+    let newAutoCompletePopup = newBrowser.autoCompletePopup;
+    ok(newAutoCompletePopup, "Found new autocomplete popup");
+
+    await openPopupOn(newBrowser, "#street-address");
+    checkPopup(newAutoCompletePopup);
+
+    // Ensure the popup is closed before entering the next test.
+    await ContentTask.spawn(newBrowser, {}, async function() {
+      content.document.getElementById("street-address").blur();
+    });
+    await BrowserTestUtils.waitForCondition(() => !newAutoCompletePopup.popupOpen,
+                                           "popup should have closed");
+    await BrowserTestUtils.closeWindow(newWin);
+  });
+});
--- a/browser/extensions/formautofill/test/browser/head.js
+++ b/browser/extensions/formautofill/test/browser/head.js
@@ -39,27 +39,29 @@ const SECONDARY_BUTTON_INDEX = 1;
 async function sleep(ms = 500) {
   await new Promise(resolve => setTimeout(resolve, ms));
 }
 
 async function expectPopupOpen(browser) {
   const {autoCompletePopup, autoCompletePopup: {richlistbox: itemsBox}} = browser;
   const listItemElems = itemsBox.querySelectorAll(".autocomplete-richlistitem");
 
-  await BrowserTestUtils.waitForCondition(() => autoCompletePopup.popupOpen);
+  await BrowserTestUtils.waitForCondition(() => autoCompletePopup.popupOpen,
+                                         "popup should be open");
   await BrowserTestUtils.waitForCondition(() => {
     return [...listItemElems].every(item => {
       return (item.getAttribute("originaltype") == "autofill-profile" ||
              item.getAttribute("originaltype") == "autofill-footer") &&
              item.hasAttribute("formautofillattached");
     });
-  });
+  }, "The popup should be a form autofill one");
 }
 
 async function openPopupOn(browser, selector) {
+  await SimpleTest.promiseFocus(browser);
   /* eslint no-shadow: ["error", { "allow": ["selector"] }] */
   await ContentTask.spawn(browser, {selector}, async function({selector}) {
     content.document.querySelector(selector).focus();
   });
   await sleep(2000);
   await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
   await expectPopupOpen(browser);
 }
--- a/browser/extensions/onboarding/content/onboarding.css
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -308,16 +308,28 @@
   border: 1px solid transparent;
   border-radius: 0;
   color: #fff;
   float: inline-end;
   margin-inline-end: 26px;
   margin-top: -32px;
 }
 
+/* Remove default dotted outline around buttons' text */
+.onboarding-tour-action-button::-moz-focus-inner {
+  border: 0;
+}
+
+/* Keyboard focus specific outline */
+.onboarding-tour-action-button:-moz-focusring {
+  outline: 2px solid rgba(0,149,221,0.5);
+  outline-offset: 1px;
+  -moz-outline-radius: 2px;
+}
+
 .onboarding-tour-action-button:hover:not([disabled]) ,
 #onboarding-notification-action-btn:hover {
   background: #0060df;
   cursor: pointer;
 }
 
 .onboarding-tour-action-button:active:not([disabled]),
 #onboarding-notification-action-btn:active  {
--- a/browser/extensions/screenshots/install.rdf
+++ b/browser/extensions/screenshots/install.rdf
@@ -7,14 +7,14 @@
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!--Firefox-->
         <em:minVersion>51.0a1</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <em:type>2</em:type>
-    <em:version>10.8.0</em:version>
+    <em:version>10.9.0</em:version>
     <em:bootstrap>true</em:bootstrap>
     <em:homepageURL>https://pageshot.net/</em:homepageURL>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
   </Description>
 </RDF>
--- a/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
+++ b/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
@@ -424,17 +424,17 @@ window.inlineSelectionCss = `
   text-align: center;
   padding-top: 20px;
   width: 400px; }
 
 .myshots-all-buttons-container {
   display: flex;
   flex-direction: row-reverse;
   background: #f5f5f5;
-  border-radius: 1px;
+  border-radius: 2px;
   box-sizing: border-box;
   height: 80px;
   padding: 8px;
   position: absolute;
   right: 5px;
   top: 5px; }
   html[dir="rtl"] .myshots-all-buttons-container {
     left: 5px;
--- a/browser/extensions/screenshots/webextension/build/onboardingCss.js
+++ b/browser/extensions/screenshots/webextension/build/onboardingCss.js
@@ -226,24 +226,24 @@ body {
   top: 50%;
   transition: opacity 100ms cubic-bezier(0.07, 0.95, 0, 1);
   z-index: 10; }
 
 #skip:hover {
   opacity: 1; }
 
 .active-slide-1 #prev,
-.active-slide-4 #next {
+.active-slide-3 #next {
   display: none; }
 
 #done {
   background-image: url("MOZ_EXTENSION/icons/done.svg");
   display: none; }
 
-.active-slide-4 #done {
+.active-slide-3 #done {
   display: inline-block; }
 
 /* for smaller screen sizes */
 @media screen and (max-width: 768px) {
   .slide {
     height: 360px;
     width: 450px; }
     .slide .slide-image {
--- a/browser/extensions/screenshots/webextension/build/onboardingHtml.js
+++ b/browser/extensions/screenshots/webextension/build/onboardingHtml.js
@@ -5,17 +5,17 @@ window.onboardingHtml = `
   <head>
     <!-- onboarding.scss is automatically inserted here: -->
     <style></style>
     <!-- Here and in onboarding.scss use MOZ_EXTENSION/path to refer to local files -->
   </head>
   <body>
     <div id="slide-overlay">
       <!-- The current slide is set by having .active-slide-1, .active-slide-2, etc on #slide element: -->
-      <div id="slide-container" data-number-of-slides="4" class="active-slide-1">
+      <div id="slide-container" data-number-of-slides="3" class="active-slide-1">
         <div class="slide slide-1">
           <!-- Note: all images must be listed in manifest.json.template under web_accessible_resources -->
           <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-1.png');"></div>
           <div class="slide-content">
             <div class="slide-content-aligner">
               <h1><span><strong>Firefox</strong> Screenshots</span><sup>Beta</sup></h1>
               <p data-l10n-id="tourBodyOne"></p>
             </div>
@@ -25,40 +25,32 @@ window.onboardingHtml = `
         <div class="slide slide-2">
           <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-2.png');"></div>
           <div class="slide-content">
             <h1 data-l10n-id="tourHeaderTwo"></h1>
             <p data-l10n-id="tourBodyTwo"></p>
           </div>
         </div>
         <div class="slide slide-3">
-          <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-3.png');"></div>
-          <div class="slide-content">
-            <h1 data-l10n-id="tourHeaderThree"></h1>
-            <p data-l10n-id="tourBodyThree"></p>
-          </div>
-        </div>
-        <div class="slide slide-4">
           <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-4.png');"></div>
           <div class="slide-content">
             <h1 data-l10n-id="tourHeaderFour"></h1>
             <p data-l10n-id="tourBodyFour"></p>
           </div>
         </div>
 
         <!-- Clickable elements should be buttons for accessibility -->
         <button id="skip" data-l10n-id="tourSkip" tabindex=1>Skip</button>
         <button id="prev" tabindex=2 data-l10n-label-id="tourPrevious"></button>
         <button id="next" tabindex=3 data-l10n-label-id="tourNext"></button>
         <button id="done" tabindex=4 data-l10n-label-id="tourDone"></button>
         <div id="slide-status-container">
           <button class="goto-slide goto-slide-1" data-number="1" tabindex=4></button>
           <button class="goto-slide goto-slide-2" data-number="2" tabindex=5></button>
           <button class="goto-slide goto-slide-3" data-number="3" tabindex=6></button>
-          <button class="goto-slide goto-slide-4" data-number="4" tabindex=7></button>
         </div>
         <!-- FIXME: Need to put in privacy / etc links -->
       </div>
     </div>
   </body>
 </html>
 
 `;
--- a/browser/extensions/screenshots/webextension/manifest.json
+++ b/browser/extensions/screenshots/webextension/manifest.json
@@ -1,12 +1,12 @@
 {
   "manifest_version": 2,
   "name": "Firefox Screenshots",
-  "version": "10.8.0",
+  "version": "10.9.0",
   "description": "__MSG_addonDescription__",
   "author": "__MSG_addonAuthorsList__",
   "homepage_url": "https://github.com/mozilla-services/screenshots",
   "applications": {
     "gecko": {
       "id": "screenshots@mozilla.org"
     }
   },
--- a/browser/extensions/screenshots/webextension/onboarding/slides.html
+++ b/browser/extensions/screenshots/webextension/onboarding/slides.html
@@ -3,17 +3,17 @@
   <head>
     <!-- onboarding.scss is automatically inserted here: -->
     <style></style>
     <!-- Here and in onboarding.scss use MOZ_EXTENSION/path to refer to local files -->
   </head>
   <body>
     <div id="slide-overlay">
       <!-- The current slide is set by having .active-slide-1, .active-slide-2, etc on #slide element: -->
-      <div id="slide-container" data-number-of-slides="4" class="active-slide-1">
+      <div id="slide-container" data-number-of-slides="3" class="active-slide-1">
         <div class="slide slide-1">
           <!-- Note: all images must be listed in manifest.json.template under web_accessible_resources -->
           <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-1.png');"></div>
           <div class="slide-content">
             <div class="slide-content-aligner">
               <h1><span><strong>Firefox</strong> Screenshots</span><sup>Beta</sup></h1>
               <p data-l10n-id="tourBodyOne"></p>
             </div>
@@ -23,38 +23,30 @@
         <div class="slide slide-2">
           <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-2.png');"></div>
           <div class="slide-content">
             <h1 data-l10n-id="tourHeaderTwo"></h1>
             <p data-l10n-id="tourBodyTwo"></p>
           </div>
         </div>
         <div class="slide slide-3">
-          <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-3.png');"></div>
-          <div class="slide-content">
-            <h1 data-l10n-id="tourHeaderThree"></h1>
-            <p data-l10n-id="tourBodyThree"></p>
-          </div>
-        </div>
-        <div class="slide slide-4">
           <div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-4.png');"></div>
           <div class="slide-content">
             <h1 data-l10n-id="tourHeaderFour"></h1>
             <p data-l10n-id="tourBodyFour"></p>
           </div>
         </div>
 
         <!-- Clickable elements should be buttons for accessibility -->
         <button id="skip" data-l10n-id="tourSkip" tabindex=1>Skip</button>
         <button id="prev" tabindex=2 data-l10n-label-id="tourPrevious"></button>
         <button id="next" tabindex=3 data-l10n-label-id="tourNext"></button>
         <button id="done" tabindex=4 data-l10n-label-id="tourDone"></button>
         <div id="slide-status-container">
           <button class="goto-slide goto-slide-1" data-number="1" tabindex=4></button>
           <button class="goto-slide goto-slide-2" data-number="2" tabindex=5></button>
           <button class="goto-slide goto-slide-3" data-number="3" tabindex=6></button>
-          <button class="goto-slide goto-slide-4" data-number="4" tabindex=7></button>
         </div>
         <!-- FIXME: Need to put in privacy / etc links -->
       </div>
     </div>
   </body>
 </html>
--- a/browser/extensions/screenshots/webextension/selector/ui.js
+++ b/browser/extensions/screenshots/webextension/selector/ui.js
@@ -234,40 +234,31 @@ this.ui = (function() { // eslint-disabl
                      <div class="face-container">
                        <div class="eye left"><div class="eyeball"></div></div>
                        <div class="eye right"><div class="eyeball"></div></div>
                        <div class="face"></div>
                      </div>
                      <div class="preview-instructions"></div>
                      <div class="myshots-all-buttons-container">
                        <button class="myshots-button myshots-link" tabindex="1"></button>
-                       <div class="spacer"></div>
-                       <button class="myshots-button visible" tabindex="2"></button>
-                       <button class="myshots-button full-page" tabindex="3"></button>
                      </div>
                    </div>
                  </div>
                </body>`;
             installHandlerOnDocument(this.document);
             if (this.addClassName) {
               this.document.body.className = this.addClassName;
             }
             this.document.documentElement.dir = browser.i18n.getMessage("@@bidi_dir");
             this.document.documentElement.lang = browser.i18n.getMessage("@@ui_locale");
             const overlay = this.document.querySelector(".preview-overlay");
             overlay.querySelector(".preview-instructions").textContent = browser.i18n.getMessage("screenshotInstructions");
             overlay.querySelector(".myshots-link").textContent = browser.i18n.getMessage("myShotsLink");
-            overlay.querySelector(".visible").textContent = browser.i18n.getMessage("saveScreenshotVisibleArea");
-            overlay.querySelector(".full-page").textContent = browser.i18n.getMessage("saveScreenshotFullPage");
             overlay.querySelector(".myshots-button").addEventListener(
               "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onOpenMyShots)));
-            overlay.querySelector(".visible").addEventListener(
-              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onClickVisible)));
-            overlay.querySelector(".full-page").addEventListener(
-              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onClickFullPage)));
             resolve();
           }), {once: true});
           document.body.appendChild(this.element);
           this.unhide();
         } else {
           resolve();
         }
       });
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -327,16 +327,18 @@ These should match what Safari and other
 <!ENTITY viewMenu.label         "View"> 
 <!ENTITY viewMenu.accesskey       "V"> 
 <!ENTITY viewToolbarsMenu.label       "Toolbars"> 
 <!ENTITY viewToolbarsMenu.accesskey     "T"> 
 <!ENTITY viewSidebarMenu.label "Sidebar">
 <!ENTITY viewSidebarMenu.accesskey "e">
 <!ENTITY viewCustomizeToolbar.label       "Customize…"> 
 <!ENTITY viewCustomizeToolbar.accesskey     "C">
+<!ENTITY overflowCustomizeToolbar.label       "Customize Toolbar…">
+<!ENTITY overflowCustomizeToolbar.accesskey   "C">
 
 <!ENTITY historyMenu.label "History">
 <!ENTITY historyMenu.accesskey "s">
 <!ENTITY historyUndoMenu.label "Recently Closed Tabs">
 <!-- LOCALIZATION NOTE (historyUndoWindowMenu): see bug 394759 -->
 <!ENTITY historyUndoWindowMenu.label "Recently Closed Windows">
 <!ENTITY historyRestoreLastSession.label "Restore Previous Session">
 
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -85,21 +85,23 @@ available. -->
 -->
 <!ENTITY updateApplication.label         "&brandShortName; Updates">
 <!-- LOCALIZATION NOTE (updateApplication.version.*): updateApplication.version.pre
 # is followed by a version number, keep the trailing space or replace it with a
 # different character as needed. updateApplication.version.post is displayed
 # after the version number, and is empty on purpose for English. You can use it
 # if required by your language.
  -->
+<!ENTITY updateApplicationDescription.label
+                                         "Keep &brandShortName; up to date for the best performance, stability, and security.">
 <!ENTITY updateApplication.version.pre   "Version ">
 <!ENTITY updateApplication.version.post  "">
 <!ENTITY updateApplication.description   "Allow &brandShortName; to">
-<!ENTITY updateAuto2.label               "Automatically install updates (recommended for improved security)">
-<!ENTITY updateAuto2.accesskey           "A">
+<!ENTITY updateAuto3.label               "Automatically install updates (recommended)">
+<!ENTITY updateAuto3.accesskey           "A">
 <!ENTITY updateCheckChoose2.label        "Check for updates but let you choose to install them">
 <!ENTITY updateCheckChoose2.accesskey    "C">
 <!ENTITY updateManual2.label             "Never check for updates (not recommended)">
 <!ENTITY updateManual2.accesskey         "N">
 
 <!ENTITY updateHistory2.label            "Show Update History…">
 <!ENTITY updateHistory2.accesskey        "p">
 
--- a/browser/locales/en-US/chrome/browser/preferences/sync.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
@@ -49,17 +49,17 @@ both, to better adapt this sentence to t
 -->
 <!ENTITY signedInLoginFailure.beforename.label "Please sign in to reconnect">
 <!ENTITY signedInLoginFailure.aftername.label "">
 
 <!ENTITY notSignedIn.label           "You are not signed in.">
 <!ENTITY signIn.label                "Sign in">
 <!ENTITY signIn.accesskey            "g">
 <!ENTITY profilePicture.tooltip      "Change profile picture">
-<!ENTITY verifiedManage.label        "Manage Account">
+<!ENTITY verifiedManage.label        "Manage account">
 <!ENTITY verifiedManage.accesskey    "o">
 <!ENTITY disconnect3.label           "Disconnect…">
 <!ENTITY disconnect3.accesskey       "D">
 <!ENTITY verify.label                "Verify Email">
 <!ENTITY verify.accesskey            "V">
 <!ENTITY forget.label                "Forget this Email">
 <!ENTITY forget.accesskey            "F">
 
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1728,17 +1728,17 @@ toolbarpaletteitem[place=panel] > .toolb
 #widget-overflow > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 .cui-widget-panelview,
 %ifndef MOZ_PHOTON_THEME
 #widget-overflow-scroller {
 %else
-#widget-overflow-mainView {
+#widget-overflow-mainView .panel-subview-body {
 %endif
   overflow-y: auto;
   overflow-x: hidden;
 }
 
 #widget-overflow-scroller {
 %ifdef MOZ_PHOTON_THEME
   margin-top: 4px;
--- a/browser/themes/shared/incontentprefs-old/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs-old/preferences.inc.css
@@ -377,26 +377,28 @@ description > html|a {
   min-width: 30ch;
 }
 
 /**
  * Sync
  */
 
 #fxaProfileImage {
-  max-width: 60px;
+  width: 60px;
+  height: 60px;
   border-radius: 50%;
   list-style-image: url(chrome://browser/skin/fxa/default-avatar.svg);
   margin-inline-end: 15px;
   image-rendering: auto;
   border: 1px solid transparent;
 }
 
 #fxaLoginStatus[hasName] #fxaProfileImage {
-  max-width: 80px;
+  width: 80px;
+  height: 80px;
 }
 
 #fxaProfileImage.actionable {
   cursor: pointer;
 }
 
 #fxaProfileImage.actionable:hover {
   border-color: #0095DD;
@@ -513,17 +515,18 @@ description > html|a {
 #fxaEmailAddress1,
 #fxaEmailAddress2,
 #fxaEmailAddress3 {
   word-break: break-all;
 }
 
 .fxaFirefoxLogo {
   list-style-image: url(chrome://browser/skin/fxa/logo.png);
-  max-width: 64px;
+  width: 64px;
+  height: 64px;
   margin-inline-end: 14px;
 }
 
 .fxaMobilePromo {
   margin-bottom: 20px;
   margin-top: 25px;
 }
 
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -274,16 +274,20 @@ html|option {
 }
 
 /* XXX This style is for bug 740213 and should be removed once that
    bug has a solution. */
 description > html|a {
   cursor: pointer;
 }
 
+description > checkbox {
+  vertical-align: middle;
+}
+
 #weavePrefsDeck > vbox > label,
 #weavePrefsDeck > vbox > groupbox,
 #weavePrefsDeck > vbox > description,
 #weavePrefsDeck > #hasFxaAccount > vbox > label,
 #weavePrefsDeck > #hasFxaAccount > hbox > label {
   /* no margin-inline-start for elements at the beginning of a line */
   margin-inline-start: 0;
 }
@@ -397,26 +401,28 @@ groupbox {
   min-width: 30ch;
 }
 
 /**
  * Sync
  */
 
 #fxaProfileImage {
-  max-width: 60px;
+  width: 60px;
+  height: 60px;
   border-radius: 50%;
   list-style-image: url(chrome://browser/skin/fxa/default-avatar.svg);
   margin-inline-end: 15px;
   image-rendering: auto;
   border: 1px solid transparent;
 }
 
 #fxaLoginStatus[hasName] #fxaProfileImage {
-  max-width: 80px;
+  width: 80px;
+  height: 80px;
 }
 
 #fxaProfileImage.actionable {
   cursor: pointer;
 }
 
 #fxaProfileImage.actionable:hover {
   border-color: #0095DD;
@@ -533,17 +539,18 @@ groupbox {
 #fxaEmailAddress1,
 #fxaEmailAddress2,
 #fxaEmailAddress3 {
   word-break: break-all;
 }
 
 .fxaFirefoxLogo {
   list-style-image: url(chrome://browser/skin/fxa/logo.png);
-  max-width: 64px;
+  width: 64px;
+  height: 64px;
   margin-inline-end: 14px;
 }
 
 .fxaMobilePromo {
   margin-bottom: 20px;
   margin-top: 25px;
 }
 
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -196,21 +196,17 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -
     else
         DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
     fi
 fi
 
 # bionic in Android < 4.1 doesn't support PIE
 # On OSX, the linker defaults to building PIE programs when targeting OSX 10.7.
 # On other Unix systems, some file managers (Nautilus) can't start PIE programs
-if test -n "$gonkdir" && test "$ANDROID_VERSION" -ge 16; then
-    MOZ_PIE=1
-else
-    MOZ_PIE=
-fi
+MOZ_PIE=
 
 MOZ_ARG_ENABLE_BOOL(pie,
 [  --enable-pie           Enable Position Independent Executables],
     MOZ_PIE=1,
     MOZ_PIE= )
 
 if test "$GNU_CC$CLANG_CC" -a -n "$MOZ_PIE"; then
     AC_MSG_CHECKING([for PIE support])
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -274,19 +274,17 @@ def mozconfig_options(mozconfig, automat
 
         for key, value in mozconfig['env']['added'].iteritems():
             add(key, value)
             os.environ[key] = value
         for key, (_, value) in mozconfig['env']['modified'].iteritems():
             add(key, value)
             os.environ[key] = value
         for key, value in mozconfig['vars']['added'].iteritems():
-            # mozconfig_loader adds _IS_SET variables that are irrelevant
-            if not key.endswith('_IS_SET'):
-                add(key, value)
+            add(key, value)
         for key, (_, value) in mozconfig['vars']['modified'].iteritems():
             add(key, value)
 
 
 # Mozilla-Build
 # ==============================================================
 option(env='MOZILLABUILD', nargs=1,
        help='Path to Mozilla Build (Windows-only)')
@@ -904,18 +902,8 @@ def js_option(*args, **kwargs):
     opt = option(*args, **kwargs)
 
     @depends(opt.option, build_project)
     def js_option(value, build_project):
         if build_project != 'js':
             return value.format(opt.option)
 
     add_old_configure_arg(js_option)
-
-
-# Bug 1278542: This function is a workaround to resolve
-# |android_ndk_include|'s dependency on 'gonkdir.' The
-# actual implementation is located in b2g/moz.configure.
-# Remove this function as soon as 'android_ndk_include'
-# depends on 'target.'
-@depends('--help')
-def gonkdir(_):
-    return None
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -60,19 +60,19 @@ def have_yasm(value):
 
 set_config('HAVE_YASM', have_yasm)
 # Until the YASM variable is not necessary in old-configure.
 add_old_configure_assignment('YASM', have_yasm)
 
 # Android NDK
 # ==============================================================
 
-@depends('--disable-compile-environment', build_project, gonkdir, '--help')
-def compiling_android(compile_env, build_project, gonkdir, _):
-    return compile_env and (gonkdir or build_project in ('mobile/android', 'js'))
+@depends('--disable-compile-environment', build_project, '--help')
+def compiling_android(compile_env, build_project, _):
+    return compile_env and build_project in ('mobile/android', 'js')
 
 include('android-ndk.configure', when=compiling_android)
 
 # MacOS deployment target version
 # ==============================================================
 # This needs to happen before any compilation test is done.
 
 option('--enable-macos-target', env='MACOSX_DEPLOYMENT_TARGET', nargs=1,
--- a/build/mozconfig.cache
+++ b/build/mozconfig.cache
@@ -9,17 +9,17 @@ if test -z "$bucket" -a -z "$NO_CACHE"; 
 
 # buildbot (or builders that use buildprops.json):
 if [ -f $topsrcdir/../buildprops.json ]; then
 read branch platform master <<EOF
 $(python2.7 -c 'import json; p = json.loads(open("'"$topsrcdir"'/../buildprops.json").read())["properties"]; print p["branch"], p["platform"], p["master"]' 2> /dev/null)
 EOF
 
 bucket=
-if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z "$MOZ_PGO"; then
+if test -z "$SCCACHE_DISABLE"; then
     case "${branch}" in
     try)
         case "${master}" in
         *scl1.mozilla.com*|*.scl3.mozilla.com*)
             bucket=mozilla-releng-s3-cache-us-west-1-try
             ;;
         *use1.mozilla.com*)
             bucket=mozilla-releng-s3-cache-us-east-1-try
@@ -39,17 +39,17 @@ if test -z "$SCCACHE_DISABLE" -a -z "$no
             ;;
         esac
         ;;
     esac
 fi
 fi
 
 # builds where buildprops didn't have the data (eg: taskcluster or non-buildbot) and without sccache disabled:
-if test -z "$bucket" -a -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z "$MOZ_PGO"; then
+if test -z "$bucket" -a -z "$SCCACHE_DISABLE"; then
 
     # prevent rerun if az is set, or wget is not available
     if test -z "$availability_zone" -a -x "$(command -v wget)"; then
         if test -n "${TASKCLUSTER_WORKER_GROUP}"; then
             # TASKCLUSTER_WORKER_GROUP is just the region now, so
             # stick an extra character on to make the already-convoluted logic
             # here simpler.
             availability_zone="${TASKCLUSTER_WORKER_GROUP}x"
@@ -103,26 +103,26 @@ if test -z "$platform"; then
         ;;
     esac
 fi
 
 if test -z "$bucket"; then
     case "$platform" in
     win*) : ;;
     *)
-        ac_add_options --with-ccache
+        export CCACHE=ccache
     esac
 else
     mk_add_options "export SCCACHE_BUCKET=$bucket"
     case "$master" in
     *us[ew][12].mozilla.com*|*euc1.mozilla.com*)
         mk_add_options "export SCCACHE_NAMESERVER=169.254.169.253"
         ;;
     esac
-    ac_add_options "--with-ccache=$topsrcdir/sccache2/sccache${suffix}"
+    export CCACHE="$topsrcdir/sccache2/sccache${suffix}"
     export SCCACHE_VERBOSE_STATS=1
     mk_add_options MOZ_PREFLIGHT_ALL+=build/sccache.mk
     mk_add_options MOZ_POSTFLIGHT_ALL+=build/sccache.mk
     mk_add_options "UPLOAD_EXTRA_FILES+=sccache.log.gz"
     case "$platform" in
     win*)
         # sccache supports a special flag to create depfiles.
         #TODO: bug 1318370 - move this all into toolchain.configure
--- a/build/mozconfig.common
+++ b/build/mozconfig.common
@@ -18,8 +18,9 @@ ac_add_options --enable-crashreporter
 MOZ_ADDON_SIGNING=${MOZ_ADDON_SIGNING-1}
 # Disable enforcing that add-ons are signed by the trusted root
 MOZ_REQUIRE_SIGNING=${MOZ_REQUIRE_SIGNING-0}
 
 ac_add_options --enable-js-shell
 
 . "$topsrcdir/build/mozconfig.automation"
 . "$topsrcdir/build/mozconfig.rust"
+. "$topsrcdir/build/mozconfig.cache"
--- a/build/mozconfig.no-compile
+++ b/build/mozconfig.no-compile
@@ -1,10 +1,15 @@
 ac_add_options --disable-compile-environment
 
+# In case mozconfig.cache was already included
+unset CCACHE
+# In case it wasn't
+NO_CACHE=1
+
 # Override any toolchain defines we've inherited from other mozconfigs.
 unset CC
 unset CXX
 unset HOST_CC
 unset HOST_CXX
 unset RUSTC
 unset CARGO
 unset MAKECAB
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -501,16 +501,20 @@ int do_relocation_section(Elf *elf, unsi
     if (dyn == nullptr) {
         fprintf(stderr, "Couldn't find SHT_DYNAMIC section\n");
         return -1;
     }
 
     ElfSegment *relro = elf->getSegmentByType(PT_GNU_RELRO);
 
     ElfRel_Section<Rel_Type> *section = (ElfRel_Section<Rel_Type> *)dyn->getSectionForType(Rel_Type::d_tag);
+    if (section == nullptr) {
+        fprintf(stderr, "No relocations\n");
+        return -1;
+    }
     assert(section->getType() == Rel_Type::sh_type);
 
     Elf32_Shdr relhack32_section =
         { 0, SHT_PROGBITS, SHF_ALLOC, 0, (Elf32_Off)-1, 0, SHN_UNDEF, 0,
           Elf_RelHack::size(elf->getClass()), Elf_RelHack::size(elf->getClass()) }; // TODO: sh_addralign should be an alignment, not size
     Elf32_Shdr relhackcode32_section =
         { 0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, (Elf32_Off)-1, 0,
           SHN_UNDEF, 0, 1, 0 };
--- a/devtools/client/inspector/boxmodel/components/BoxModelInfo.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelInfo.js
@@ -30,20 +30,20 @@ module.exports = createClass({
   onToggleGeometryEditor(e) {
     this.props.onToggleGeometryEditor();
   },
 
   render() {
     let { boxModel } = this.props;
     let { geometryEditorEnabled, layout } = boxModel;
     let {
-      height,
+      height = "-",
       isPositionEditable,
       position,
-      width,
+      width = "-",
     } = layout;
 
     let buttonClass = "layout-geometry-editor devtools-button";
     if (geometryEditorEnabled) {
       buttonClass += " checked";
     }
 
     return dom.div(
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -115,38 +115,38 @@ module.exports = createClass({
    * Returns true if the position is displayed and false otherwise.
    */
   getDisplayPosition() {
     let { layout } = this.props.boxModel;
     return layout.position && layout.position != "static";
   },
 
   getHeightValue(property) {
-    let { layout } = this.props.boxModel;
-
     if (property == undefined) {
       return "-";
     }
 
+    let { layout } = this.props.boxModel;
+
     property -= parseFloat(layout["border-top-width"]) +
                 parseFloat(layout["border-bottom-width"]) +
                 parseFloat(layout["padding-top"]) +
                 parseFloat(layout["padding-bottom"]);
     property = parseFloat(property.toPrecision(6));
 
     return property;
   },
 
   getWidthValue(property) {
-    let { layout } = this.props.boxModel;
-
     if (property == undefined) {
       return "-";
     }
 
+    let { layout } = this.props.boxModel;
+
     property -= parseFloat(layout["border-left-width"]) +
                 parseFloat(layout["border-right-width"]) +
                 parseFloat(layout["padding-left"]) +
                 parseFloat(layout["padding-right"]);
     property = parseFloat(property.toPrecision(6));
 
     return property;
   },
--- a/devtools/client/netmonitor/index.js
+++ b/devtools/client/netmonitor/index.js
@@ -10,22 +10,19 @@
  * See README.md for more information.
  */
 const React = require("react");
 const ReactDOM = require("react-dom");
 const { bindActionCreators } = require("redux");
 const { bootstrap, renderRoot } = require("devtools-launchpad");
 const EventEmitter = require("devtools-modules/src/utils/event-emitter");
 const { Services: { appinfo, pref }} = require("devtools-modules");
-const { configureStore } = require("./src/utils/create-store");
 
-require("./src/assets/styles/netmonitor.css");
-
-EventEmitter.decorate(window);
-
+// Initialize preferences as early as possible
+pref("devtools.cache.disabled", false);
 pref("devtools.netmonitor.enabled", true);
 pref("devtools.netmonitor.filters", "[\"all\"]");
 pref("devtools.netmonitor.visibleColumns",
      "[\"status\",\"method\",\"file\",\"domain\",\"cause\"," +
      "\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
 );
 pref("devtools.netmonitor.panes-network-details-width", 550);
 pref("devtools.netmonitor.panes-network-details-height", 450);
@@ -36,16 +33,21 @@ pref("devtools.netmonitor.har.jsonpCallb
 pref("devtools.netmonitor.har.includeResponseBodies", true);
 pref("devtools.netmonitor.har.compress", false);
 pref("devtools.netmonitor.har.forceExport", false);
 pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
 pref("devtools.netmonitor.har.enableAutoExportToFile", false);
 pref("devtools.webconsole.persistlog", false);
 pref("devtools.styleeditor.enabled", true);
 
+const { configureStore } = require("./src/utils/create-store");
+
+require("./src/assets/styles/netmonitor.css");
+
+EventEmitter.decorate(window);
 const App = require("./src/components/app");
 const store = configureStore();
 const actions = bindActionCreators(require("./src/actions"), store.dispatch);
 const { onConnect } = require("./src/connector");
 
 // Inject to global window for testing
 window.store = store;
 
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2985,18 +2985,18 @@ Element::List(FILE* out, int32_t aIndent
   fprintf(out, "@%p", (void *)this);
 
   ListAttributes(out);
 
   fprintf(out, " state=[%llx]",
           static_cast<unsigned long long>(State().GetInternalValue()));
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   if (IsCommonAncestorForRangeInSelection()) {
-    nsRange::RangeHashTable* ranges =
-      static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
+    const nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
+      GetExistingCommonAncestorRanges();
     fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
   }
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
 
   nsIContent* child = GetFirstChild();
   if (child) {
     fputs("\n", out);
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -653,16 +653,29 @@ nsNodeSupportsWeakRefTearoff::GetWeakRef
   }
 
   NS_ADDREF(*aInstancePtr = slots->mWeakReference);
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
+
+static const size_t MaxDOMSlotSizeAllowed =
+#ifdef HAVE_64BIT_BUILD
+128;
+#else
+64;
+#endif
+
+static_assert(sizeof(nsINode::nsSlots) <= MaxDOMSlotSizeAllowed,
+              "DOM slots cannot be grown without consideration");
+static_assert(sizeof(FragmentOrElement::nsDOMSlots) <= MaxDOMSlotSizeAllowed,
+              "DOM slots cannot be grown without consideration");
+
 FragmentOrElement::nsDOMSlots::nsDOMSlots()
   : nsINode::nsSlots(),
     mDataset(nullptr)
 {
 }
 
 FragmentOrElement::nsDOMSlots::~nsDOMSlots()
 {
--- a/dom/base/StructuredCloneBlob.cpp
+++ b/dom/base/StructuredCloneBlob.cpp
@@ -17,27 +17,32 @@
 #include "mozilla/dom/StructuredCloneTags.h"
 
 namespace mozilla {
 namespace dom {
 
 StructuredCloneBlob::StructuredCloneBlob()
     : StructuredCloneHolder(CloningSupported, TransferringNotSupported,
                             StructuredCloneScope::DifferentProcess)
-{};
+{}
+
+StructuredCloneBlob::~StructuredCloneBlob()
+{
+  UnregisterWeakMemoryReporter(this);
+}
 
 
 /* static */ already_AddRefed<StructuredCloneBlob>
 StructuredCloneBlob::Constructor(GlobalObject& aGlobal, JS::HandleValue aValue,
                                  JS::HandleObject aTargetGlobal,
                                  ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.Context();
 
-  RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
+  RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create();
 
   Maybe<JSAutoCompartment> ac;
   JS::RootedValue value(cx, aValue);
 
   if (aTargetGlobal) {
     JS::RootedObject targetGlobal(cx, js::CheckedUnwrap(aTargetGlobal));
     if (!targetGlobal) {
       js::ReportAccessDenied(cx);
@@ -99,17 +104,17 @@ StructuredCloneBlob::Deserialize(JSConte
 
 
 /* static */ JSObject*
 StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
                                          StructuredCloneHolder* aHolder)
 {
   JS::RootedObject obj(aCx);
   {
-    RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
+    RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create();
 
     if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
         !holder->WrapObject(aCx, nullptr, &obj)) {
       return nullptr;
     }
   }
   return obj.get();
 }
@@ -176,10 +181,25 @@ StructuredCloneBlob::WriteStructuredClon
 }
 
 bool
 StructuredCloneBlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto, JS::MutableHandleObject aResult)
 {
     return StructuredCloneHolderBinding::Wrap(aCx, this, aGivenProto, aResult);
 }
 
+
+NS_IMETHODIMP
+StructuredCloneBlob::CollectReports(nsIHandleReportCallback* aHandleReport,
+                                    nsISupports* aData, bool aAnonymize)
+{
+  MOZ_COLLECT_REPORT(
+    "explicit/dom/structured-clone-holder", KIND_HEAP, UNITS_BYTES,
+    MallocSizeOf(this) + SizeOfExcludingThis(MallocSizeOf),
+    "Memory used by StructuredCloneHolder DOM objects.");
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(StructuredCloneBlob, nsIMemoryReporter)
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/StructuredCloneBlob.h
+++ b/dom/base/StructuredCloneBlob.h
@@ -4,32 +4,33 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_StructuredCloneBlob_h
 #define mozilla_dom_StructuredCloneBlob_h
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/StructuredCloneHolderBinding.h"
-#include "mozilla/RefCounted.h"
 
 #include "jsapi.h"
 
+#include "nsIMemoryReporter.h"
 #include "nsISupports.h"
 
 namespace mozilla {
 namespace dom {
 
-class StructuredCloneBlob : public StructuredCloneHolder
-                          , public RefCounted<StructuredCloneBlob>
+class StructuredCloneBlob final : public nsIMemoryReporter
+                                , public StructuredCloneHolder
 {
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
+
 public:
-  MOZ_DECLARE_REFCOUNTED_TYPENAME(StructuredCloneBlob)
-
-  explicit StructuredCloneBlob();
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMEMORYREPORTER
 
   static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
                                        StructuredCloneHolder* aHolder);
   bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
                             StructuredCloneHolder* aHolder);
 
   static already_AddRefed<StructuredCloneBlob>
   Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, JS::HandleObject aTargetGlobal, ErrorResult& aRv);
@@ -38,22 +39,28 @@ public:
                    JS::MutableHandleValue aResult, ErrorResult& aRv);
 
   nsISupports* GetParentObject() const { return nullptr; }
   JSObject* GetWrapper() const { return nullptr; }
 
   bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandleObject aResult);
 
 protected:
-  template <typename T, detail::RefCountAtomicity>
-  friend class detail::RefCounted;
-
-  ~StructuredCloneBlob() = default;
+  virtual ~StructuredCloneBlob();
 
 private:
+  explicit StructuredCloneBlob();
+
+  static already_AddRefed<StructuredCloneBlob> Create()
+  {
+    RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
+    RegisterWeakMemoryReporter(holder);
+    return holder.forget();
+  }
+
   bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
                                    StructuredCloneHolder* aHolder);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_StructuredCloneBlob_h
--- a/dom/base/StructuredCloneHolder.h
+++ b/dom/base/StructuredCloneHolder.h
@@ -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/. */
 
 #ifndef mozilla_dom_StructuredCloneHolder_h
 #define mozilla_dom_StructuredCloneHolder_h
 
 #include "jsapi.h"
 #include "js/StructuredClone.h"
+#include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsISupports.h"
 #include "nsTArray.h"
 
 #ifdef DEBUG
 #include "nsIThread.h"
@@ -111,16 +112,25 @@ public:
   }
 
   JSStructuredCloneData& BufferData() const
   {
     MOZ_ASSERT(mBuffer, "Write() has never been called.");
     return mBuffer->data();
   }
 
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+  {
+    size_t size = 0;
+    if (HasData()) {
+      size += mBuffer->sizeOfIncludingThis(aMallocSizeOf);
+    }
+    return size;
+  }
+
 protected:
   UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
 
   StructuredCloneScope mStructuredCloneScope;
 
 #ifdef DEBUG
   bool mClearCalled;
 #endif
@@ -301,16 +311,22 @@ protected:
                       JSStructuredCloneData& aBuffer,
                       uint32_t aAlgorithmVersion,
                       JS::MutableHandle<JS::Value> aValue,
                       ErrorResult &aRv);
 
   bool mSupportsCloning;
   bool mSupportsTransferring;
 
+  // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't
+  // account for objects in the following arrays because a) they're not expected
+  // to be stored in long-lived StructuredCloneHolder objects, and b) in the
+  // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters,
+  // and the other types do not hold significant amounts of memory alive.
+
   // Used for cloning blobs in the structured cloning algorithm.
   nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
 
   // Used for cloning JS::WasmModules in the structured cloning algorithm.
   nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
 
   // Used for cloning InputStream in the structured cloning algorithm.
   nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray;
--- a/dom/base/TabGroup.h
+++ b/dom/base/TabGroup.h
@@ -2,16 +2,17 @@
 /* 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 TabGroup_h
 #define TabGroup_h
 
+#include "nsHashKeys.h"
 #include "nsISupportsImpl.h"
 #include "nsIPrincipal.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 
 #include "mozilla/Atomics.h"
 #include "mozilla/SchedulerGroup.h"
 #include "mozilla/RefPtr.h"
@@ -38,16 +39,17 @@ class TabChild;
 // A TabGroup is a set of browsing contexts which are all "related". Within a
 // TabGroup, browsing contexts are broken into "similar-origin" DocGroups. In
 // more detail, a DocGroup is actually a collection of documents, and a
 // TabGroup is a collection of DocGroups. A TabGroup typically will contain
 // (through its DocGroups) the documents from one or more tabs related by
 // window.opener. A DocGroup is a member of exactly one TabGroup.
 
 class DocGroup;
+class TabChild;
 
 class TabGroup final : public SchedulerGroup
 {
 private:
   class HashEntry : public nsCStringHashKey
   {
   public:
     // NOTE: Weak reference. The DocGroup destructor removes itself from its
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -1286,16 +1286,18 @@ TimeoutManager::MaybeStartThrottleTimeou
     do_CreateInstance("@mozilla.org/timer;1");
   if (!mThrottleTimeoutsTimer) {
     return;
   }
 
   nsCOMPtr<nsITimerCallback> callback =
     new ThrottleTimeoutsCallback(&mWindow);
 
+  mThrottleTimeoutsTimer->SetTarget(EventTarget());
+
   mThrottleTimeoutsTimer->InitWithCallback(
     callback, gTimeoutThrottlingDelay, nsITimer::TYPE_ONE_SHOT);
 }
 
 void
 TimeoutManager::BeginSyncOperation()
 {
   // If we're beginning a sync operation, the currently running
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -845,16 +845,23 @@ nsFrameMessageManager::GetContent(mozIDO
 NS_IMETHODIMP
 nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
 {
   *aDocShell = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsFrameMessageManager::GetTabEventTarget(nsIEventTarget** aTarget)
+{
+  *aTarget = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
                             nsAString& aAsciiBase64String)
 {
   return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::Atob(const nsAString& aAsciiString,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1028,17 +1028,17 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMW
   mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
   mDesktopModeViewport(false), mIsRootOuterWindow(false), mInnerWindow(nullptr),
   mOuterWindow(aOuterWindow),
   // Make sure no actual window ends up with mWindowID == 0
   mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
   mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false),
   mLargeAllocStatus(LargeAllocStatus::NONE),
   mHasTriedToCacheTopInnerWindow(false),
-  mNumOfIndexedDBDatabases(0), mCleanedUp(false)
+  mNumOfIndexedDBDatabases(0)
 {
   if (aOuterWindow) {
     mTimeoutManager =
       MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindow::Cast(AsInner()));
   }
 }
 
 template<class T>
@@ -1615,16 +1615,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mIdleRequestExecutor(nullptr),
 #ifdef DEBUG
     mSetOpenerWindowCalled(false),
 #endif
 #ifdef MOZ_B2G
     mNetworkUploadObserverEnabled(false),
     mNetworkDownloadObserverEnabled(false),
 #endif
+    mCleanedUp(false),
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true),
 #ifdef DEBUG
     mIsValidatingTabGroup(false),
 #endif
     mCanSkipCCGeneration(0),
     mAutoActivateVRDisplayID(0),
     mBeforeUnloadListenerCount(0)
@@ -2000,20 +2001,17 @@ nsGlobalWindow::CleanUp()
 
   mAudioWorklet = nullptr;
   mPaintWorklet = nullptr;
 
   mExternal = nullptr;
 
   mMozSelfSupport = nullptr;
 
-  if (mPerformance) {
-    mPerformance->Shutdown();
-    mPerformance = nullptr;
-  }
+  mPerformance = nullptr;
 
 #ifdef MOZ_WEBSPEECH
   mSpeechSynthesis = nullptr;
 #endif
 
 #if defined(MOZ_WIDGET_ANDROID)
   mOrientationChangeObserver = nullptr;
 #endif
@@ -4358,20 +4356,19 @@ nsGlobalWindow::GetPerformance()
   return AsInner()->GetPerformance();
 }
 
 void
 nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded()
 {
   MOZ_ASSERT(IsInnerWindow());
 
-  if (mPerformance || !mDoc || mCleanedUp) {
-    return;
-  }
-
+  if (mPerformance || !mDoc) {
+    return;
+  }
   RefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
   nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
   bool timingEnabled = false;
   if (!timedChannel ||
       !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
       !timingEnabled) {
     timedChannel = nullptr;
   }
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -2005,16 +2005,18 @@ protected:
   nsCOMPtr<nsIURI> mLastOpenedURI;
 #endif
 
 #ifdef MOZ_B2G
   bool mNetworkUploadObserverEnabled;
   bool mNetworkDownloadObserverEnabled;
 #endif // MOZ_B2G
 
+  bool mCleanedUp;
+
   nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;
 
   using XBLPrototypeHandlerTable = nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>;
   nsAutoPtr<XBLPrototypeHandlerTable> mCachedXBLPrototypeHandlers;
 
   // mSuspendedDoc is only set on outer windows. It's useful when we get matched
   // EnterModalState/LeaveModalState calls, in which case the outer window is
   // responsible for unsuspending events on the document. If we don't (for
--- a/dom/base/nsIMessageManager.idl
+++ b/dom/base/nsIMessageManager.idl
@@ -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/. */
 
 #include "nsISupports.idl"
 
 interface mozIDOMWindowProxy;
 interface nsIDocShell;
 interface nsIContent;
+interface nsIEventTarget;
 interface nsIFrameLoader;
 interface nsIPrincipal;
 
 /**
  * Message managers provide a way for chrome-privileged JS code to
  * communicate with each other, even across process boundaries.
  *
  * Message managers are separated into "parent side" and "child side".
@@ -393,16 +394,22 @@ interface nsIContentFrameMessageManager 
    * The current top level window in the frame or null.
    */
   readonly attribute mozIDOMWindowProxy content;
 
   /**
    * The top level docshell or null.
    */
   readonly attribute nsIDocShell docShell;
+
+  /**
+   * Returns the SchedulerEventTarget corresponding to the TabGroup
+   * for this frame.
+   */
+  readonly attribute nsIEventTarget tabEventTarget;
 };
 
 [uuid(b39a3324-b574-4f85-8cdb-274d04f807ef)]
 interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
 {
   [notxpcom] nsIContent getOwnerContent();
   [notxpcom] void cacheFrameLoader(in nsIFrameLoader aFrameLoader);
 };
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -18,16 +18,17 @@
 #include "nsPropertyTable.h"        // for typedefs
 #include "nsTObserverArray.h"       // for member
 #include "mozilla/ErrorResult.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/EventTarget.h" // for base class
 #include "js/TypeDecls.h"     // for Handle, Value, JSObject, JSContext
 #include "mozilla/dom/DOMString.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "nsTHashtable.h"
 #include <iosfwd>
 
 // Including 'windows.h' will #define GetClassInfo to something else.
 #ifdef XP_WIN
 #ifdef GetClassInfo
 #undef GetClassInfo
 #endif
 #endif
@@ -46,16 +47,17 @@ class nsIMutationObserver;
 class nsINode;
 class nsINodeList;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeSupportsWeakRefTearoff;
 class nsNodeWeakReference;
 class nsDOMMutationObserver;
+class nsRange;
 
 namespace mozilla {
 class EventListenerManager;
 class TextEditor;
 namespace dom {
 /**
  * @return true if aChar is what the WHATWG defines as a 'ascii whitespace'.
  * https://infra.spec.whatwg.org/#ascii-whitespace
@@ -1104,16 +1106,22 @@ public:
 
     /**
      * Weak reference to this node.  This is cleared by the destructor of
      * nsNodeWeakReference.
      */
     nsNodeWeakReference* MOZ_NON_OWNING_REF mWeakReference;
 
     /**
+     * A set of ranges in the common ancestor for the selection to which
+     * this node belongs to.
+     */
+    mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>> mCommonAncestorRanges;
+
+    /**
      * Number of descendant nodes in the uncomposed document that have been
      * explicitly set as editable.
      */
     uint32_t mEditableDescendantCount;
   };
 
   /**
    * Functions for managing flags and slots
@@ -1893,16 +1901,37 @@ public:
                                                 CallerType aCallerType,
                                                 ErrorResult& aRv);
   already_AddRefed<DOMPoint> ConvertPointFromNode(const DOMPointInit& aPoint,
                                                   const TextOrElementOrDocument& aFrom,
                                                   const ConvertCoordinateOptions& aOptions,
                                                   CallerType aCallerType,
                                                   ErrorResult& aRv);
 
+  const nsTHashtable<nsPtrHashKey<nsRange>>* GetExistingCommonAncestorRanges() const
+  {
+    if (!HasSlots()) {
+      return nullptr;
+    }
+    mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>>& ranges =
+      GetExistingSlots()->mCommonAncestorRanges;
+    return ranges.get();
+  }
+
+  nsTHashtable<nsPtrHashKey<nsRange>>* GetExistingCommonAncestorRanges()
+  {
+    nsINode::nsSlots* slots = GetExistingSlots();
+    return slots ? slots->mCommonAncestorRanges.get() : nullptr;
+  }
+
+  mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>>& GetCommonAncestorRangesPtr()
+  {
+    return Slots()->mCommonAncestorRanges;
+  }
+
 protected:
 
   // Override this function to create a custom slots class.
   // Must not return null.
   virtual nsINode::nsSlots* CreateSlots();
 
   bool HasSlots() const
   {
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -194,16 +194,24 @@ nsInProcessTabChildGlobal::GetContent(mo
 
 NS_IMETHODIMP
 nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
 {
   NS_IF_ADDREF(*aDocShell = mDocShell);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsInProcessTabChildGlobal::GetTabEventTarget(nsIEventTarget** aTarget)
+{
+  nsCOMPtr<nsIEventTarget> target = GetMainThreadEventTarget();
+  target.forget(aTarget);
+  return NS_OK;
+}
+
 void
 nsInProcessTabChildGlobal::FireUnloadEvent()
 {
   // We're called from nsDocument::MaybeInitializeFinalizeFrameLoaders, so it
   // should be safe to run script.
   MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
 
   // Don't let the unload event propagate to chrome event handlers.
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -72,16 +72,17 @@ public:
   {
     return mMessageManager
       ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote,
                                         aPrincipal, aCx, aArgc, aRetval)
       : NS_ERROR_NULL_POINTER;
   }
   NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
   NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
+  NS_IMETHOD GetTabEventTarget(nsIEventTarget** aTarget) override;
 
   NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
 
   /**
    * MessageManagerCallback methods that we override.
    */
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                       const nsAString& aMessage,
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2085,20 +2085,25 @@ CCRunnerFired(TimeStamp aDeadline, void*
   if (isLateTimerFire && ShouldTriggerCC(suspected)) {
     if (sCCRunnerFireCount == numEarlyTimerFires + 1) {
       FireForgetSkippable(suspected, true, aDeadline);
       didDoWork = true;
       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
         // Our efforts to avoid a CC have failed, so we return to let the
         // timer fire once more to trigger a CC.
 
-        // Clear content unbinder before the first CC slice.
-        Element::ClearContentUnbinder();
-        // And trigger deferred deletion too.
-        nsCycleCollector_doDeferredDeletion();
+        if (!aDeadline.IsNull() && TimeStamp::Now() < aDeadline) {
+          // Clear content unbinder before the first CC slice.
+          Element::ClearContentUnbinder();
+
+          if (TimeStamp::Now() < aDeadline) {
+            // And trigger deferred deletion too.
+            nsCycleCollector_doDeferredDeletion();
+          }
+        }
         return didDoWork;
       }
     } else {
       // We are in the final timer fire and still meet the conditions for
       // triggering a CC. Let RunCycleCollectorSlice finish the current IGC, if
       // any because that will allow us to include the GC time in the CC pause.
       nsJSContext::RunCycleCollectorSlice(aDeadline);
       didDoWork = true;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -767,18 +767,16 @@ protected:
 
   // The evidence that we have tried to cache mTopInnerWindow only once from
   // SetNewDocument(). Note: We need this extra flag because mTopInnerWindow
   // could be null and we don't want it to be set multiple times.
   bool mHasTriedToCacheTopInnerWindow;
 
   // The number of active IndexedDB databases. Inner window only.
   uint32_t mNumOfIndexedDBDatabases;
-
-  bool mCleanedUp;
 };
 
 #define NS_PIDOMWINDOWINNER_IID \
 { 0x775dabc9, 0x8f43, 0x4277, \
   { 0x9a, 0xdb, 0xf1, 0x99, 0x0d, 0x77, 0xcf, 0xfb } }
 
 #define NS_PIDOMWINDOWOUTER_IID \
   { 0x769693d4, 0xb009, 0x4fe2, \
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -200,18 +200,21 @@ nsRange::IsNodeSelected(nsINode* aNode, 
   NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
                "orphan selection descendant");
 
   // Collect the potential ranges and their selection objects.
   RangeHashTable ancestorSelectionRanges;
   nsTHashtable<nsPtrHashKey<Selection>> ancestorSelections;
   uint32_t maxRangeCount = 0;
   for (; n; n = GetNextRangeCommonAncestor(n->GetParentNode())) {
-    RangeHashTable* ranges =
-      static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
+    nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
+      n->GetExistingCommonAncestorRanges();
+    if (!ranges) {
+      continue;
+    }
     for (auto iter = ranges->ConstIter(); !iter.Done(); iter.Next()) {
       nsRange* range = iter.Get()->GetKey();
       if (range->IsInSelection() && !range->Collapsed()) {
         ancestorSelectionRanges.PutEntry(range);
         Selection* selection = range->mSelection;
         ancestorSelections.PutEntry(selection);
         maxRangeCount = std::max(maxRangeCount, selection->RangeCount());
       }
@@ -403,39 +406,38 @@ static void UnmarkDescendants(nsINode* a
 void
 nsRange::RegisterCommonAncestor(nsINode* aNode)
 {
   NS_PRECONDITION(aNode, "bad arg");
   NS_ASSERTION(IsInSelection(), "registering range not in selection");
 
   MarkDescendants(aNode);
 
-  RangeHashTable* ranges =
-    static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
+  UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>>& ranges =
+    aNode->GetCommonAncestorRangesPtr();
   if (!ranges) {
-    ranges = new RangeHashTable;
-    aNode->SetProperty(nsGkAtoms::range, ranges,
-                       nsINode::DeleteProperty<nsRange::RangeHashTable>, true);
+    ranges = MakeUnique<nsRange::RangeHashTable>();
   }
   ranges->PutEntry(this);
   aNode->SetCommonAncestorForRangeInSelection();
 }
 
 void
 nsRange::UnregisterCommonAncestor(nsINode* aNode)
 {
   NS_PRECONDITION(aNode, "bad arg");
   NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
-  RangeHashTable* ranges =
-    static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
+  nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
+    aNode->GetExistingCommonAncestorRanges();
+  MOZ_ASSERT(ranges);
   NS_ASSERTION(ranges->GetEntry(this), "unknown range");
 
   if (ranges->Count() == 1) {
     aNode->ClearCommonAncestorForRangeInSelection();
-    aNode->DeleteProperty(nsGkAtoms::range);
+    aNode->GetCommonAncestorRangesPtr().reset();
     UnmarkDescendants(aNode);
   } else {
     ranges->RemoveEntry(this);
   }
 }
 
 /******************************************************
  * nsIMutationObserver implementation
@@ -3391,18 +3393,18 @@ nsRange::GetUsedFontFaces(nsIDOMFontFace
 
 nsINode*
 nsRange::GetRegisteredCommonAncestor()
 {
   NS_ASSERTION(IsInSelection(),
                "GetRegisteredCommonAncestor only valid for range in selection");
   nsINode* ancestor = GetNextRangeCommonAncestor(mStartContainer);
   while (ancestor) {
-    RangeHashTable* ranges =
-      static_cast<RangeHashTable*>(ancestor->GetProperty(nsGkAtoms::range));
+    nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
+      ancestor->GetExistingCommonAncestorRanges();
     if (ranges->GetEntry(this)) {
       break;
     }
     ancestor = GetNextRangeCommonAncestor(ancestor->GetParentNode());
   }
   NS_ASSERTION(ancestor, "can't find common ancestor for selected range");
   return ancestor;
 }
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -388,20 +388,20 @@ protected:
   // CharacterDataChanged does the re-registering when needed.
   void DoSetRange(nsINode* aStartN, uint32_t aStartOffset,
                   nsINode* aEndN, uint32_t aEndOffset,
                   nsINode* aRoot, bool aNotInsertedYet = false);
 
   /**
    * For a range for which IsInSelection() is true, return the common
    * ancestor for the range.  This method uses the selection bits and
-   * nsGkAtoms::range property on the nodes to quickly find the ancestor.
-   * That is, it's a faster version of GetCommonAncestor that only works
-   * for ranges in a Selection.  The method will assert and the behavior
-   * is undefined if called on a range where IsInSelection() is false.
+   * node slots to quickly find the ancestor.  That is, it's a faster
+   * version of GetCommonAncestor that only works for ranges in a
+   * Selection.  The method will assert and the behavior is undefined if
+   * called on a range where IsInSelection() is false.
    */
   nsINode* GetRegisteredCommonAncestor();
 
   // Helper to IsNodeSelected.
   static bool IsNodeInSortedRanges(nsINode* aNode,
                                    uint32_t aStartOffset,
                                    uint32_t aEndOffset,
                                    const nsTArray<const nsRange*>& aRanges,
--- a/dom/base/nsTextNode.cpp
+++ b/dom/base/nsTextNode.cpp
@@ -160,19 +160,18 @@ void
 nsTextNode::List(FILE* out, int32_t aIndent) const
 {
   int32_t index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
 
   fprintf(out, "Text@%p", static_cast<const void*>(this));
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   if (IsCommonAncestorForRangeInSelection()) {
-    typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
-    RangeHashTable* ranges =
-      static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range));
+    const nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
+      GetExistingCommonAncestorRanges();
     fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
   }
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
 
   nsAutoString tmp;
   ToCString(tmp, 0, mText.GetLength());
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -583,17 +583,19 @@ skip-if = toolkit == 'android' #bug 6870
 [test_bug922681.html]
 [test_bug927196.html]
 [test_bug962251.html]
 [test_bug976673.html]
 [test_bug982153.html]
 [test_bug999456.html]
 [test_bug1022229.html]
 [test_bug1025933.html]
+skip-if = stylo # bug 1293844
 [test_bug1037687.html]
+skip-if = stylo # bug 1293844
 [test_bug1043106.html]
 [test_bug1057176.html]
 [test_bug1060938.html]
 [test_bug1064481.html]
 [test_bug1070015.html]
 [test_bug1075702.html]
 [test_bug1081686.html]
 skip-if = toolkit == 'android'
--- a/dom/base/test/test_mutationobservers.html
+++ b/dom/base/test/test_mutationobservers.html
@@ -601,16 +601,22 @@ function testExpandos() {
     SpecialPowers.gc();
     SpecialPowers.gc();
     SpecialPowers.gc();
   }
   div.setAttribute("foo", "bar2");
 }
 
 function testOutsideShadowDOM() {
+  if (!div.createShadowRoot) {
+    todo(false, "Skipping testOutsideShadowDOM and testInsideShadowDOM " +
+         "because createShadowRoot is not supported");
+    then(testMarquee);
+    return;
+  }
   var m = new M(function(records, observer) {
     is(records.length, 1);
     is(records[0].type, "attributes", "Should have got attributes");
     observer.disconnect();
     then(testInsideShadowDOM);
   });
   m.observe(div, {
       attributes: true,
--- a/dom/credentialmanagement/Credential.cpp
+++ b/dom/credentialmanagement/Credential.cpp
@@ -41,10 +41,22 @@ Credential::GetId(nsAString& aId) const
 }
 
 void
 Credential::GetType(nsAString& aType) const
 {
   aType.Assign(mType);
 }
 
+void
+Credential::SetId(const nsAString& aId)
+{
+  mId.Assign(aId);
+}
+
+void
+Credential::SetType(const nsAString& aType)
+{
+  mType.Assign(aType);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/credentialmanagement/Credential.h
+++ b/dom/credentialmanagement/Credential.h
@@ -39,16 +39,22 @@ public:
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void
   GetId(nsAString& aId) const;
 
   void
   GetType(nsAString& aType) const;
 
+  void
+  SetId(const nsAString& aId);
+
+  void
+  SetType(const nsAString& aType);
+
 private:
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   nsAutoString mId;
   nsAutoString mType;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/events/ContentEventHandler.h
+++ b/dom/events/ContentEventHandler.h
@@ -161,28 +161,40 @@ public:
       return IsValid() && mNode->IsElement() && !mOffset && !mAfterOpenTag;
     }
     bool IsImmediatelyAfterOpenTag() const
     {
       return IsValid() && mNode->IsElement() && !mOffset && mAfterOpenTag;
     }
     nsresult SetToRangeStart(nsRange* aRange) const
     {
-      nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
-      return aRange->SetStart(domNode, mOffset);
+      if (!IsValid()) {
+        return NS_ERROR_FAILURE;
+      }
+      ErrorResult errorResult;
+      aRange->SetStart(*mNode, mOffset, errorResult);
+      return errorResult.StealNSResult();
     }
     nsresult SetToRangeEnd(nsRange* aRange) const
     {
-      nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
-      return aRange->SetEnd(domNode, mOffset);
+      if (!IsValid()) {
+        return NS_ERROR_FAILURE;
+      }
+      ErrorResult errorResult;
+      aRange->SetEnd(*mNode, mOffset, errorResult);
+      return errorResult.StealNSResult();
     }
     nsresult SetToRangeEndAfter(nsRange* aRange) const
     {
-      nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
-      return aRange->SetEndAfter(domNode);
+      if (!IsValid()) {
+        return NS_ERROR_FAILURE;
+      }
+      ErrorResult errorResult;
+      aRange->SetEndAfter(*mNode, errorResult);
+      return errorResult.StealNSResult();
     }
   };
 
   // NodePositionBefore isn't good name if mNode isn't an element node nor
   // mOffset is not 0, though, when mNode is an element node and mOffset is 0,
   // this is treated as before the open tag of mNode.
   struct NodePositionBefore final : public NodePosition
   {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4103,19 +4103,19 @@ public:
   WidgetMouseEvent* mMouseEvent;
   EventMessage mEventMessage;
 };
 
 void
 EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
                                   nsIContent* aMovingInto)
 {
-  OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
-
-  if (!wrapper->mLastOverElement)
+  RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
+
+  if (!wrapper || !wrapper->mLastOverElement)
     return;
   // Before firing mouseout, check for recursion
   if (wrapper->mLastOverElement == wrapper->mFirstOutEventElement)
     return;
 
   if (wrapper->mLastOverFrame) {
     // if the frame is associated with a subdocument,
     // tell the subdocument that we're moving out of it
@@ -4171,19 +4171,19 @@ EventStateManager::NotifyMouseOut(Widget
 }
 
 void
 EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
                                    nsIContent* aContent)
 {
   NS_ASSERTION(aContent, "Mouse must be over something");
 
-  OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
-
-  if (wrapper->mLastOverElement == aContent)
+  RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
+
+  if (!wrapper || wrapper->mLastOverElement == aContent)
     return;
 
   // Before firing mouseover, check for recursion
   if (aContent == wrapper->mFirstOverEventElement)
     return;
 
   // Check to see if we're a subdocument and if so update the parent
   // document's ESM state to indicate that the mouse is over the
@@ -4343,33 +4343,33 @@ EventStateManager::GenerateMouseEnterExi
       nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
       if (!targetElement) {
         // We're always over the document root, even if we're only
         // over dead space in a page (whose frame is not associated with
         // any content) or in print preview dead space
         targetElement = mDocument->GetRootElement();
       }
       if (targetElement) {
-        OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
+        RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
         if (helper) {
           helper->mLastOverElement = targetElement;
         }
         NotifyMouseOut(aMouseEvent, nullptr);
       }
     }
     break;
   case ePointerLeave:
   case ePointerCancel:
   case eMouseExitFromWidget:
     {
       // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
-      OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
-      if (helper->mLastOverFrame &&
+      RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
+      if (helper && helper->mLastOverFrame &&
           nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
           nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
         // the Mouse/PointerOut event widget doesn't have same top widget with
         // mLastOverFrame, it's a spurious event for mLastOverFrame
         break;
       }
 
       // Reset sLastRefPoint, so that we'll know not to report any
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -529,16 +529,17 @@ IMEStateManager::OnChangeFocusInternal(n
   // process actually gets focus because if user types keys before that they
   // are handled by IME.
   IMEState newState =
     newTabParent ? IMEState(IMEState::DISABLED) :
                    GetNewIMEState(aPresContext, aContent);
   bool setIMEState = true;
 
   if (newTabParent) {
+    MOZ_ASSERT(XRE_IsParentProcess());
     if (aAction.mFocusChange == InputContextAction::MENU_GOT_PSEUDO_FOCUS ||
         aAction.mFocusChange == InputContextAction::MENU_LOST_PSEUDO_FOCUS) {
       // XXX When menu keyboard listener is being uninstalled, IME state needs
       //     to be restored by the child process asynchronously.  Therefore,
       //     some key events which are fired immediately after closing menu
       //     may not be handled by IME.
       Unused << newTabParent->
         SendMenuKeyboardListenerInstalled(sInstalledMenuKeyboardListener);
@@ -554,17 +555,17 @@ IMEStateManager::OnChangeFocusInternal(n
            "and the IME state is already disabled by a remote process"));
       } else {
         MOZ_LOG(sISMLog, LogLevel::Debug,
           ("  OnChangeFocusInternal(), will disable IME "
            "until new focused element (or document) in the child process "
            "will get focus actually"));
       }
     } else if (newWidget->GetInputContext().mOrigin !=
-                 InputContext::ORIGIN_CONTENT) {
+                 InputContext::ORIGIN_MAIN) {
       // When focus is NOT changed actually, we shouldn't set IME state if
       // current input context was set by a remote process since that means
       // that the window is being activated and the child process may have
       // composition.  Then, we shouldn't commit the composition with making
       // IME state disabled.
       setIMEState = false;
       MOZ_LOG(sISMLog, LogLevel::Debug,
         ("  OnChangeFocusInternal(), doesn't set IME "
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -131,21 +131,24 @@ skip-if = (e10s && os == "mac") # bug 12
 [test_bug1003432.html]
 support-files = test_bug1003432.js
 [test_bug1013412.html]
 [test_bug1017086_disable.html]
 support-files = bug1017086_inner.html
 [test_bug1017086_enable.html]
 support-files = bug1017086_inner.html
 [test_bug1079236.html]
+skip-if = stylo # bug 1293844
 [test_bug1145910.html]
+skip-if = stylo # bug 1293844
 [test_bug1150308.html]
+skip-if = stylo # bug 1293844
 [test_bug1248459.html]
 [test_bug1264380.html]
-run-if = (e10s && os != "win") # Bug 1270043, crash at windows platforms; Bug1264380 comment 20, nsDragService::InvokeDragSessionImpl behaves differently among platform implementations in non-e10s mode which prevents us to check the validity of nsIDragService::getCurrentSession() consistently via synthesize mouse clicks in non-e10s mode.
+run-if = (e10s && os != "win" && !stylo) # Bug 1270043, crash at windows platforms; Bug1264380 comment 20, nsDragService::InvokeDragSessionImpl behaves differently among platform implementations in non-e10s mode which prevents us to check the validity of nsIDragService::getCurrentSession() consistently via synthesize mouse clicks in non-e10s mode. bug 1293844 for stylo.
 [test_bug1327798.html]
 subsuite = clipboard
 [test_clickevent_on_input.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_continuous_wheel_events.html]
 [test_dblclick_explicit_original_target.html]
 [test_dom_activate_event.html]
 [test_dom_keyboard_event.html]
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1129,41 +1129,16 @@ ContentParent::RecvConnectPluginBridge(c
   // pointer and just throw it away.
   uint32_t dummy = 0;
   if (!mozilla::plugins::SetupBridge(aPluginId, this, aRv, &dummy, aEndpoint)) {
     return IPC_FAIL(this, "SetupBridge failed");
   }
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-ContentParent::RecvGetBlocklistState(const uint32_t& aPluginId,
-                                     uint32_t* aState)
-{
-  *aState = nsIBlocklistService::STATE_BLOCKED;
-
-  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
-  if (!pluginHost) {
-    NS_WARNING("Plugin host not found");
-    return IPC_FAIL_NO_REASON(this);
-  }
-  nsPluginTag* tag =  pluginHost->PluginWithId(aPluginId);
-
-  if (!tag) {
-    // Default state is blocked anyway
-    NS_WARNING("Plugin tag not found. This should never happen, but to avoid a crash we're forcibly blocking it");
-    return IPC_OK();
-  }
-
-  if (NS_FAILED(tag->GetBlocklistState(aState))) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
 /*static*/ TabParent*
 ContentParent::CreateBrowser(const TabContext& aContext,
                              Element* aFrameElement,
                              ContentParent* aOpenerContentParent,
                              TabParent* aSameTabGroupAs,
                              uint64_t aNextTabParentId)
 {
   AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -299,19 +299,16 @@ public:
                                                  Endpoint<PPluginModuleParent>* aEndpoint) override;
 
   virtual mozilla::ipc::IPCResult RecvMaybeReloadPlugins() override;
 
   virtual mozilla::ipc::IPCResult RecvConnectPluginBridge(const uint32_t& aPluginId,
                                                           nsresult* aRv,
                                                           Endpoint<PPluginModuleParent>* aEndpoint) override;
 
-  virtual mozilla::ipc::IPCResult RecvGetBlocklistState(const uint32_t& aPluginId,
-                                                        uint32_t* aIsBlocklisted) override;
-
   virtual mozilla::ipc::IPCResult RecvUngrabPointer(const uint32_t& aTime) override;
 
   virtual mozilla::ipc::IPCResult RecvRemovePermission(const IPC::Principal& aPrincipal,
                                                        const nsCString& aPermissionType,
                                                        nsresult* aRv) override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -636,21 +636,16 @@ parent:
      * This call is used by asynchronous plugin instantiation to notify the
      * content parent that it is now safe to initiate the plugin bridge for
      * the specified plugin id. The endpoint for the content process part of the
      * bridge is returned.
      */
     sync ConnectPluginBridge(uint32_t aPluginId)
         returns (nsresult rv, Endpoint<PPluginModuleParent> aEndpoint);
 
-    /**
-     * Return the current blocklist state for a particular plugin.
-     */
-    sync GetBlocklistState(uint32_t aPluginId) returns (uint32_t aState);
-
     async PJavaScript();
 
     async PRemoteSpellcheckEngine();
 
     async InitCrashReporter(Shmem shmem, NativeThreadId tid);
 
     /**
      * Is this token compatible with the provided version?
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3515,16 +3515,24 @@ TabChildGlobal::GetDocShell(nsIDocShell*
   *aDocShell = nullptr;
   if (!mTabChild)
     return NS_ERROR_NULL_POINTER;
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mTabChild->WebNavigation());
   docShell.swap(*aDocShell);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TabChildGlobal::GetTabEventTarget(nsIEventTarget** aTarget)
+{
+  nsCOMPtr<nsIEventTarget> target = EventTargetFor(TaskCategory::Other);
+  target.forget(aTarget);
+  return NS_OK;
+}
+
 nsIPrincipal*
 TabChildGlobal::GetPrincipal()
 {
   if (!mTabChild)
     return nullptr;
   return mTabChild->GetPrincipal();
 }
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -109,16 +109,17 @@ public:
   {
     return mMessageManager
       ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote,
                                         aPrincipal, aCx, aArgc, aRetval)
       : NS_ERROR_NULL_POINTER;
   }
   NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
   NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
+  NS_IMETHOD GetTabEventTarget(nsIEventTarget** aTarget) override;
 
   nsresult AddEventListener(const nsAString& aType,
                             nsIDOMEventListener* aListener,
                             bool aUseCapture)
   {
     // By default add listeners only for trusted events!
     return DOMEventTargetHelper::AddEventListener(aType, aListener,
                                                   aUseCapture, false, 2);
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -154,54 +154,50 @@ CanCreateWMFDecoder()
   static Maybe<bool> result;
   if (result.isNothing()) {
     result.emplace(CanCreateMFTDecoder(aGuid));
   }
   return result.value();
 }
 
 static bool
-IsH264DecoderBlacklisted()
+IsWin7H264Decoder4KCapable()
 {
-#ifdef BLACKLIST_CRASHY_H264_DECODERS
   WCHAR systemPath[MAX_PATH + 1];
   if (!ConstructSystem32Path(L"msmpeg2vdec.dll", systemPath, MAX_PATH + 1)) {
-    // Cannot build path -> Assume it's not the blacklisted DLL.
+    // Cannot build path -> Assume it's the old DLL or it's missing.
     return false;
   }
 
   DWORD zero;
   DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero);
   if (infoSize == 0) {
-    // Can't get file info -> Assume we don't have the blacklisted DLL.
+    // Can't get file info -> Assume it's the old DLL or it's missing.
     return false;
   }
   auto infoData = MakeUnique<unsigned char[]>(infoSize);
   VS_FIXEDFILEINFO *vInfo;
   UINT vInfoLen;
   if (GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get()) &&
     VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen))
   {
-    if ((vInfo->dwFileVersionMS == ((12u << 16) | 0u))
-        && ((vInfo->dwFileVersionLS == ((9200u << 16) | 16426u))
-            || (vInfo->dwFileVersionLS == ((9200u << 16) | 17037u)))) {
-      // 12.0.9200.16426 & .17037 are blacklisted on Win64, see bug 1242343.
-      return true;
-    }
+    uint64_t version =
+      uint64_t(vInfo->dwFileVersionMS) << 32 | uint64_t(vInfo->dwFileVersionLS);
+    // 12.0.9200.16426 & later allow for >1920x1088 resolutions.
+    const uint64_t minimum =
+      (uint64_t(12) << 48) | (uint64_t(9200) << 16) | uint64_t(16426);
+    return version >= minimum;
   }
-#endif // BLACKLIST_CRASHY_H264_DECODERS
+  // Can't get file version -> Assume it's the old DLL.
   return false;
 }
 
 /* static */ bool
 WMFDecoderModule::HasH264()
 {
-  if (IsH264DecoderBlacklisted()) {
-    return false;
-  }
   return CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>();
 }
 
 /* static */ bool
 WMFDecoderModule::HasAAC()
 {
   return CanCreateWMFDecoder<CLSID_CMSAACDecMFT>();
 }
@@ -229,24 +225,25 @@ WMFDecoderModule::Supports(const TrackIn
   }
   if (MP4Decoder::IsH264(aTrackInfo.mMimeType)
       && WMFDecoderModule::HasH264()) {
     if (!MediaPrefs::PDMWMFAllowUnsupportedResolutions()) {
       const VideoInfo* videoInfo = aTrackInfo.GetAsVideoInfo();
       MOZ_ASSERT(videoInfo);
       // Check Windows format constraints, based on:
       // https://msdn.microsoft.com/en-us/library/windows/desktop/dd797815(v=vs.85).aspx
-      if (IsWin8OrLater()) {
-        // Windows >7 supports at most 4096x2304.
+      if (IsWin8OrLater() || IsWin7H264Decoder4KCapable()) {
+        // Windows >7, and Win7 with recent-enough decoder, support at most
+        // 4096x2304.
         if (videoInfo->mImage.width > 4096
             || videoInfo->mImage.height > 2304) {
           return false;
         }
       } else {
-        // Windows <=7 supports at most 1920x1088.
+        // Windows <=7 (with original decoder) supports at most 1920x1088.
         if (videoInfo->mImage.width > 1920
             || videoInfo->mImage.height > 1088) {
           return false;
         }
       }
     }
     return true;
   }
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -379,17 +379,21 @@ PaymentRequest::Show(ErrorResult& aRv)
   RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
   if (NS_WARN_IF(!manager)) {
     mState = eClosed;
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   nsresult rv = manager->ShowPayment(mInternalId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    promise->MaybeReject(NS_ERROR_FAILURE);
+    if (rv == NS_ERROR_ABORT) {
+      promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+    } else {
+      promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+    }
     mState = eClosed;
     return promise.forget();
   }
 
   mAcceptPromise = promise;
   mState = eInteractive;
   return promise.forget();
 }
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -485,25 +485,29 @@ PaymentRequestManager::CanMakePayment(co
   IPCPaymentCanMakeActionRequest action(requestId);
 
   return SendRequestPayment(request, action);
 }
 
 nsresult
 PaymentRequestManager::ShowPayment(const nsAString& aRequestId)
 {
+  if (mShowingRequest) {
+    return NS_ERROR_ABORT;
+  }
   RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
   if (!request) {
     return NS_ERROR_FAILURE;
   }
 
   nsAutoString requestId(aRequestId);
   IPCPaymentShowActionRequest action(requestId);
-
-  return SendRequestPayment(request, action);
+  nsresult rv = SendRequestPayment(request, action);
+  mShowingRequest = request;
+  return rv;
 }
 
 nsresult
 PaymentRequestManager::AbortPayment(const nsAString& aRequestId)
 {
   RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
   if (!request) {
     return NS_ERROR_FAILURE;
@@ -588,47 +592,53 @@ PaymentRequestManager::RespondPayment(co
       }
       request->RespondShowPayment(response.isAccepted(),
                                   response.methodName(),
                                   response.data(),
                                   response.payerName(),
                                   response.payerEmail(),
                                   response.payerPhone());
       if (!response.isAccepted()) {
+        MOZ_ASSERT(mShowingRequest == request);
+        mShowingRequest = nullptr;
         mRequestQueue.RemoveElement(request);
         nsresult rv = ReleasePaymentChild(request);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
       const IPCPaymentAbortActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondAbortPayment(response.isSucceeded());
       if (response.isSucceeded()) {
+        MOZ_ASSERT(mShowingRequest == request);
+        mShowingRequest = nullptr;
         mRequestQueue.RemoveElement(request);
         nsresult rv = ReleasePaymentChild(request);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
       const IPCPaymentCompleteActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondComplete();
+      MOZ_ASSERT(mShowingRequest == request);
+      mShowingRequest = nullptr;
       mRequestQueue.RemoveElement(request);
       nsresult rv = ReleasePaymentChild(request);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       break;
     }
     default: {
--- a/dom/payments/PaymentRequestManager.h
+++ b/dom/payments/PaymentRequestManager.h
@@ -74,14 +74,15 @@ private:
 
   nsresult SendRequestPayment(PaymentRequest* aRequest,
                               const IPCPaymentActionRequest& action,
                               bool aReleaseAfterSend = false);
 
   // The container for the created PaymentRequests
   nsTArray<RefPtr<PaymentRequest>> mRequestQueue;
   nsRefPtrHashtable<nsRefPtrHashKey<PaymentRequest>, PaymentRequestChild> mPaymentChildHash;
+  RefPtr<PaymentRequest> mShowingRequest;
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -301,21 +301,56 @@ PaymentRequestService::RequestPayment(ns
     }
     /*
      *  TODO: 1. Check basic card support once the Basic Card Payment spec is
      *           implemented.
      *           https://www.w3.org/TR/payment-method-basic-card/
      *        2. Check third party payment app support by traversing all
      *           registered third party payment apps.
      */
-    case nsIPaymentActionRequest::CANMAKE_ACTION:
+    case nsIPaymentActionRequest::CANMAKE_ACTION: {
+      rv = CallTestingUIAction(requestId, type);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return NS_ERROR_FAILURE;
+      }
+      break;
+    }
     /*
      *  TODO: Launch/inform payment UI here once the UI module is implemented.
      */
-    case nsIPaymentActionRequest::SHOW_ACTION:
+    case nsIPaymentActionRequest::SHOW_ACTION: {
+      if (mShowingRequest) {
+        nsCOMPtr<nsIPaymentShowActionResponse> showResponse =
+          do_CreateInstance(NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID);
+        MOZ_ASSERT(showResponse);
+        rv = showResponse->Init(requestId,
+                                nsIPaymentActionResponse::PAYMENT_REJECTED,
+                                EmptyString(),
+                                EmptyString(),
+                                EmptyString(),
+                                EmptyString(),
+                                EmptyString());
+        nsCOMPtr<nsIPaymentActionResponse> response = do_QueryInterface(showResponse);
+        MOZ_ASSERT(response);
+        rv = RespondPayment(response);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      } else {
+        rv = GetPaymentRequestById(requestId, getter_AddRefs(mShowingRequest));
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return NS_ERROR_FAILURE;
+        }
+        rv = CallTestingUIAction(requestId, type);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return NS_ERROR_FAILURE;
+        }
+      }
+      break;
+    }
     case nsIPaymentActionRequest::ABORT_ACTION:
     case nsIPaymentActionRequest::COMPLETE_ACTION: {
       rv = CallTestingUIAction(requestId, type);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return NS_ERROR_FAILURE;
       }
       break;
     }
@@ -386,21 +421,36 @@ PaymentRequestService::RespondPayment(ns
     case nsIPaymentActionResponse::ABORT_ACTION: {
       nsCOMPtr<nsIPaymentAbortActionResponse> response =
         do_QueryInterface(aResponse);
       MOZ_ASSERT(response);
       bool isSucceeded;
       rv = response->IsSucceeded(&isSucceeded);
       NS_ENSURE_SUCCESS(rv, rv);
       if (isSucceeded) {
+        mShowingRequest = nullptr;
+        mRequestQueue.RemoveElement(request);
+      }
+      break;
+    }
+    case nsIPaymentActionResponse::SHOW_ACTION: {
+      nsCOMPtr<nsIPaymentShowActionResponse> response =
+        do_QueryInterface(aResponse);
+      MOZ_ASSERT(response);
+      bool isAccepted;
+      rv = response->IsAccepted(&isAccepted);
+      NS_ENSURE_SUCCESS(rv, rv);
+      if (!isAccepted) {
+        mShowingRequest = nullptr;
         mRequestQueue.RemoveElement(request);
       }
       break;
     }
     case nsIPaymentActionResponse::COMPLETE_ACTION: {
+      mShowingRequest = nullptr;
       mRequestQueue.RemoveElement(request);
       break;
     }
     default: {
       break;
     }
   }
   return NS_OK;
--- a/dom/payments/PaymentRequestService.h
+++ b/dom/payments/PaymentRequestService.h
@@ -46,14 +46,16 @@ private:
   nsresult
   CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType);
 
   FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
 
   nsInterfaceHashtable<nsStringHashKey, nsIPaymentActionCallback> mCallbackHashtable;
 
   nsCOMPtr<nsIPaymentUIService> mTestingUIService;
+
+  nsCOMPtr<nsIPaymentRequest> mShowingRequest;
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -101,17 +101,17 @@ NS_IMPL_RELEASE_INHERITED(Performance, D
 /* static */ already_AddRefed<Performance>
 Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
                                  nsDOMNavigationTiming* aDOMTiming,
                                  nsITimedChannel* aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<Performance> performance =
-    PerformanceMainThread::Create(aWindow, aDOMTiming, aChannel);
+    new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
   return performance.forget();
 }
 
 /* static */ already_AddRefed<Performance>
 Performance::CreateForWorker(workers::WorkerPrivate* aWorkerPrivate)
 {
   MOZ_ASSERT(aWorkerPrivate);
   aWorkerPrivate->AssertIsOnWorkerThread();
@@ -272,23 +272,28 @@ Performance::RoundTime(double aTime) con
 void
 Performance::Mark(const nsAString& aName, ErrorResult& aRv)
 {
   // We add nothing when 'privacy.resistFingerprinting' is on.
   if (nsContentUtils::ShouldResistFingerprinting()) {
     return;
   }
 
+  // Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
+  if (mUserEntries.Length() >= mResourceTimingBufferSize) {
+    return;
+  }
+
   if (IsPerformanceTimingAttribute(aName)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   RefPtr<PerformanceMark> performanceMark =
-    new PerformanceMark(GetParentObject(), aName, Now());
+    new PerformanceMark(GetAsISupports(), aName, Now());
   InsertUserEntry(performanceMark);
 
   if (profiler_is_active()) {
     profiler_add_marker(
       "UserTiming",
       MakeUnique<UserTimingMarkerPayload>(aName, TimeStamp::Now()));
   }
 }
@@ -334,16 +339,22 @@ Performance::Measure(const nsAString& aN
                      const Optional<nsAString>& aEndMark,
                      ErrorResult& aRv)
 {
   // We add nothing when 'privacy.resistFingerprinting' is on.
   if (nsContentUtils::ShouldResistFingerprinting()) {
     return;
   }
 
+  // Don't add the entry if the buffer is full. XXX should be removed by bug
+  // 1159003.
+  if (mUserEntries.Length() >= mResourceTimingBufferSize) {
+    return;
+  }
+
   DOMHighResTimeStamp startTime;
   DOMHighResTimeStamp endTime;
 
   if (IsPerformanceTimingAttribute(aName)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
@@ -364,17 +375,17 @@ Performance::Measure(const nsAString& aN
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   } else {
     endTime = Now();
   }
 
   RefPtr<PerformanceMeasure> performanceMeasure =
-    new PerformanceMeasure(GetParentObject(), aName, startTime, endTime);
+    new PerformanceMeasure(GetAsISupports(), aName, startTime, endTime);
   InsertUserEntry(performanceMeasure);
 
   if (profiler_is_active()) {
     TimeStamp startTimeStamp = CreationTimeStamp() +
                                TimeDuration::FromMilliseconds(startTime);
     TimeStamp endTimeStamp = CreationTimeStamp() +
                              TimeDuration::FromMilliseconds(endTime);
     profiler_add_marker(
@@ -562,16 +573,10 @@ Performance::IsObserverEnabled(JSContext
 
   RefPtr<PrefEnabledRunnable> runnable =
     new PrefEnabledRunnable(workerPrivate,
                             NS_LITERAL_CSTRING("dom.enable_performance_observer"));
 
   return runnable->Dispatch() && runnable->IsEnabled();
 }
 
-void
-Performance::MemoryPressure()
-{
-  mUserEntries.Clear();
-}
-
 } // dom namespace
 } // mozilla namespace
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -96,36 +96,33 @@ public:
 
   virtual void GetMozMemory(JSContext *aCx,
                             JS::MutableHandle<JSObject*> aObj) = 0;
 
   virtual nsDOMNavigationTiming* GetDOMTiming() const = 0;
 
   virtual nsITimedChannel* GetChannel() const = 0;
 
-  void MemoryPressure();
-
-  // This method is currently called only on the main-thread.
-  virtual void Shutdown() {}
-
 protected:
   Performance();
   explicit Performance(nsPIDOMWindowInner* aWindow);
 
   virtual ~Performance();
 
   virtual void InsertUserEntry(PerformanceEntry* aEntry);
   void InsertResourceEntry(PerformanceEntry* aEntry);
 
   void ClearUserEntries(const Optional<nsAString>& aEntryName,
                         const nsAString& aEntryType);
 
   DOMHighResTimeStamp ResolveTimestampFromName(const nsAString& aName,
                                                ErrorResult& aRv);
 
+  virtual nsISupports* GetAsISupports() = 0;
+
   virtual void DispatchBufferFullEvent() = 0;
 
   virtual TimeStamp CreationTimeStamp() const = 0;
 
   virtual DOMHighResTimeStamp CreationTime() const = 0;
 
   virtual bool IsPerformanceTimingAttribute(const nsAString& aName)
   {
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -2,17 +2,16 @@
 /* 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 "PerformanceMainThread.h"
 #include "PerformanceNavigation.h"
 #include "nsICacheInfoChannel.h"
-#include "nsISupportsPrimitives.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceMainThread)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
                                                 Performance)
@@ -34,50 +33,28 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INH
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_ADDREF_INHERITED(PerformanceMainThread, Performance)
 NS_IMPL_RELEASE_INHERITED(PerformanceMainThread, Performance)
 
 // QueryInterface implementation for PerformanceMainThread
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMainThread)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END_INHERITING(Performance)
 
-already_AddRefed<PerformanceMainThread>
-PerformanceMainThread::Create(nsPIDOMWindowInner* aWindow,
-                              nsDOMNavigationTiming* aDOMTiming,
-                              nsITimedChannel* aChannel)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aWindow, "Parent window object should be provided");
-
-  RefPtr<PerformanceMainThread> performance =
-    new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
-
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (NS_WARN_IF(!obs)) {
-    return nullptr;
-  }
-
-  nsresult rv = obs->AddObserver(performance, "memory-pressure", false);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nullptr;
-  }
-
-  return performance.forget();
-}
-
 PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
                                              nsDOMNavigationTiming* aDOMTiming,
                                              nsITimedChannel* aChannel)
   : Performance(aWindow)
   , mDOMTiming(aDOMTiming)
   , mChannel(aChannel)
-{}
+{
+  MOZ_ASSERT(aWindow, "Parent window object should be provided");
+}
 
 PerformanceMainThread::~PerformanceMainThread()
 {
   mozilla::DropJSObjects(this);
 }
 
 void
 PerformanceMainThread::GetMozMemory(JSContext *aCx,
@@ -355,33 +332,10 @@ PerformanceMainThread::CreationTimeStamp
 }
 
 DOMHighResTimeStamp
 PerformanceMainThread::CreationTime() const
 {
   return GetDOMTiming()->GetNavigationStart();
 }
 
-NS_IMETHODIMP
-PerformanceMainThread::Observe(nsISupports* aSubject, const char* aTopic,
-                               const char16_t* aData)
-{
-  AssertIsOnMainThread();
-
-  if (!strcmp(aTopic, "memory-pressure")) {
-    MemoryPressure();
-    return NS_OK;
-  }
-
-  return NS_OK;
-}
-
-void
-PerformanceMainThread::Shutdown()
-{
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (obs) {
-    obs->RemoveObserver(this, "memory-pressure");
-  }
-}
-
 } // dom namespace
 } // mozilla namespace
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -8,28 +8,26 @@
 #define mozilla_dom_PerformanceMainThread_h
 
 #include "Performance.h"
 
 namespace mozilla {
 namespace dom {
 
 class PerformanceMainThread final : public Performance
-                                  , public nsIObserver
 {
 public:
+  PerformanceMainThread(nsPIDOMWindowInner* aWindow,
+                        nsDOMNavigationTiming* aDOMTiming,
+                        nsITimedChannel* aChannel);
+
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIOBSERVER
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMainThread,
                                                          Performance)
 
-  static already_AddRefed<PerformanceMainThread>
-  Create(nsPIDOMWindowInner* aWindow, nsDOMNavigationTiming* aDOMTiming,
-         nsITimedChannel* aChannel);
-
   virtual PerformanceTiming* Timing() override;
 
   virtual PerformanceNavigation* Navigation() override;
 
   virtual void AddEntry(nsIHttpChannel* channel,
                         nsITimedChannel* timedChannel) override;
 
   TimeStamp CreationTimeStamp() const override;
@@ -44,24 +42,23 @@ public:
     return mDOMTiming;
   }
 
   virtual nsITimedChannel* GetChannel() const override
   {
     return mChannel;
   }
 
-  void Shutdown() override;
+protected:
+  ~PerformanceMainThread();
 
-protected:
-  PerformanceMainThread(nsPIDOMWindowInner* aWindow,
-                        nsDOMNavigationTiming* aDOMTiming,
-                        nsITimedChannel* aChannel);
-
-  ~PerformanceMainThread();
+  nsISupports* GetAsISupports() override
+  {
+    return this;
+  }
 
   void InsertUserEntry(PerformanceEntry* aEntry) override;
 
   bool IsPerformanceTimingAttribute(const nsAString& aName) override;
 
   DOMHighResTimeStamp
   GetPerformanceTimingFromString(const nsAString& aTimingName) override;
 
--- a/dom/performance/PerformanceWorker.h
+++ b/dom/performance/PerformanceWorker.h
@@ -59,16 +59,21 @@ public:
   {
     MOZ_CRASH("This should not be called on workers.");
     return nullptr;
   }
 
 protected:
   ~PerformanceWorker();
 
+  nsISupports* GetAsISupports() override
+  {
+    return nullptr;
+  }
+
   void InsertUserEntry(PerformanceEntry* aEntry) override;
 
   void DispatchBufferFullEvent() override
   {
     MOZ_CRASH("This should not be called on workers.");
   }
 
 private:
--- a/dom/plugins/base/nsPluginsDirWin.cpp
+++ b/dom/plugins/base/nsPluginsDirWin.cpp
@@ -419,14 +419,14 @@ nsresult nsPluginFile::FreePluginInfo(ns
 
   if (info.fFullPath)
     PL_strfree(info.fFullPath);
 
   if (info.fFileName)
     PL_strfree(info.fFileName);
 
   if (info.fVersion)
-    mozilla::SmprintfFree(info.fVersion);
+    free(info.fVersion);
 
   ZeroMemory((void *)&info, sizeof(info));
 
   return NS_OK;
 }
--- a/dom/power/PowerManagerService.cpp
+++ b/dom/power/PowerManagerService.cpp
@@ -28,17 +28,17 @@
 #include <android/log.h>
 extern "C" char* PrintJSStack();
 static void LogFunctionAndJSStack(const char* funcname) {
   char *jsstack = PrintJSStack();
   __android_log_print(ANDROID_LOG_INFO, "PowerManagerService", \
                       "Call to %s. The JS stack is:\n%s\n",
                       funcname,
                       jsstack ? jsstack : "<no JS stack>");
-  JS_smprintf_free(jsstack);
+  js_free(jsstack);
 }
 // bug 839452
 #define LOG_FUNCTION_AND_JS_STACK() \
   LogFunctionAndJSStack(__PRETTY_FUNCTION__);
 #else
 #define LOG_FUNCTION_AND_JS_STACK()
 #endif
 
--- a/dom/tests/mochitest/chrome/chrome.ini
+++ b/dom/tests/mochitest/chrome/chrome.ini
@@ -17,16 +17,17 @@ support-files =
   file_bug1224790-2_nonmodal.xul
   file_subscript_bindings.js
   focus_frameset.html
   focus_window2.xul
   fullscreen.xul
   queryCaretRectUnix.html
   queryCaretRectWin.html
   selectAtPoint.html
+  selectAtPoint-innerframe.html
   sizemode_attribute.xul
   window_activation.xul
   window_callback_wrapping.xul
   window_docshell_swap.xul
   window_focus.xul
   window_focus_docnav.xul
   !/dom/tests/mochitest/general/file_clonewrapper.html
   !/dom/tests/mochitest/general/file_moving_nodeList.html
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/selectAtPoint-innerframe.html
@@ -0,0 +1,6 @@
+<html>
+<body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'>
+<div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div>
+<br/><br/>
+</body>
+</html>">
--- a/dom/tests/mochitest/chrome/selectAtPoint.html
+++ b/dom/tests/mochitest/chrome/selectAtPoint.html
@@ -262,17 +262,17 @@ body {
 </style>
 </head>
 <body id="body" onload="onPageLoad();">
 
 <div id="div1">ttestselection1 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos. Ei munere officiis assentior pro, nibh decore ius at.</div>
 
 <br />
 
-<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
+<iframe id="frame1" src="selectAtPoint-innerframe.html"></iframe>
 
 <br/>
 
 <div id="div2">Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos.</div>
 
 <br />
 
 <span id="measure">t</span>
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -407,17 +407,17 @@ var interfaceNamesInGlobalScope =
     "HTMLBRElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLButtonElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLCanvasElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLCollection",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "HTMLContentElement",
+    {name: "HTMLContentElement", stylo: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLDataElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLDataListElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLDetailsElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "HTMLDialogElement", disabled: true},
@@ -505,17 +505,17 @@ var interfaceNamesInGlobalScope =
     "HTMLProgressElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLQuoteElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLScriptElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLSelectElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "HTMLShadowElement",
+    {name: "HTMLShadowElement", stylo: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLSourceElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLSpanElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLStyleElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLTableCaptionElement",
@@ -835,17 +835,17 @@ var interfaceNamesInGlobalScope =
     "ServiceWorkerContainer",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerRegistration",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "ScopedCredential", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "ScopedCredentialInfo", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "ShadowRoot", // Bogus, but the test harness forces it on.  See bug 1159768.
+    {name: "ShadowRoot", stylo: false}, // Bogus, but the test harness forces it on.  See bug 1159768.
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SharedWorker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SimpleGestureEvent", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SimpleTest", xbl: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SourceBuffer",
@@ -1291,16 +1291,17 @@ function createInterfaceMap(isXBLScope) 
   var version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
   var isNightly = version.endsWith("a1");
   var isRelease = !version.includes("a");
   var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
   var isMac = /Mac OS/.test(navigator.oscpu);
   var isWindows = /Windows/.test(navigator.oscpu);
   var isAndroid = navigator.userAgent.includes("Android");
   var isLinux = /Linux/.test(navigator.oscpu) && !isAndroid;
+  var isStylo = SpecialPowers.DOMWindowUtils.isStyledByServo;
   var isSecureContext = window.isSecureContext;
 
   var interfaceMap = {};
 
   function addInterfaces(interfaces)
   {
     for (var entry of interfaces) {
       if (typeof(entry) === "string") {
@@ -1311,16 +1312,17 @@ function createInterfaceMap(isXBLScope) 
             (entry.nightlyAndroid === !(isAndroid && isNightly) && isAndroid) ||
             (entry.xbl === !isXBLScope) ||
             (entry.desktop === !isDesktop) ||
             (entry.windows === !isWindows) ||
             (entry.releaseNonWindows === !isRelease && !isWindows) ||
             (entry.mac === !isMac) ||
             (entry.linux === !isLinux) ||
             (entry.android === !isAndroid && !entry.nightlyAndroid) ||
+            (entry.stylo === !isStylo) ||
             (entry.release === !isRelease) ||
             (entry.isSecureContext === !isSecureContext) ||
             entry.disabled) {
           interfaceMap[entry.name] = false;
         } else {
           interfaceMap[entry.name] = true;
         }
       }
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -1,55 +1,78 @@
 [DEFAULT]
 support-files =
   inert_style.css
   dummy_page.html
 
 [test_bug900724.html]
 [test_bug1017896.html]
 [test_bug1176757.html]
+skip-if = stylo # bug 1293844
 [test_bug1276240.html]
 [test_content_element.html]
+skip-if = stylo # bug 1293844
 [test_custom_element_adopt_callbacks.html]
 [test_custom_element_callback_innerhtml.html]
 [test_custom_element_clone_callbacks.html]
 [test_custom_element_clone_callbacks_extended.html]
 [test_custom_element_htmlconstructor.html]
 skip-if = os == 'android' # bug 1323645
 support-files =
   htmlconstructor_autonomous_tests.js
   htmlconstructor_builtin_tests.js
 [test_custom_element_import_node_created_callback.html]
 [test_custom_element_in_shadow.html]
+skip-if = stylo # bug 1293844
 [test_custom_element_register_invalid_callbacks.html]
 [test_custom_element_get.html]
 [test_custom_element_when_defined.html]
 [test_nested_content_element.html]
+skip-if = stylo # bug 1293844
 [test_dest_insertion_points.html]
+skip-if = stylo # bug 1293844
 [test_dest_insertion_points_shadow.html]
+skip-if = stylo # bug 1293844
 [test_fallback_dest_insertion_points.html]
+skip-if = stylo # bug 1293844
 [test_detached_style.html]
+skip-if = stylo # bug 1293844
 [test_dynamic_content_element_matching.html]
+skip-if = stylo # bug 1293844
 [test_document_adoptnode.html]
+skip-if = stylo # bug 1293844
 [test_document_importnode.html]
+skip-if = stylo # bug 1293844
 [test_document_register.html]
 [test_document_register_base_queue.html]
 [test_document_register_lifecycle.html]
 [test_document_register_parser.html]
 [test_document_register_stack.html]
 [test_document_shared_registry.html]
 [test_event_dispatch.html]
+skip-if = stylo # bug 1293844
 [test_event_retarget.html]
+skip-if = stylo # bug 1293844
 [test_event_stopping.html]
+skip-if = stylo # bug 1293844
 [test_template.html]
 [test_template_xhtml.html]
 [test_template_custom_elements.html]
 [test_shadowroot.html]
+skip-if = stylo # bug 1293844
 [test_shadowroot_inert_element.html]
+skip-if = stylo # bug 1293844
 [test_shadowroot_host.html]
+skip-if = stylo # bug 1293844
 [test_shadowroot_style.html]
+skip-if = stylo # bug 1293844
 [test_shadowroot_style_multiple_shadow.html]
+skip-if = stylo # bug 1293844
 [test_shadowroot_style_order.html]
+skip-if = stylo # bug 1293844
 [test_shadowroot_youngershadowroot.html]
+skip-if = stylo # bug 1293844
 [test_style_fallback_content.html]
+skip-if = stylo # bug 1293844
 [test_unresolved_pseudo_class.html]
 [test_link_prefetch.html]
-[test_bug1269155.html]
\ No newline at end of file
+[test_bug1269155.html]
+skip-if = stylo # bug 1293844
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -690,16 +690,23 @@ WebAuthnManager::FinishMakeCredential(ns
   nsresult rv = U2FDecomposeRegistrationResponse(regData, pubKeyBuf, keyHandleBuf,
                                                  attestationCertBuf, signatureBuf);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Cancel(rv);
     return;
   }
   MOZ_ASSERT(keyHandleBuf.Length() <= 0xFFFF);
 
+  nsAutoString keyHandleBase64Url;
+  rv = keyHandleBuf.ToJwkBase64(keyHandleBase64Url);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    Cancel(rv);
+    return;
+  }
+
   CryptoBuffer clientDataBuf;
   if (!clientDataBuf.Assign(mClientData.ref())) {
     Cancel(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   CryptoBuffer rpIdHashBuf;
   if (!rpIdHashBuf.Assign(mInfo.ref().RpIdHash())) {
@@ -770,16 +777,18 @@ WebAuthnManager::FinishMakeCredential(ns
   // values returned from the authenticator as well as the clientDataJSON
   // computed earlier.
   RefPtr<AuthenticatorAttestationResponse> attestation =
       new AuthenticatorAttestationResponse(mCurrentParent);
   attestation->SetClientDataJSON(clientDataBuf);
   attestation->SetAttestationObject(attObj);
 
   RefPtr<PublicKeyCredential> credential = new PublicKeyCredential(mCurrentParent);
+  credential->SetId(keyHandleBase64Url);
+  credential->SetType(NS_LITERAL_STRING("public-key"));
   credential->SetRawId(keyHandleBuf);
   credential->SetResponse(attestation);
 
   mTransactionPromise->MaybeResolve(credential);
   MaybeClearTransaction();
 }
 
 void
@@ -812,16 +821,23 @@ WebAuthnManager::FinishGetAssertion(nsTA
                                              signatureData);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Cancel(rv);
     return;
   }
 
   CryptoBuffer credentialBuf;
   if (!credentialBuf.Assign(aCredentialId)) {
+    Cancel(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  nsAutoString credentialBase64Url;
+  rv = credentialBuf.ToJwkBase64(credentialBase64Url);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     Cancel(rv);
     return;
   }
 
   // If any authenticator returns success:
 
   // Create a new PublicKeyCredential object named value and populate its fields
   // with the values returned from the authenticator as well as the
@@ -829,16 +845,18 @@ WebAuthnManager::FinishGetAssertion(nsTA
   RefPtr<AuthenticatorAssertionResponse> assertion =
     new AuthenticatorAssertionResponse(mCurrentParent);
   assertion->SetClientDataJSON(clientDataBuf);
   assertion->SetAuthenticatorData(authenticatorDataBuf);
   assertion->SetSignature(signatureData);
 
   RefPtr<PublicKeyCredential> credential =
     new PublicKeyCredential(mCurrentParent);
+  credential->SetId(credentialBase64Url);
+  credential->SetType(NS_LITERAL_STRING("public-key"));
   credential->SetRawId(credentialBuf);
   credential->SetResponse(assertion);
 
   mTransactionPromise->MaybeResolve(credential);
   MaybeClearTransaction();
 }
 
 void
--- a/dom/webauthn/tests/test_webauthn_loopback.html
+++ b/dom/webauthn/tests/test_webauthn_loopback.html
@@ -38,23 +38,28 @@ function() {
   let gAssertionChallenge = new Uint8Array(16);
   window.crypto.getRandomValues(gAssertionChallenge);
 
   testMakeCredential();
 
   function decodeCreatedCredential(aCredInfo) {
     /* PublicKeyCredential : Credential
        - rawId: Key Handle buffer pulled from U2F Register() Response
+       - id: Key Handle buffer in base64url form, should == rawId
+       - type: Literal 'public-key'
        - response : AuthenticatorAttestationResponse : AuthenticatorResponse
          - attestationObject: CBOR object
          - clientDataJSON: serialized JSON
        - clientExtensionResults: (not yet supported)
     */
 
+    is(aCredInfo.type, "public-key", "Credential type must be public-key")
+
     ok(aCredInfo.rawId.length > 0, "Key ID exists");
+    is(aCredInfo.id, bytesToBase64UrlSafe(aCredInfo.rawId), "Encoded Key ID and Raw Key ID match");
 
     let clientData = JSON.parse(buffer2string(aCredInfo.response.clientDataJSON));
     is(clientData.challenge, bytesToBase64UrlSafe(gCredentialChallenge), "Challenge is correct");
     is(clientData.origin, window.location.origin, "Origin is correct");
     is(clientData.hashAlg, "S256", "Hash algorithm is correct");
 
     return webAuthnDecodeAttestation(aCredInfo.response.attestationObject.buffer)
     .then(function(decodedResult) {
@@ -63,23 +68,28 @@ function() {
       aCredInfo.attestationObject = decodedResult.attestationObject;
       return aCredInfo;
     });
   }
 
   function checkAssertionAndSigValid(aPublicKey, aAssertion) {
     /* PublicKeyCredential : Credential
        - rawId: ID of Credential from AllowList that succeeded
+       - id: Key Handle buffer in base64url form, should == rawId
+       - type: Literal 'public-key'
        - response : AuthenticatorAssertionResponse : AuthenticatorResponse
          - clientDataJSON: serialized JSON
          - authenticatorData: RP ID Hash || U2F Sign() Response
          - signature: U2F Sign() Response
     */
 
+    is(aAssertion.type, "public-key", "Credential type must be public-key")
+
     ok(aAssertion.rawId.length > 0, "Key ID exists");
+    is(aAssertion.id, bytesToBase64UrlSafe(aAssertion.rawId), "Encoded Key ID and Raw Key ID match");
 
     ok(aAssertion.response.authenticatorData.length > 0, "Authenticator data exists");
     let clientData = JSON.parse(buffer2string(aAssertion.response.clientDataJSON));
     is(clientData.challenge, bytesToBase64UrlSafe(gAssertionChallenge), "Challenge is correct");
     is(clientData.origin, window.location.origin, "Origin is correct");
     is(clientData.hashAlg, "S256", "Hash algorithm is correct");
 
     // Parse the signature data
--- a/dom/webidl/WebAuthentication.webidl
+++ b/dom/webidl/WebAuthentication.webidl
@@ -6,30 +6,30 @@
  * The origin of this IDL file is
  * https://www.w3.org/TR/webauthn/
  */
 
 /***** Interfaces to Data *****/
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface PublicKeyCredential : Credential {
-    readonly attribute ArrayBuffer           rawId;
-    readonly attribute AuthenticatorResponse response;
+    [SameObject] readonly attribute ArrayBuffer           rawId;
+    [SameObject] readonly attribute AuthenticatorResponse response;
     // Extensions are not supported yet.
-    // readonly attribute AuthenticationExtensions clientExtensionResults;
+    // [SameObject] readonly attribute AuthenticationExtensions clientExtensionResults;
 };
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface AuthenticatorResponse {
-    readonly attribute ArrayBuffer clientDataJSON;
+    [SameObject] readonly attribute ArrayBuffer clientDataJSON;
 };
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface AuthenticatorAttestationResponse : AuthenticatorResponse {
-    readonly attribute ArrayBuffer attestationObject;
+    [SameObject] readonly attribute ArrayBuffer attestationObject;
 };
 
 dictionary PublicKeyCredentialParameters {
     required PublicKeyCredentialType  type;
     required WebAuthnAlgorithmID algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
 };
 
 dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
@@ -94,18 +94,18 @@ dictionary PublicKeyCredentialDescriptor
     required BufferSource id;
     sequence<WebAuthnTransport>   transports;
 };
 
 typedef (boolean or DOMString) WebAuthnAlgorithmID; // Fix when upstream there's a definition of how to serialize AlgorithmIdentifier
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface AuthenticatorAssertionResponse : AuthenticatorResponse {
-    readonly attribute ArrayBuffer      authenticatorData;
-    readonly attribute ArrayBuffer      signature;
+    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
+    [SameObject] readonly attribute ArrayBuffer      signature;
 };
 
 // Renamed from "Transport" to avoid a collision with U2F
 enum WebAuthnTransport {
     "usb",
     "nfc",
     "ble"
 };
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -6770,33 +6770,24 @@ WorkerPrivate::CycleCollectInternal(bool
   }
 }
 
 void
 WorkerPrivate::MemoryPressureInternal()
 {
   AssertIsOnWorkerThread();
 
-  if (mScope) {
-    RefPtr<Console> console = mScope->GetConsoleIfExists();
-    if (console) {
-      console->ClearStorage();
-    }
-
-    RefPtr<Performance> performance = mScope->GetPerformanceIfExists();
-    if (performance) {
-      performance->MemoryPressure();
-    }
-  }
-
-  if (mDebuggerScope) {
-    RefPtr<Console> console = mDebuggerScope->GetConsoleIfExists();
-    if (console) {
-      console->ClearStorage();
-    }
+  RefPtr<Console> console = mScope ? mScope->GetConsoleIfExists() : nullptr;
+  if (console) {
+    console->ClearStorage();
+  }
+
+  console = mDebuggerScope ? mDebuggerScope->GetConsoleIfExists() : nullptr;
+  if (console) {
+    console->ClearStorage();
   }
 
   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
     mChildWorkers[index]->MemoryPressure(false);
   }
 }
 
 void
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -151,21 +151,16 @@ public:
   IMPL_EVENT_HANDLER(online)
   IMPL_EVENT_HANDLER(offline)
 
   void
   Dump(const Optional<nsAString>& aString) const;
 
   Performance* GetPerformance();
 
-  Performance* GetPerformanceIfExists() const
-  {
-    return mPerformance;
-  }
-
   already_AddRefed<Promise>
   Fetch(const RequestOrUSVString& aInput, const RequestInit& aInit,
         CallerType aCallerType, ErrorResult& aRv);
 
   already_AddRefed<IDBFactory>
   GetIndexedDB(ErrorResult& aErrorResult);
 
   already_AddRefed<cache::CacheStorage>
--- a/gfx/config/gfxVars.h
+++ b/gfx/config/gfxVars.h
@@ -34,16 +34,17 @@ class gfxVarReceiver;
   _(PDMWMFDisableD3D11Dlls,     nsCString,        nsCString())          \
   _(PDMWMFDisableD3D9Dlls,      nsCString,        nsCString())          \
   _(DXInterop2Blocked,          bool,             false)                \
   _(UseWebRender,               bool,             false)                \
   _(UseWebRenderANGLE,          bool,             false)                \
   _(ScreenDepth,                int32_t,          0)                    \
   _(GREDirectory,               nsCString,        nsCString())          \
   _(UseOMTP,                    bool,             false)                \
+  _(AllowD3D11KeyedMutex,       bool,             false)                \
 
   /* Add new entries above this line. */
 
 // Some graphics settings are computed on the UI process and must be
 // communicated to content and GPU processes. gfxVars helps facilitate
 // this. Its function is similar to gfxPrefs, except rather than hold
 // user preferences, it holds dynamically computed values.
 //
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1100,16 +1100,23 @@ CompositorD3D11::NormalDrawingDone()
 void
 CompositorD3D11::EndFrame()
 {
   if (!mDefaultRT) {
     Compositor::EndFrame();
     return;
   }
 
+  if (XRE_IsParentProcess() && mDevice->GetDeviceRemovedReason() != S_OK) {
+    gfxCriticalNote << "GFX: D3D11 skip EndFrame with device-removed.";
+    Compositor::EndFrame();
+    mCurrentRT = nullptr;
+    return;
+  }
+
   LayoutDeviceIntSize oldSize = mSize;
   EnsureSize();
   if (mSize.width <= 0 || mSize.height <= 0) {
     Compositor::EndFrame();
     return;
   }
 
   RefPtr<ID3D11Query> query;
--- a/gfx/layers/d3d11/MLGDeviceD3D11.cpp
+++ b/gfx/layers/d3d11/MLGDeviceD3D11.cpp
@@ -1646,47 +1646,47 @@ MLGDeviceD3D11::DrawInstanced(uint32_t a
                               uint32_t aVertexOffset, uint32_t aInstanceOffset)
 {
   mCtx->DrawInstanced(aVertexCountPerInstance, aInstanceCount, aVertexOffset, aInstanceOffset);
 }
 
 void
 MLGDeviceD3D11::SetPSTextures(uint32_t aSlot, uint32_t aNumTextures, TextureSource* const* aTextures)
 {
-  StackArray<ID3D11ShaderResourceView*, 2> textures(aNumTextures);
+  // TextureSource guarantees that the ID3D11ShaderResourceView will be cached,
+  // so we don't hold a RefPtr here.
+  StackArray<ID3D11ShaderResourceView*, 3> views(aNumTextures);
 
   for (size_t i = 0; i < aNumTextures; i++) {
-    if (!aTextures[i]) {
-      gfxWarning() << "Null TextureRef in SetPSTextures";
-      continue;
+    views[i] = ResolveTextureSourceForShader(aTextures[i]);
+  }
+
+  mCtx->PSSetShaderResources(aSlot, aNumTextures, views.data());
+}
+
+ID3D11ShaderResourceView*
+MLGDeviceD3D11::ResolveTextureSourceForShader(TextureSource* aTexture)
+{
+  if (!aTexture) {
+    return nullptr;
+  }
+
+  if (TextureSourceD3D11* source = aTexture->AsSourceD3D11()) {
+    ID3D11Texture2D* texture = source->GetD3D11Texture();
+    if (!texture) {
+      gfxWarning() << "No D3D11 texture present in SetPSTextures";
+      return nullptr;
     }
 
-    ID3D11ShaderResourceView* view = nullptr;
-    if (TextureSourceD3D11* source = aTextures[i]->AsSourceD3D11()) {
-      ID3D11Texture2D* texture = source->GetD3D11Texture();
-      if (!texture) {
-        gfxWarning() << "No D3D11 texture present in SetPSTextures";
-        continue;
-      }
-      MaybeLockTexture(texture);
-
-      view = source->GetShaderResourceView();
-    } else {
-      gfxWarning() << "Unknown texture type in SetPSTextures";
-      continue;
-    }
-
-    if (!view) {
-      gfxWarning() << "Failed to get shader resource view for texture";
-      continue;
-    }
-    textures[i] = view;
+    MaybeLockTexture(texture);
+    return source->GetShaderResourceView();
   }
 
-  mCtx->PSSetShaderResources(aSlot, aNumTextures, textures.data());
+  gfxWarning() << "Unknown texture type in SetPSTextures";
+  return nullptr;
 }
 
 void
 MLGDeviceD3D11::SetPSTexture(uint32_t aSlot, MLGTexture* aTexture)
 {
   RefPtr<ID3D11ShaderResourceView> view;
   if (aTexture) {
     MLGTextureD3D11* texture = aTexture->AsD3D11();
--- a/gfx/layers/d3d11/MLGDeviceD3D11.h
+++ b/gfx/layers/d3d11/MLGDeviceD3D11.h
@@ -272,16 +272,20 @@ private:
   bool InitSamplerStates();
   bool InitBlendStates();
   bool InitDepthStencilState();
   bool VerifyConstantBufferOffsetting() override;
 
   void SetInputLayout(ID3D11InputLayout* aLayout);
   void SetVertexShader(ID3D11VertexShader* aShader);
 
+  // Resolve a TextureSource to an ID3D11ShaderResourceView, locking the
+  // texture if needed. The lock is released at the end of the frame.
+  ID3D11ShaderResourceView* ResolveTextureSourceForShader(TextureSource* aSource);
+
 private:
   RefPtr<ID3D11Device> mDevice;
   RefPtr<ID3D11DeviceContext> mCtx;
   RefPtr<ID3D11DeviceContext1> mCtx1;
   UniquePtr<DiagnosticsD3D11> mDiagnostics;
 
   typedef EnumeratedArray<PixelShaderID, PixelShaderID::MaxShaders, RefPtr<ID3D11PixelShader>> PixelShaderArray;
   typedef EnumeratedArray<VertexShaderID, VertexShaderID::MaxShaders, RefPtr<ID3D11VertexShader>> VertexShaderArray;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1657,17 +1657,17 @@ CompositorBridgeParent::RecvAdoptChild(c
       sIndirectLayerTrees[child].mWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
                                                             mWrBridge->GetWebRenderAPI(),
                                                             mWrBridge->CompositableHolder(),
                                                             GetAnimationStorage());
       // Pretend we composited, since parent CompositorBridgeParent was replaced.
       CrossProcessCompositorBridgeParent* cpcp = sIndirectLayerTrees[child].mCrossProcessParent;
       if (cpcp) {
         TimeStamp now = TimeStamp::Now();
-        cpcp->DidComposite(child, now, now);
+        cpcp->DidCompositeLocked(child, now, now);
       }
     }
     parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
   }
 
   if (mApzcTreeManager && parent) {
     parent->ChildAdopted(mApzcTreeManager);
   }
@@ -2000,17 +2000,17 @@ CompositorBridgeParent::NotifyDidComposi
       Unused << ImageBridgeParent::NotifyImageComposites(notifications);
     }
   }
 
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
     if (lts->mCrossProcessParent && lts->mParent == this) {
       CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
-      cpcp->DidComposite(aLayersId, aCompositeStart, aCompositeEnd);
+      cpcp->DidCompositeLocked(aLayersId, aCompositeStart, aCompositeEnd);
     }
   });
 }
 
 void
 CompositorBridgeParent::InvalidateRemoteLayers()
 {
   MOZ_ASSERT(CompositorLoop() == MessageLoop::current());
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -357,16 +357,26 @@ CrossProcessCompositorBridgeParent::Shad
 }
 
 void
 CrossProcessCompositorBridgeParent::DidComposite(
   uint64_t aId,
   TimeStamp& aCompositeStart,
   TimeStamp& aCompositeEnd)
 {
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  DidCompositeLocked(aId, aCompositeStart, aCompositeEnd);
+}
+
+void
+CrossProcessCompositorBridgeParent::DidCompositeLocked(
+  uint64_t aId,
+  TimeStamp& aCompositeStart,
+  TimeStamp& aCompositeEnd)
+{
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
     uint64_t transactionId = layerTree->GetPendingTransactionId();
     if (transactionId) {
       Unused << SendDidComposite(aId, transactionId, aCompositeStart, aCompositeEnd);
       layerTree->SetPendingTransactionId(0);
     }
   } else if (WebRenderBridgeParent* wrbridge = sIndirectLayerTrees[aId].mWrBridge) {
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -102,16 +102,22 @@ public:
                               APZTestData* aOutData) override;
   virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId,
                                       const uint64_t& aInputBlockId,
                                       const nsTArray<ScrollableLayerGuid>& aTargets) override;
 
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
   virtual mozilla::ipc::IPCResult RecvRemotePluginsReady()  override { return IPC_FAIL_NO_REASON(this); }
 
+  // Use DidCompositeLocked if you already hold a lock on
+  // sIndirectLayerTreesLock; Otherwise use DidComposite, which would request
+  // the lock automatically.
+  void DidCompositeLocked(uint64_t aId,
+                                  TimeStamp& aCompositeStart,
+                                  TimeStamp& aCompositeEnd);
   virtual void DidComposite(uint64_t aId,
                             TimeStamp& aCompositeStart,
                             TimeStamp& aCompositeEnd) override;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const LayersBackend& aLayersBackend,
                                               const TextureFlags& aFlags,
                                               const uint64_t& aId,
--- a/gfx/thebes/DeviceManagerDx.cpp
+++ b/gfx/thebes/DeviceManagerDx.cpp
@@ -10,16 +10,17 @@
 #include "gfxPrefs.h"
 #include "gfxWindowsPlatform.h"
 #include "mozilla/D3DMessageUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/gfx/GPUParent.h"
 #include "mozilla/gfx/GraphicsMessages.h"
 #include "mozilla/gfx/Logging.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
 #include "mozilla/layers/MLGDeviceD3D11.h"
 #include "mozilla/layers/PaintThread.h"
 #include "nsIGfxInfo.h"
 #include "nsString.h"
 #include <d3d11.h>
@@ -939,22 +940,18 @@ DeviceManagerDx::TextureSharingWorks()
   }
   return mDeviceStatus->textureSharingWorks();
 }
 
 bool
 DeviceManagerDx::CanInitializeKeyedMutexTextures()
 {
   MutexAutoLock lock(mDeviceLock);
-  if (!mDeviceStatus) {
-    return false;
-  }
-  // Disable this on all Intel devices because of crashes.
-  // See bug 1292923.
-  return (mDeviceStatus->adapter().VendorId != 0x8086 || gfxPrefs::Direct3D11AllowIntelMutex());
+  return mDeviceStatus && gfxPrefs::Direct3D11AllowKeyedMutex() &&
+         gfxVars::AllowD3D11KeyedMutex();
 }
 
 bool
 DeviceManagerDx::HasCrashyInitData()
 {
   MutexAutoLock lock(mDeviceLock);
   if (!mDeviceStatus) {
     return false;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2280,27 +2280,38 @@ gfxPlatform::InitAcceleration()
   // If this is called for the first time on a non-main thread, we're screwed.
   // At the moment there's no explicit guarantee that the main thread calls
   // this before the compositor thread, but let's at least make the assumption
   // explicit.
   MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
 
   gfxPrefs::GetSingleton();
 
+  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+  nsCString discardFailureId;
+  int32_t status;
+
   if (XRE_IsParentProcess()) {
     gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
     gfxVars::SetOffscreenFormat(GetOffscreenFormat());
     gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
               RequiresAcceleratedGLContextForCompositorOGL());
+#ifdef XP_WIN
+    if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
+                                               discardFailureId, &status))) {
+      gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK);
+    } else {
+      // If we couldn't properly evaluate the status, err on the side
+      // of caution and give this functionality to the user.
+      gfxCriticalNote << "Cannot evaluate keyed mutex feature status";
+      gfxVars::SetAllowD3D11KeyedMutex(true);
+    }
+#endif
   }
 
-  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-  nsCString discardFailureId;
-  int32_t status;
-
   if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
 #ifdef XP_WIN
     Preferences::GetBool("media.windows-media-foundation.use-dxva", true) &&
 #endif
       NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
                                                discardFailureId, &status))) {
       if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) {
         sLayersSupportsHardwareVideoDecoding = true;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -432,17 +432,17 @@ private:
   DECL_GFX_PREF(Once, "gfx.content.skia-font-cache-size",      SkiaContentFontCacheSize, int32_t, 10);
 
   DECL_GFX_PREF(Once, "gfx.device-reset.limit",                DeviceResetLimitCount, int32_t, 10);
   DECL_GFX_PREF(Once, "gfx.device-reset.threshold-ms",         DeviceResetThresholdMilliseconds, int32_t, -1);
 
   DECL_GFX_PREF(Once, "gfx.direct2d.disabled",                 Direct2DDisabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled",            Direct2DForceEnabled, bool, false);
   DECL_GFX_PREF(Live, "gfx.direct3d11.reuse-decoder-device",   Direct3D11ReuseDecoderDevice, int32_t, -1);
-  DECL_GFX_PREF(Live, "gfx.direct3d11.allow-intel-mutex",      Direct3D11AllowIntelMutex, bool, true);
+  DECL_GFX_PREF(Live, "gfx.direct3d11.allow-keyed-mutex",      Direct3D11AllowKeyedMutex, bool, true);
   DECL_GFX_PREF(Live, "gfx.direct3d11.use-double-buffering",   Direct3D11UseDoubleBuffering, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.enable-debug-layer",     Direct3D11EnableDebugLayer, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.break-on-error",         Direct3D11BreakOnError, bool, false);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_variation_tables", KeepVariationTables, bool, false);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.otl_validation", ValidateOTLTables, bool, true);
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
   DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll",      HidePluginsForScroll, bool, true);
   DECL_GFX_PREF(Live, "gfx.layerscope.enabled",                LayerScopeEnabled, bool, false);
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -64,17 +64,19 @@ imgRequest::imgRequest(imgLoader* aLoade
  , mMutex("imgRequest")
  , mProgressTracker(new ProgressTracker())
  , mIsMultiPartChannel(false)
  , mGotData(false)
  , mIsInCache(false)
  , mDecodeRequested(false)
  , mNewPartPending(false)
  , mHadInsecureRedirect(false)
-{ }
+{
+  LOG_FUNC(gImgLog, "imgRequest::imgRequest()");
+}
 
 imgRequest::~imgRequest()
 {
   if (mLoader) {
     mLoader->RemoveFromUncachedImages(this);
   }
   if (mURI) {
     nsAutoCString spec;
--- a/image/imgRequestProxy.cpp
+++ b/image/imgRequestProxy.cpp
@@ -117,17 +117,17 @@ imgRequestProxy::imgRequestProxy() :
   mIsInLoadGroup(false),
   mListenerIsStrongRef(false),
   mDecodeRequested(false),
   mDeferNotifications(false),
   mHadListener(false),
   mHadDispatch(false)
 {
   /* member initializers and constructor code */
-
+  LOG_FUNC(gImgLog, "imgRequestProxy::imgRequestProxy");
 }
 
 imgRequestProxy::~imgRequestProxy()
 {
   /* destructor code */
   NS_PRECONDITION(!mListener,
                   "Someone forgot to properly cancel this request!");
 
@@ -164,16 +164,18 @@ imgRequestProxy::~imgRequestProxy()
     /* Call RemoveProxy with a successful status.  This will keep the
        channel, if still downloading data, from being canceled if 'this' is
        the last observer.  This allows the image to continue to download and
        be cached even if no one is using it currently.
     */
     mCanceled = true;
     GetOwner()->RemoveProxy(this, NS_OK);
   }
+
+  LOG_FUNC(gImgLog, "imgRequestProxy::~imgRequestProxy");
 }
 
 nsresult
 imgRequestProxy::Init(imgRequest* aOwner,
                       nsILoadGroup* aLoadGroup,
                       nsIDocument* aLoadingDocument,
                       ImageURL* aURI,
                       imgINotificationObserver* aObserver)
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -163,16 +163,21 @@ MessageLoop::EventTarget::DelayedDispatc
 
 //------------------------------------------------------------------------------
 
 // static
 MessageLoop* MessageLoop::current() {
   return get_tls_ptr().Get();
 }
 
+// static
+void MessageLoop::set_current(MessageLoop* loop) {
+  get_tls_ptr().Set(loop);
+}
+
 static mozilla::Atomic<int32_t> message_loop_id_seq(0);
 
 MessageLoop::MessageLoop(Type type, nsIThread* aThread)
     : type_(type),
       id_(++message_loop_id_seq),
       nestable_tasks_allowed_(true),
       exception_restoration_(false),
       state_(NULL),
@@ -379,17 +384,17 @@ void MessageLoop::PostTask_Helper(alread
   }
 
   // Tasks should only be queued before or during the Run loop, not after.
   MOZ_ASSERT(!shutting_down_);
 
 #ifdef MOZ_TASK_TRACER
   nsCOMPtr<nsIRunnable> tracedTask = task;
   if (mozilla::tasktracer::IsStartLogging()) {
-    tracedTask = mozilla::tasktracer::CreateTracedRunnable(Move(task));
+    tracedTask = mozilla::tasktracer::CreateTracedRunnable(tracedTask.forget());
     (static_cast<mozilla::tasktracer::TracedRunnable*>(tracedTask.get()))->DispatchTask();
   }
   PendingTask pending_task(tracedTask.forget(), true);
 #else
   PendingTask pending_task(Move(task), true);
 #endif
 
   if (delay_ms > 0) {
--- a/ipc/chromium/src/base/message_loop.h
+++ b/ipc/chromium/src/base/message_loop.h
@@ -214,16 +214,18 @@ public:
     DCHECK(thread_name_.empty()) << "Should not rename this thread!";
     thread_name_ = aThreadName;
   }
   const std::string& thread_name() const { return thread_name_; }
 
   // Returns the MessageLoop object for the current thread, or null if none.
   static MessageLoop* current();
 
+  static void set_current(MessageLoop* loop);
+
   // Enables or disables the recursive task processing. This happens in the case
   // of recursive message loops. Some unwanted message loop may occurs when
   // using common controls or printer functions. By default, recursive task
   // processing is disabled.
   //
   // The specific case where tasks get queued is:
   // - The thread is running a message loop.
   // - It receives a task #1 and execute it.
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -12,28 +12,24 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/string16.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/BufferList.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/TimeStamp.h"
-
 #ifdef FUZZING
 #include "base/singleton.h"
 #include "mozilla/ipc/Faulty.h"
 #endif
-
-#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
+#if (!defined(RELEASE_OR_BETA) && !defined(FUZZING)) || defined(DEBUG)
 #define MOZ_PICKLE_SENTINEL_CHECKING
 #endif
-
 class Pickle;
-
 class PickleIterator {
 public:
   explicit PickleIterator(const Pickle& pickle);
 
 private:
   friend class Pickle;
 
   mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_;
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -530,16 +530,18 @@ GeckoChildProcessHost::SetChildLogName(c
   // for the time we launch the sub-process.  It's copied to the new
   // environment.
   PR_SetEnv(buffer.BeginReading());
 }
 
 bool
 GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
 {
+  AutoSetProfilerEnvVarsForChildProcess profilerEnvironment;
+
   // If NSPR log files are not requested, we're done.
   const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
   const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
   if (!origNSPRLogName && !origMozLogName) {
     return PerformAsyncLaunchInternal(aExtraOpts, arch);
   }
 
   // - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
--- a/ipc/glue/MessageLink.cpp
+++ b/ipc/glue/MessageLink.cpp
@@ -67,16 +67,18 @@ ProcessLink::~ProcessLink()
     mIOLoop = nullptr;
     mExistingListener = nullptr;
 #endif
 }
 
 void
 ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Side aSide)
 {
+    mChan->AssertWorkerThread();
+
     NS_PRECONDITION(aTransport, "need transport layer");
 
     // FIXME need to check for valid channel
 
     mTransport = aTransport;
 
     // FIXME figure out whether we're in parent or child, grab IO loop
     // appropriately
@@ -125,18 +127,22 @@ ProcessLink::Open(mozilla::ipc::Transpor
             // over the channel from the previous listener and process
             // any queued messages.
             mIOLoop->PostTask(NewNonOwningRunnableMethod(
               "ipc::ProcessLink::OnTakeConnectedChannel",
               this,
               &ProcessLink::OnTakeConnectedChannel));
         }
 
-        // Should not wait here if something goes wrong with the channel.
-        while (!mChan->Connected() && mChan->mChannelState != ChannelError) {
+        // Wait until one of the runnables above changes the state of the
+        // channel. Note that the state could be changed again after that (to
+        // ChannelClosing, for example, by the IO thread). We can rely on it not
+        // changing back to Closed: only the worker thread changes it to closed,
+        // and we're on the worker thread, blocked.
+        while (mChan->mChannelState == ChannelClosed) {
             mChan->mMonitor->Wait();
         }
     }
 }
 
 void
 ProcessLink::EchoMessage(Message *msg)
 {
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -132,17 +132,19 @@ description =
 [PTestLatency::Rpc]
 description =
 [PTestLatency::Synchro]
 description =
 [PTestLatency::Synchro2]
 description =
 [PTestNestedLoops::R]
 description =
-[PTestPriority::Msg2]
+[PTestPriority::PMsg2]
+description =
+[PTestPriority::PMsg4]
 description =
 [PTestRPC::Test1_Start]
 description =
 [PTestRPC::Test1_InnerEvent]
 description =
 [PTestRPC::Test2_OutOfOrder]
 description =
 [PTestRPC::Test1_InnerQuery]
@@ -851,18 +853,16 @@ description =
 [PContent::CreateChildProcess]
 description =
 [PContent::BridgeToChildProcess]
 description =
 [PContent::LoadPlugin]
 description =
 [PContent::ConnectPluginBridge]
 description =
-[PContent::GetBlocklistState]
-description =
 [PContent::NSSU2FTokenIsCompatibleVersion]
 description =
 [PContent::NSSU2FTokenIsRegistered]
 description =
 [PContent::NSSU2FTokenRegister]
 description =
 [PContent::NSSU2FTokenSign]
 description =
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef js_StructuredClone_h
 #define js_StructuredClone_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/BufferList.h"
+#include "mozilla/MemoryReporting.h"
 
 #include <stdint.h>
 
 #include "jstypes.h"
 
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Value.h"
@@ -334,16 +335,26 @@ class JS_PUBLIC_API(JSAutoStructuredClon
 
     bool write(JSContext* cx, JS::HandleValue v,
                const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
     bool write(JSContext* cx, JS::HandleValue v, JS::HandleValue transferable,
                JS::CloneDataPolicy cloneDataPolicy,
                const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+    {
+        return data_.SizeOfExcludingThis(mallocSizeOf);
+    }
+
+    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
+    {
+        return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
+    }
+
   private:
     // Copy and assignment are not supported.
     JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = delete;
     JSAutoStructuredCloneBuffer& operator=(const JSAutoStructuredCloneBuffer& other) = delete;
 };
 
 // The range of tag values the application may use for its own custom object types.
 #define JS_SCTAG_USER_MIN  ((uint32_t) 0xFFFF8000)
--- a/js/public/TrackedOptimizationInfo.h
+++ b/js/public/TrackedOptimizationInfo.h
@@ -18,17 +18,16 @@ namespace JS {
     _(GetProp_Constant)                                 \
     _(GetProp_NotDefined)                               \
     _(GetProp_StaticName)                               \
     _(GetProp_SimdGetter)                               \
     _(GetProp_TypedObject)                              \
     _(GetProp_DefiniteSlot)                             \
     _(GetProp_Unboxed)                                  \
     _(GetProp_CommonGetter)                             \
-    _(GetProp_Static)                                   \
     _(GetProp_InlineAccess)                             \
     _(GetProp_Innerize)                                 \
     _(GetProp_InlineCache)                              \
     _(GetProp_SharedCache)                              \
     _(GetProp_ModuleNamespace)                          \
                                                         \
     _(SetProp_CommonSetter)                             \
     _(SetProp_TypedObject)                              \
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -9511,25 +9511,16 @@ BytecodeEmitter::emitCallOrNew(ParseNode
         if (!emitGetName(pn2, callop))
             return false;
         break;
       case PNK_DOT:
         MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
         if (pn2->as<PropertyAccess>().isSuper()) {
             if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
                 return false;
-        } else if ((pn->getOp() == JSOP_FUNCALL || pn->getOp() == JSOP_FUNAPPLY) &&
-                   pn2->expr()->getKind() == PNK_FUNCTION &&
-                   checkRunOnceContext()) {
-            // Top level lambdas whose .call or .apply methods are immediately
-            // invoked should be treated as run once lambdas.
-            emittingRunOnceLambda = true;
-            if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
-                return false;
-            emittingRunOnceLambda = false;
         } else {
             if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
                 return false;
         }
 
         break;
       case PNK_ELEM:
         MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -357,19 +357,16 @@ js::gc::GCRuntime::traceRuntimeCommon(JS
     for (const CooperatingContext& target : rt->cooperatingContexts())
         target.context()->trace(trc);
 
     // Trace all compartment roots, but not the compartment itself; it is
     // traced via the parent pointer if traceRoots actually traces anything.
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
         c->traceRoots(trc, traceOrMark);
 
-    // Trace the Gecko Profiler.
-    rt->geckoProfiler().trace(trc);
-
     // Trace helper thread roots.
     HelperThreadState().trace(trc);
 
     // Trace the embedding's black and gray roots.
     if (!JS::CurrentThreadIsHeapMinorCollecting()) {
         gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_EMBEDDING);
 
         /*
--- a/js/src/gc/ZoneGroup.cpp
+++ b/js/src/gc/ZoneGroup.cpp
@@ -6,16 +6,18 @@
 
 #include "gc/ZoneGroup.h"
 
 #include "jscntxt.h"
 
 #include "jit/IonBuilder.h"
 #include "jit/JitCompartment.h"
 
+using namespace js;
+
 namespace js {
 
 ZoneGroup::ZoneGroup(JSRuntime* runtime)
   : runtime(runtime),
     ownerContext_(TlsContext.get()),
     enterCount(1),
     zones_(this),
     usedByHelperThread(false),
@@ -142,8 +144,31 @@ ZoneGroup::deleteEmptyZone(Zone* zone)
             zone->destroy(runtime->defaultFreeOp());
             return;
         }
     }
     MOZ_CRASH("Zone not found");
 }
 
 } // namespace js
+
+JS::AutoRelinquishZoneGroups::AutoRelinquishZoneGroups(JSContext* cx)
+  : cx(cx)
+{
+    MOZ_ASSERT(cx == TlsContext.get());
+
+    AutoEnterOOMUnsafeRegion oomUnsafe;
+    for (ZoneGroupsIter group(cx->runtime()); !group.done(); group.next()) {
+        while (group->ownerContext().context() == cx) {
+            group->leave();
+            if (!enterList.append(group))
+                oomUnsafe.crash("AutoRelinquishZoneGroups");
+        }
+    }
+}
+
+JS::AutoRelinquishZoneGroups::~AutoRelinquishZoneGroups()
+{
+    for (size_t i = 0; i < enterList.length(); i++) {
+        ZoneGroup* group = static_cast<ZoneGroup*>(enterList[i]);
+        group->enter(cx);
+    }
+}
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/bailoutStaticObject.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Test bailouts from loading particular non-singleton static objects.
-
-function wrap(fun) {
-    function wrapper() {
-	return fun.apply(this, arguments);
-    }
-    return wrapper;
-}
-
-var adder = wrap(function(a, b) { return a + b; });
-var subber = wrap(function(a, b) { return a - b; });
-var tmp = adder;
-adder = subber;
-adder = tmp;
-
-function foo() {
-    var i = 0;
-    var a = 0;
-    for (var i = 0; i < 10000; i++) {
-	a = adder(a, 1);
-	a = subber(a, 1);
-    }
-    return a;
-}
-
-assertEq(foo(), 0);
-adder = subber;
-assertEq(foo(), -20000);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/idempotentCache.js
@@ -0,0 +1,34 @@
+// Test that we don't attach ICs to idempotent caches that are incompatible
+// with the cache result type.
+
+var missingObjs = [{a:1},Object.create({a:2}),{}];
+function testMissing(limit)
+{
+    var res = 0;
+    for (var i = 0; i < 1000; i++) {
+	for (var j = 0; j < missingObjs.length; j++) {
+	    var obj = missingObjs[j];
+	    if (j < limit)
+		res += obj.a;
+	}
+    }
+    return res;
+}
+assertEq(testMissing(2), 3000);
+assertEq(testMissing(3), NaN);
+
+var lengthObjs = [{length:{a:1}},Object.create({length:{a:2}}),[0,1]];
+function testArrayLength(limit)
+{
+    var res = 0;
+    for (var i = 0; i < 1000; i++) {
+	for (var j = 0; j < lengthObjs.length; j++) {
+	    var obj = lengthObjs[j];
+	    if (j < limit)
+		res += obj.length.a;
+	}
+    }
+    return res;
+}
+assertEq(testArrayLength(2), 3000);
+assertEq(testArrayLength(3), NaN);
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1998,17 +1998,16 @@ jit::FinishBailoutToBaseline(BaselineBai
       case Bailout_NonObjectInput:
       case Bailout_NonStringInput:
       case Bailout_NonSymbolInput:
       case Bailout_UnexpectedSimdInput:
       case Bailout_NonSharedTypedArrayInput:
       case Bailout_Debugger:
       case Bailout_UninitializedThis:
       case Bailout_BadDerivedConstructorReturn:
-      case Bailout_LoadStaticObject:
         // Do nothing.
         break;
 
       case Bailout_FirstExecution:
         // Do not return directly, as this was not frequent in the first place,
         // thus rely on the check for frequent bailouts to recompile the current
         // script.
         break;
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1540,17 +1540,17 @@ BaselineCompiler::emit_JSOP_FUNCTIONTHIS
     if (!callVM(GetFunctionThisInfo))
         return false;
 
     masm.bind(&skipCall);
     frame.push(R0);
     return true;
 }
 
-typedef bool (*GetNonSyntacticGlobalThisFn)(JSContext*, HandleObject, MutableHandleValue);
+typedef void (*GetNonSyntacticGlobalThisFn)(JSContext*, HandleObject, MutableHandleValue);
 static const VMFunction GetNonSyntacticGlobalThisInfo =
     FunctionInfo<GetNonSyntacticGlobalThisFn>(js::GetNonSyntacticGlobalThis,
                                               "GetNonSyntacticGlobalThis");
 
 bool
 BaselineCompiler::emit_JSOP_GLOBALTHIS()
 {
     frame.syncStack(0);
@@ -4803,17 +4803,18 @@ BaselineCompiler::emit_JSOP_RESUME()
 
     // If profiler instrumentation is on, update lastProfilingFrame on
     // current JitActivation
     {
         Register scratchReg = scratch2;
         Label skip;
         AbsoluteAddress addressOfEnabled(cx->runtime()->geckoProfiler().addressOfEnabled());
         masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skip);
-        masm.loadPtr(AbsoluteAddress(cx->addressOfProfilingActivation()), scratchReg);
+        masm.loadJSContext(scratchReg);
+        masm.loadPtr(Address(scratchReg, JSContext::offsetOfProfilingActivation()), scratchReg);
         masm.storePtr(masm.getStackPointer(),
                       Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()));
         masm.bind(&skip);
     }
 
     // Construct BaselineFrame.
     masm.push(BaselineFrameReg);
     masm.moveStackPtrTo(BaselineFrameReg);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -805,18 +805,20 @@ DoGetElemFallback(JSContext* cx, Baselin
     bool attached = false;
     bool isTemporarilyUnoptimizable = false;
 
     if (stub->state().maybeTransition())
         stub->discardStubs(cx);
 
     if (stub->state().canAttachStub()) {
         ICStubEngine engine = ICStubEngine::Baseline;
-        GetPropIRGenerator gen(cx, script, pc, CacheKind::GetElem, stub->state().mode(),
-                               &isTemporarilyUnoptimizable, lhs, rhs, lhs, CanAttachGetter::Yes);
+        GetPropIRGenerator gen(cx, script, pc,
+                               CacheKind::GetElem, stub->state().mode(),
+                               &isTemporarilyUnoptimizable, lhs, rhs, lhs,
+                               GetPropertyResultFlags::All);
         if (gen.tryAttachStub()) {
             ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
                                                         BaselineCacheIRStubKind::Monitored,
                                                         engine, script, stub, &attached);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 if (gen.shouldNotePreliminaryObjectStub())
                     newStub->toCacheIR_Monitored()->notePreliminaryObject();
@@ -879,17 +881,17 @@ DoGetElemSuperFallback(JSContext* cx, Ba
 
     if (stub->state().maybeTransition())
         stub->discardStubs(cx);
 
     if (stub->state().canAttachStub()) {
         ICStubEngine engine = ICStubEngine::Baseline;
         GetPropIRGenerator gen(cx, script, pc, CacheKind::GetElemSuper, stub->state().mode(),
                                &isTemporarilyUnoptimizable, lhs, rhs, receiver,
-                               CanAttachGetter::Yes);
+                               GetPropertyResultFlags::All);
         if (gen.tryAttachStub()) {
             ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
                                                         BaselineCacheIRStubKind::Monitored,
                                                         engine, script, stub, &attached);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 if (gen.shouldNotePreliminaryObjectStub())
                     newStub->toCacheIR_Monitored()->notePreliminaryObject();
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -1035,17 +1035,17 @@ GetMegamorphicGetterSetterFunction(ICStu
     JSObject* obj = isGetter ? propShape->getterObject() : propShape->setterObject();
     return &obj->as<JSFunction>();
 }
 
 bool
 BaselineInspector::megamorphicGetterSetterFunction(jsbytecode* pc, bool isGetter,
                                                    JSFunction** getterOrSetter)
 {
-    if (!hasBaselineScript() || *pc == JSOP_SETALIASEDVAR)
+    if (!hasBaselineScript())
         return false;
 
     *getterOrSetter = nullptr;
     const ICEntry& entry = icEntryFromPC(pc);
 
     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isCacheIR_Monitored()) {
             MOZ_ASSERT(isGetter);
@@ -1186,17 +1186,17 @@ AddCacheIRSetPropFunction(ICCacheIR_Upda
 }
 
 bool
 BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
                                          JSFunction** commonSetter, bool* isOwnProperty,
                                          ReceiverVector& receivers,
                                          ObjectGroupVector& convertUnboxedGroups)
 {
-    if (!hasBaselineScript() || *pc == JSOP_SETALIASEDVAR)
+    if (!hasBaselineScript())
         return false;
 
     MOZ_ASSERT(receivers.empty());
     MOZ_ASSERT(convertUnboxedGroups.empty());
 
     *commonSetter = nullptr;
     const ICEntry& entry = icEntryFromPC(pc);
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -1261,13 +1261,15 @@ MarkActiveBaselineScripts(JSContext* cx,
 }
 
 void
 jit::MarkActiveBaselineScripts(Zone* zone)
 {
     if (zone->isAtomsZone())
         return;
     JSContext* cx = TlsContext.get();
-    for (JitActivationIterator iter(cx, zone->group()->ownerContext()); !iter.done(); ++iter) {
-        if (iter->compartment()->zone() == zone)
-            MarkActiveBaselineScripts(cx, iter);
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        for (JitActivationIterator iter(cx, target); !iter.done(); ++iter) {
+            if (iter->compartment()->zone() == zone)
+                MarkActiveBaselineScripts(cx, iter);
+        }
     }
 }
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -43,23 +43,23 @@ IRGenerator::IRGenerator(JSContext* cx, 
     cacheKind_(cacheKind),
     mode_(mode)
 {}
 
 GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
                                        CacheKind cacheKind, ICState::Mode mode,
                                        bool* isTemporarilyUnoptimizable, HandleValue val,
                                        HandleValue idVal, HandleValue receiver,
-                                       CanAttachGetter canAttachGetter)
+                                       GetPropertyResultFlags resultFlags)
   : IRGenerator(cx, script, pc, cacheKind, mode),
     val_(val),
     idVal_(idVal),
     receiver_(receiver),
     isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
-    canAttachGetter_(canAttachGetter),
+    resultFlags_(resultFlags),
     preliminaryObjectAction_(PreliminaryObjectAction::None)
 {}
 
 static void
 EmitLoadSlotResult(CacheIRWriter& writer, ObjOperandId holderOp, NativeObject* holder,
                    Shape* shape)
 {
     if (holder->isFixedSlot(shape->slot())) {
@@ -242,72 +242,75 @@ GetPropIRGenerator::tryAttachStub()
 
     trackNotAttached();
     return false;
 }
 
 bool
 GetPropIRGenerator::tryAttachIdempotentStub()
 {
-    // For idempotent ICs, only attach stubs for plain data properties.
-    // This ensures (1) the lookup has no side-effects and (2) Ion has complete
-    // static type information and we don't have to monitor the result. Because
-    // of (2), we don't support for instance missing properties or array
-    // lengths, as TI does not account for these cases.
+    // For idempotent ICs, only attach stubs which we can be sure have no side
+    // effects and produce a result which the MIR in the calling code is able
+    // to handle, since we do not have a pc to explicitly monitor the result.
 
     MOZ_ASSERT(idempotent());
 
     RootedObject obj(cx_, &val_.toObject());
     RootedId id(cx_, NameToId(idVal_.toString()->asAtom().asPropertyName()));
 
     ValOperandId valId(writer.setInputOperandId(0));
     ObjOperandId objId = writer.guardIsObject(valId);
     if (tryAttachNative(obj, objId, id))
         return true;
 
+    // Object lengths are supported only if int32 results are allowed.
+    if ((resultFlags_ & GetPropertyResultFlags::AllowInt32) && tryAttachObjectLength(obj, objId, id))
+        return true;
+
     // Also support native data properties on DOMProxy prototypes.
     if (GetProxyStubType(cx_, obj, id) == ProxyStubType::DOMUnshadowed)
         return tryAttachDOMProxyUnshadowed(obj, objId, id);
 
     return false;
 }
 
 static bool
 IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
-                      jsbytecode* pc)
+                      jsbytecode* pc, GetPropertyResultFlags resultFlags)
 {
     if (shape)
         return false;
 
     MOZ_ASSERT(!holder);
 
-    if (!pc) {
-        // This is an idempotent IC, don't attach a missing-property stub.
-        // See tryAttachStub.
+    // Idempotent ICs may only attach missing-property stubs if undefined
+    // results are explicitly allowed, since no monitoring is done of the
+    // cache result.
+    if (!pc && !(resultFlags & GetPropertyResultFlags::AllowUndefined))
         return false;
-    }
 
     // If we're doing a name lookup, we have to throw a ReferenceError. If
     // extra warnings are enabled, we may have to report a warning.
-    if (*pc == JSOP_GETBOUNDNAME || cx->compartment()->behaviors().extraWarnings(cx))
+    // Note that Ion does not generate idempotent caches for JSOP_GETBOUNDNAME.
+    if ((pc && *pc == JSOP_GETBOUNDNAME) || cx->compartment()->behaviors().extraWarnings(cx))
         return false;
 
     return CheckHasNoSuchProperty(cx, obj, id);
 }
 
 enum NativeGetPropCacheability {
     CanAttachNone,
     CanAttachReadSlot,
     CanAttachCallGetter,
 };
 
 static NativeGetPropCacheability
 CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
                        MutableHandleNativeObject holder, MutableHandleShape shape,
-                       jsbytecode* pc, CanAttachGetter canAttachGetter,
+                       jsbytecode* pc, GetPropertyResultFlags resultFlags,
                        bool* isTemporarilyUnoptimizable)
 {
     MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
 
     // The lookup needs to be universally pure, otherwise we risk calling hooks out
     // of turn. We don't mind doing this even when purity isn't required, because we
     // only miss out on shape hashification, which is only a temporary perf cost.
     // The limits were arbitrarily set, anyways.
@@ -322,32 +325,27 @@ CanAttachNativeGetProp(JSContext* cx, Ha
             return CanAttachNone;
         holder.set(&baseHolder->as<NativeObject>());
     }
     shape.set(prop.maybeShape());
 
     if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop))
         return CanAttachReadSlot;
 
-    // Idempotent ICs only support plain data properties, see
-    // tryAttachIdempotentStub.
-    if (!pc)
-        return CanAttachNone;
-
-    if (IsCacheableNoProperty(cx, obj, holder, shape, id, pc))
+    if (IsCacheableNoProperty(cx, obj, holder, shape, id, pc, resultFlags))
         return CanAttachReadSlot;
 
-    if (canAttachGetter == CanAttachGetter::No)
-        return CanAttachNone;
-
-    if (IsCacheableGetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable))
-        return CanAttachCallGetter;
-
-    if (IsCacheableGetPropCallNative(obj, holder, shape))
-        return CanAttachCallGetter;
+    // Idempotent ICs cannot call getters, see tryAttachIdempotentStub.
+    if (pc && (resultFlags & GetPropertyResultFlags::Monitored)) {
+        if (IsCacheableGetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable))
+            return CanAttachCallGetter;
+
+        if (IsCacheableGetPropCallNative(obj, holder, shape))
+            return CanAttachCallGetter;
+    }
 
     return CanAttachNone;
 }
 
 static void
 GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder, ObjOperandId objId)
 {
     // The guards here protect against the effects of JSObject::swap(). If the
@@ -577,20 +575,18 @@ GetPropIRGenerator::attachMegamorphicNat
 
 bool
 GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id)
 {
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
 
     NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
-                                                            canAttachGetter_,
+                                                            resultFlags_,
                                                             isTemporarilyUnoptimizable_);
-    MOZ_ASSERT_IF(idempotent(),
-                  type == CanAttachNone || (type == CanAttachReadSlot && holder));
     switch (type) {
       case CanAttachNone:
         return false;
       case CanAttachReadSlot:
         if (mode_ == ICState::Mode::Megamorphic) {
             attachMegamorphicNativeSlot(objId, id, holder == nullptr);
             return true;
         }
@@ -608,16 +604,17 @@ GetPropIRGenerator::tryAttachNative(Hand
         }
         EmitReadSlotResult(writer, obj, holder, shape, objId);
         EmitReadSlotReturn(writer, obj, holder, shape);
 
         trackAttached("NativeSlot");
         return true;
       case CanAttachCallGetter: {
         // |super.prop| accesses use a |this| value that differs from lookup object
+        MOZ_ASSERT(!idempotent());
         ObjOperandId receiverId = isSuper() ? writer.guardIsObject(getSuperReceiverValueId())
                                             : objId;
         maybeEmitIdGuard(id);
         EmitCallGetterResult(writer, obj, holder, shape, objId, receiverId, mode_);
 
         trackAttached("NativeGetter");
         return true;
       }
@@ -646,17 +643,17 @@ GetPropIRGenerator::tryAttachWindowProxy
     MOZ_ASSERT(obj->getClass() == cx_->runtime()->maybeWindowProxyClass());
     MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx_->global());
 
     // Now try to do the lookup on the Window (the current global).
     HandleObject windowObj = cx_->global();
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
     NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_,
-                                                            canAttachGetter_,
+                                                            resultFlags_,
                                                             isTemporarilyUnoptimizable_);
     switch (type) {
       case CanAttachNone:
         return false;
 
       case CanAttachReadSlot: {
         maybeEmitIdGuard(id);
         writer.guardClass(objId, GuardClassKind::WindowProxy);
@@ -733,18 +730,18 @@ GetPropIRGenerator::tryAttachCrossCompar
         MOZ_ASSERT(ToWindowIfWindowProxy(unwrapped) == unwrapped->compartment()->maybeGlobal());
         unwrapped = cx_->global();
         MOZ_ASSERT(unwrapped);
     }
 
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
     NativeGetPropCacheability canCache =
-        CanAttachNativeGetProp(cx_, unwrapped, id, &holder, &shape, pc_, canAttachGetter_,
-                               isTemporarilyUnoptimizable_);
+        CanAttachNativeGetProp(cx_, unwrapped, id, &holder, &shape, pc_,
+                               resultFlags_, isTemporarilyUnoptimizable_);
     if (canCache != CanAttachReadSlot)
         return false;
 
     if (holder) {
         EnsureTrackPropertyTypes(cx_, holder, id);
         if (unwrapped == holder) {
             // See the comment in StripPreliminaryObjectStubs.
             if (IsPreliminaryObject(unwrapped))
@@ -958,17 +955,17 @@ GetPropIRGenerator::tryAttachDOMProxyExp
         expandoObj = &expandoAndGeneration->expando.toObject();
     }
 
     // Try to do the lookup on the expando object.
     RootedNativeObject holder(cx_);
     RootedShape propShape(cx_);
     NativeGetPropCacheability canCache =
         CanAttachNativeGetProp(cx_, expandoObj, id, &holder, &propShape, pc_,
-                               canAttachGetter_, isTemporarilyUnoptimizable_);
+                               resultFlags_, isTemporarilyUnoptimizable_);
     if (canCache != CanAttachReadSlot && canCache != CanAttachCallGetter)
         return false;
     if (!holder)
         return false;
 
     MOZ_ASSERT(holder == expandoObj);
 
     maybeEmitIdGuard(id);
@@ -1049,20 +1046,18 @@ GetPropIRGenerator::tryAttachDOMProxyUns
 
     RootedObject checkObj(cx_, obj->staticPrototype());
     if (!checkObj)
         return false;
 
     RootedNativeObject holder(cx_);
     RootedShape shape(cx_);
     NativeGetPropCacheability canCache = CanAttachNativeGetProp(cx_, checkObj, id, &holder, &shape,
-                                                                pc_, canAttachGetter_,
+                                                                pc_, resultFlags_,
                                                                 isTemporarilyUnoptimizable_);
-    MOZ_ASSERT_IF(idempotent(),
-                  canCache == CanAttachNone || (canCache == CanAttachReadSlot && holder));
     if (canCache == CanAttachNone)
         return false;
 
     maybeEmitIdGuard(id);
     writer.guardShape(objId, obj->maybeShape());
 
     // Guard that our expando object hasn't started shadowing this property.
     CheckDOMProxyExpandoDoesNotShadow(writer, obj, id, objId);
@@ -1389,17 +1384,17 @@ GetPropIRGenerator::tryAttachPrimitive(V
         return false;
     }
     if (!proto)
         return false;
 
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
     NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, proto, id, &holder, &shape, pc_,
-                                                            canAttachGetter_,
+                                                            resultFlags_,
                                                             isTemporarilyUnoptimizable_);
     if (type != CanAttachReadSlot)
         return false;
 
     if (holder) {
         // Instantiate this property, for use during Ion compilation.
         if (IsIonEnabled(cx_))
             EnsureTrackPropertyTypes(cx_, holder, id);
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -1142,26 +1142,57 @@ class MOZ_RAII IRGenerator
   public:
     explicit IRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
                          ICState::Mode mode);
 
     const CacheIRWriter& writerRef() const { return writer; }
     CacheKind cacheKind() const { return cacheKind_; }
 };
 
-enum class CanAttachGetter { Yes, No };
+// Flags used to describe what values a GetProperty cache may produce.
+enum class GetPropertyResultFlags {
+    None            = 0,
+
+    // Values produced by this cache will go through a type barrier,
+    // so the cache may produce any type of value that is compatible with its
+    // result operand.
+    Monitored       = 1 << 0,
+
+    // Whether particular primitives may be produced by this cache.
+    AllowUndefined  = 1 << 1,
+    AllowInt32      = 1 << 2,
+    AllowDouble     = 1 << 3,
+
+    All             = Monitored | AllowUndefined | AllowInt32 | AllowDouble
+};
+
+static inline bool operator&(GetPropertyResultFlags a, GetPropertyResultFlags b)
+{
+    return static_cast<int>(a) & static_cast<int>(b);
+}
+
+static inline GetPropertyResultFlags operator|(GetPropertyResultFlags a, GetPropertyResultFlags b)
+{
+    return static_cast<GetPropertyResultFlags>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+static inline GetPropertyResultFlags& operator|=(GetPropertyResultFlags& lhs, GetPropertyResultFlags b)
+{
+    lhs = lhs | b;
+    return lhs;
+}
 
 // GetPropIRGenerator generates CacheIR for a GetProp IC.
 class MOZ_RAII GetPropIRGenerator : public IRGenerator
 {
     HandleValue val_;
     HandleValue idVal_;
     HandleValue receiver_;
     bool* isTemporarilyUnoptimizable_;
-    CanAttachGetter canAttachGetter_;
+    GetPropertyResultFlags resultFlags_;
 
     enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
     PreliminaryObjectAction preliminaryObjectAction_;
 
     bool tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId, HandleId id);
@@ -1228,17 +1259,18 @@ class MOZ_RAII GetPropIRGenerator : publ
     void maybeEmitIdGuard(jsid id);
 
     void trackAttached(const char* name);
     void trackNotAttached();
 
   public:
     GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
                        ICState::Mode mode, bool* isTemporarilyUnoptimizable, HandleValue val,
-                       HandleValue idVal, HandleValue receiver, CanAttachGetter canAttachGetter);
+                       HandleValue idVal, HandleValue receiver,
+                       GetPropertyResultFlags resultFlags);
 
     bool tryAttachStub();
     bool tryAttachIdempotentStub();
 
     bool shouldUnlinkPreliminaryObjectStubs() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
     }
     bool shouldNotePreliminaryObjectStub() const {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10280,28 +10280,27 @@ CodeGenerator::visitGetNameCache(LGetNam
     IonGetNameIC ic(liveRegs, envChain, output, temp);
     addIC(ins, allocateIC(ic));
 }
 
 void
 CodeGenerator::addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                                    TypedOrValueRegister value, const ConstantOrRegister& id,
                                    TypedOrValueRegister output, Register maybeTemp,
-                                   bool monitoredResult, bool allowDoubleResult,
+                                   GetPropertyResultFlags resultFlags,
                                    jsbytecode* profilerLeavePc)
 {
     CacheKind kind = CacheKind::GetElem;
     if (id.constant() && id.value().isString()) {
         JSString* idString = id.value().toString();
         uint32_t dummy;
         if (idString->isAtom() && !idString->asAtom().isIndex(&dummy))
             kind = CacheKind::GetProp;
     }
-    IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, monitoredResult,
-                           allowDoubleResult);
+    IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, resultFlags);
     addIC(ins, allocateIC(cache));
 }
 
 void
 CodeGenerator::addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
                                    Register temp, FloatRegister tempDouble,
                                    FloatRegister tempF32, const ConstantOrRegister& id,
                                    const ConstantOrRegister& value,
@@ -10328,44 +10327,71 @@ CodeGenerator::toConstantOrRegister(LIns
 
     const LAllocation* value = lir->getOperand(n);
     if (value->isConstant())
         return ConstantOrRegister(value->toConstant()->toJSValue());
 
     return TypedOrValueRegister(type, ToAnyRegister(value));
 }
 
+static GetPropertyResultFlags
+IonGetPropertyICFlags(const MGetPropertyCache* mir)
+{
+    GetPropertyResultFlags flags = GetPropertyResultFlags::None;
+    if (mir->monitoredResult())
+        flags |= GetPropertyResultFlags::Monitored;
+
+    if (mir->type() == MIRType::Value) {
+        if (TemporaryTypeSet* types = mir->resultTypeSet()) {
+            if (types->hasType(TypeSet::UndefinedType()))
+                flags |= GetPropertyResultFlags::AllowUndefined;
+            if (types->hasType(TypeSet::Int32Type()))
+                flags |= GetPropertyResultFlags::AllowInt32;
+            if (types->hasType(TypeSet::DoubleType()))
+                flags |= GetPropertyResultFlags::AllowDouble;
+        } else {
+            flags |= GetPropertyResultFlags::AllowUndefined
+                   | GetPropertyResultFlags::AllowInt32
+                   | GetPropertyResultFlags::AllowDouble;
+        }
+    } else if (mir->type() == MIRType::Int32) {
+        flags |= GetPropertyResultFlags::AllowInt32;
+    } else if (mir->type() == MIRType::Double) {
+        flags |= GetPropertyResultFlags::AllowInt32 | GetPropertyResultFlags::AllowDouble;
+    }
+
+    return flags;
+}
+
 void
 CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins)
 {
     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
     TypedOrValueRegister value =
         toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
     ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheV::Id, ins->mir()->idval()->type());
-    bool monitoredResult = ins->mir()->monitoredResult();
     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
     Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
 
-    addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
-                        ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
+    addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp,
+                        IonGetPropertyICFlags(ins->mir()), ins->mir()->profilerLeavePc());
 }
 
 void
 CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins)
 {
     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
     TypedOrValueRegister value =
         toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
     ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheT::Id, ins->mir()->idval()->type());
-    bool monitoredResult = ins->mir()->monitoredResult();
     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
     Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
 
-    addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
-                        ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
+    addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp,
+                        IonGetPropertyICFlags(ins->mir()), ins->mir()->profilerLeavePc());
 }
 
 void
 CodeGenerator::visitBindNameCache(LBindNameCache* ins)
 {
     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register envChain = ToRegister(ins->environmentChain());
     Register output = ToRegister(ins->output());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_CodeGenerator_h
 #define jit_CodeGenerator_h
 
+#include "jit/CacheIR.h"
 #include "jit/IonCaches.h"
 #if defined(JS_ION_PERF)
 # include "jit/PerfSpewer.h"
 #endif
 
 #if defined(JS_CODEGEN_X86)
 # include "jit/x86/CodeGenerator-x86.h"
 #elif defined(JS_CODEGEN_X64)
@@ -463,18 +464,18 @@ class CodeGenerator final : public CodeG
         IonScriptCounts* counts = scriptCounts_;
         scriptCounts_ = nullptr;  // prevent delete in dtor
         return counts;
     }
 
   private:
     void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                              TypedOrValueRegister value, const ConstantOrRegister& id,
-                             TypedOrValueRegister output, Register maybeTemp, bool monitoredResult,
-                             bool allowDoubleResult, jsbytecode* profilerLeavePc);
+                             TypedOrValueRegister output, Register maybeTemp,
+                             GetPropertyResultFlags flags, jsbytecode* profilerLeavePc);
     void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
                              Register temp, FloatRegister tempDouble,
                              FloatRegister tempF32, const ConstantOrRegister& id,
                              const ConstantOrRegister& value,
                              bool strict, bool needsPostBarrier, bool needsTypeBarrier,
                              bool guardHoles, jsbytecode* profilerLeavePc);
 
     MOZ_MUST_USE bool generateBranchV(const ValueOperand& value, Label* ifTrue, Label* ifFalse,
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -32,17 +32,17 @@ CompileRuntime::addressOfGCZealModeBits(
 #endif
 
 const JitRuntime*
 CompileRuntime::jitRuntime()
 {
     return runtime()->jitRuntime();
 }
 
-GeckoProfiler&
+GeckoProfilerRuntime&
 CompileRuntime::geckoProfiler()
 {
     return runtime()->geckoProfiler();
 }
 
 bool
 CompileRuntime::jitSupportsFloatingPoint()
 {
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -29,17 +29,17 @@ class CompileRuntime
 
 #ifdef JS_GC_ZEAL
     const void* addressOfGCZealModeBits();
 #endif
 
     const JitRuntime* jitRuntime();
 
     // Compilation does not occur off thread when the Gecko Profiler is enabled.
-    GeckoProfiler& geckoProfiler();
+    GeckoProfilerRuntime& geckoProfiler();
 
     bool jitSupportsFloatingPoint();
     bool hadOutOfMemory();
     bool profilingScripts();
 
     const JSAtomState& names();
     const PropertyName* emptyString();
     const StaticStrings& staticStrings();
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -3120,20 +3120,22 @@ jit::InvalidateAll(FreeOp* fop, Zone* zo
     // The caller should previously have cancelled off thread compilation.
 #ifdef DEBUG
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
         MOZ_ASSERT(!HasOffThreadIonCompile(comp));
 #endif
     if (zone->isAtomsZone())
         return;
     JSContext* cx = TlsContext.get();
-    for (JitActivationIterator iter(cx, zone->group()->ownerContext()); !iter.done(); ++iter) {
-        if (iter->compartment()->zone() == zone) {
-            JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
-            InvalidateActivation(fop, iter, true);
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        for (JitActivationIterator iter(cx, target); !iter.done(); ++iter) {
+            if (iter->compartment()->zone() == zone) {
+                JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
+                InvalidateActivation(fop, iter, true);
+            }
         }
     }
 }
 
 
 void
 jit::Invalidate(TypeZone& types, FreeOp* fop,
                 const RecompileInfoVector& invalid, bool resetUses,
@@ -3174,18 +3176,20 @@ jit::Invalidate(TypeZone& types, FreeOp*
     // This method can be called both during GC and during the course of normal
     // script execution. In the former case this class will already be on the
     // stack, and in the latter case the invalidations will all be on the
     // current thread's stack, but the assertion under ActivationIterator can't
     // tell that this is a thread local use of the iterator.
     JSRuntime::AutoProhibitActiveContextChange apacc(fop->runtime());
 
     JSContext* cx = TlsContext.get();
-    for (JitActivationIterator iter(cx, types.zone()->group()->ownerContext()); !iter.done(); ++iter)
-        InvalidateActivation(fop, iter, false);
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        for (JitActivationIterator iter(cx, target); !iter.done(); ++iter)
+            InvalidateActivation(fop, iter, false);
+    }
 
     // Drop the references added above. If a script was never active, its
     // IonScript will be immediately destroyed. Otherwise, it will be held live
     // until its last invalidated frame is destroyed.
     for (size_t i = 0; i < invalid.length(); i++) {
         CompilerOutput* co = invalid[i].compilerOutput(types);
         if (!co)
             continue;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/IonBuilder.h"
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/SizePrintfMacros.h"
 
 #include "builtin/Eval.h"
 #include "builtin/TypedObject.h"
 #include "frontend/SourceNotes.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineInspector.h"
 #include "jit/Ion.h"
@@ -831,21 +832,23 @@ IonBuilder::build()
 #ifdef DEBUG
     // lazyArguments should never be accessed in |argsObjAliasesFormals| scripts.
     if (info().hasArguments() && !info().argsObjAliasesFormals())
         hasLazyArguments_ = true;
 #endif
 
     insertRecompileCheck();
 
+    auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] {
+        // Discard unreferenced & pre-allocated resume points.
+        replaceMaybeFallbackFunctionGetter(nullptr);
+    });
+
     MOZ_TRY(traverseBytecode());
 
-    // Discard unreferenced & pre-allocated resume points.
-    replaceMaybeFallbackFunctionGetter(nullptr);
-
     if (script_->hasBaselineScript() &&
         inlinedBytecodeLength_ > script_->baselineScript()->inlinedBytecodeLength())
     {
         script_->baselineScript()->setInlinedBytecodeLength(inlinedBytecodeLength_);
     }
 
     MOZ_TRY(maybeAddOsrTypeBarriers());
     MOZ_TRY(processIterators());
@@ -993,20 +996,23 @@ IonBuilder::buildInline(IonBuilder* call
 #endif
 
     insertRecompileCheck();
 
     // Initialize the env chain now that all resume points operands are
     // initialized.
     MOZ_TRY(initEnvironmentChain(callInfo.fun()));
 
+    auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] {
+        // Discard unreferenced & pre-allocated resume points.
+        replaceMaybeFallbackFunctionGetter(nullptr);
+    });
+
     MOZ_TRY(traverseBytecode());
 
-    // Discard unreferenced & pre-allocated resume points.
-    replaceMaybeFallbackFunctionGetter(nullptr);
 
     MOZ_ASSERT(iterators_.empty(), "Iterators should be added to outer builder");
 
     if (!info().isAnalysis() && !abortedPreliminaryGroups().empty())
         return abort(AbortReason::PreliminaryObjects);
 
     return Ok();
 }
@@ -7270,16 +7276,27 @@ IonBuilder::ensureDefiniteTypeSet(MDefin
     }
 
     // Create a NOP mir instruction to filter the typeset.
     MFilterTypeSet* filter = MFilterTypeSet::New(alloc(), def, types);
     current->add(filter);
     return filter;
 }
 
+static size_t
+NumFixedSlots(JSObject* object)
+{
+    // Note: we can't use object->numFixedSlots() here, as this will read the
+    // shape and can race with the active thread if we are building off thread.
+    // The allocation kind and object class (which goes through the type) can
+    // be read freely, however.
+    gc::AllocKind kind = object->asTenured().getAllocKind();
+    return gc::GetGCKindSlots(kind, object->getClass());
+}
+
 static bool
 IsUninitializedGlobalLexicalSlot(JSObject* obj, PropertyName* name)
 {
     LexicalEnvironmentObject &globalLexical = obj->as<LexicalEnvironmentObject>();
     MOZ_ASSERT(globalLexical.isGlobal());
     Shape* shape = globalLexical.lookupPure(name);
     if (!shape)
         return false;
@@ -7291,58 +7308,42 @@ IonBuilder::getStaticName(bool* emitted,
                           MDefinition* lexicalCheck)
 {
     MOZ_ASSERT(*emitted == false);
 
     jsid id = NameToId(name);
 
     bool isGlobalLexical = staticObject->is<LexicalEnvironmentObject>() &&
                            staticObject->as<LexicalEnvironmentObject>().isGlobal();
+    MOZ_ASSERT(isGlobalLexical ||
+               staticObject->is<GlobalObject>() ||
+               staticObject->is<CallObject>() ||
+               staticObject->is<ModuleEnvironmentObject>());
+    MOZ_ASSERT(staticObject->isSingleton());
 
     // Always emit the lexical check. This could be optimized, but is
     // currently not for simplicity's sake.
     if (lexicalCheck)
         return Ok();
 
-    // Only optimize accesses on native objects.
-    if (!staticObject->isNative())
-        return Ok();
-
-    // Only optimize accesses on own data properties.
-    Shape* propertyShape = staticObject->as<NativeObject>().lastProperty()->searchLinear(NameToId(name));
-    if (!propertyShape || !propertyShape->isDataDescriptor() || !propertyShape->hasSlot())
-        return Ok();
-    uint32_t slot = propertyShape->slot();
-
     TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(staticObject);
     if (analysisContext)
         staticKey->ensureTrackedProperty(analysisContext, NameToId(name));
 
-    // Make sure the property is a normal data property. This is not done for
-    // call objects, as they are not tracked by TI and their data properties
-    // cannot be dynamically reconfigured.
-    Maybe<HeapTypeSetKey> property;
-    if (!staticObject->is<CallObject>()) {
-        if (staticKey->unknownProperties())
-            return Ok();
-
-        property.emplace(staticKey->property(id));
-
-        if (property.ref().nonData(constraints()) ||
-            !property.ref().maybeTypes() ||
-            !property.ref().maybeTypes()->definiteProperty())
-        {
-            // We can't be sure the slot will match at runtime, so include a
-            // shape guard on the object.
-            MInstruction* obj = MConstant::NewConstraintlessObject(alloc(), staticObject);
-            current->add(obj);
-            addShapeGuard(obj, staticObject->as<NativeObject>().lastProperty(), Bailout_ShapeGuard);
-        } else {
-            MOZ_ASSERT(slot == property.ref().maybeTypes()->definiteSlot());
-        }
+    if (staticKey->unknownProperties())
+        return Ok();
+
+    HeapTypeSetKey property = staticKey->property(id);
+    if (!property.maybeTypes() ||
+        !property.maybeTypes()->definiteProperty() ||
+        property.nonData(constraints()))
+    {
+        // The property has been reconfigured as non-configurable, non-enumerable
+        // or non-writable.
+        return Ok();
     }
 
     // Don't optimize global lexical bindings if they aren't initialized at
     // compile time.
     if (isGlobalLexical && IsUninitializedGlobalLexicalSlot(staticObject, name))
         return Ok();
 
     *emitted = true;
@@ -7358,47 +7359,23 @@ IonBuilder::getStaticName(bool* emitted,
             if (testSingletonProperty(staticObject, id) == singleton) {
                 pushConstant(ObjectValue(*singleton));
                 return Ok();
             }
         }
 
         // Try to inline properties that have never been overwritten.
         Value constantValue;
-        if (property.isSome() && property.ref().constant(constraints(), &constantValue)) {
+        if (property.constant(constraints(), &constantValue)) {
             pushConstant(constantValue);
             return Ok();
         }
     }
 
-    MOZ_TRY(loadStaticSlot(staticObject, barrier, types, slot));
-
-    // If the static object has a function object stored in this property,
-    // test that the result is that specific function. This is yet another
-    // technique for trying to force a property load to be a specific value,
-    // and is included because other mechanisms (property types and observed
-    // types) do not always work, especially in polymorphic framework code.
-    // We restrict this optimization to function properties, as they are less
-    // likely to change over time and are more likely to require precise
-    // information for inlining decisions.
-    if (!outermostBuilder()->script()->hadFrequentBailouts()) {
-        Value v = staticObject->as<NativeObject>().getSlot(slot);
-        if (v.isObject() &&
-            v.toObject().is<JSFunction>() &&
-            v.toObject().as<JSFunction>().isInterpreted())
-        {
-            JSObject* result = checkNurseryObject(&v.toObject().as<JSFunction>());
-            MDefinition* load = current->pop();
-            MInstruction* expected = MConstant::NewConstraintlessObject(alloc(), result);
-            expected->setResultTypeSet(MakeSingletonTypeSet(constraints(), result));
-            current->add(expected);
-            current->add(MGuardObjectIdentity::New(alloc(), load, expected, false, Bailout_LoadStaticObject));
-            current->push(expected);
-        }
-    }
+    MOZ_TRY(loadStaticSlot(staticObject, barrier, types, property.maybeTypes()->definiteSlot()));
 
     return Ok();
 }
 
 AbortReasonOr<Ok>
 IonBuilder::loadStaticSlot(JSObject* staticObject, BarrierKind barrier, TemporaryTypeSet* types,
                            uint32_t slot)
 {
@@ -7416,17 +7393,17 @@ IonBuilder::loadStaticSlot(JSObject* sta
     }
 
     MInstruction* obj = constant(ObjectValue(*staticObject));
 
     MIRType rvalType = types->getKnownMIRType();
     if (barrier != BarrierKind::NoBarrier)
         rvalType = MIRType::Value;
 
-    return loadSlot(obj, slot, staticObject->as<NativeObject>().numFixedSlots(), rvalType, barrier, types);
+    return loadSlot(obj, slot, NumFixedSlots(staticObject), rvalType, barrier, types);
 }
 
 // Whether a write of the given value may need a post-write barrier for GC purposes.
 bool
 jit::NeedsPostBarrier(MDefinition* value)
 {
     if (!GetJitContext()->compartment->zone()->nurseryExists())
         return false;
@@ -7481,18 +7458,17 @@ IonBuilder::setStaticName(JSObject* stat
     // If the property has a known type, we may be able to optimize typed stores by not
     // storing the type tag.
     MIRType slotType = MIRType::None;
     MIRType knownType = property.knownMIRType(constraints());
     if (knownType != MIRType::Value)
         slotType = knownType;
 
     bool needsPreBarrier = property.needsBarrier(constraints());
-    return storeSlot(obj, property.maybeTypes()->definiteSlot(),
-                     staticObject->as<NativeObject>().numFixedSlots(),
+    return storeSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
                      value, needsPreBarrier, slotType);
 }
 
 JSObject*
 IonBuilder::testGlobalLexicalBinding(PropertyName* name)
 {
     MOZ_ASSERT(JSOp(*pc) == JSOP_BINDGNAME ||
                JSOp(*pc) == JSOP_GETGNAME ||
@@ -10423,22 +10399,16 @@ IonBuilder::jsop_getprop(PropertyName* n
             return Ok();
 
         // Try to inline a common property getter, or make a call.
         trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
         MOZ_TRY(getPropTryCommonGetter(&emitted, obj, name, types));
         if (emitted)
             return Ok();
 
-        // Try to optimize for loads from a specific object.
-        trackOptimizationAttempt(TrackedStrategy::GetProp_Static);
-        MOZ_TRY(getPropTryStaticAccess(&emitted, obj, name, barrier, types));
-        if (emitted)
-            return Ok();
-
         // Try to emit a monomorphic/polymorphic access based on baseline caches.
         trackOptimizationAttempt(TrackedStrategy::GetProp_InlineAccess);
         MOZ_TRY(getPropTryInlineAccess(&emitted, obj, name, barrier, types));
         if (emitted)
             return Ok();
 
         // Try to emit loads from a module namespace.
         trackOptimizationAttempt(TrackedStrategy::GetProp_ModuleNamespace);
@@ -11229,27 +11199,16 @@ PropertyShapesHaveSameSlot(const Baselin
             return nullptr;
         }
     }
 
     return firstShape;
 }
 
 AbortReasonOr<Ok>
-IonBuilder::getPropTryStaticAccess(bool* emitted, MDefinition* obj, PropertyName* name,
-                                   BarrierKind barrier, TemporaryTypeSet* types)
-{
-    if (!obj->isConstant() || obj->type() != MIRType::Object)
-        return Ok();
-
-    obj->setImplicitlyUsedUnchecked();
-    return getStaticName(emitted, &obj->toConstant()->toObject(), name);
-}
-
-AbortReasonOr<Ok>
 IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
                                    BarrierKind barrier, TemporaryTypeSet* types)
 {
     MOZ_ASSERT(*emitted == false);
 
     BaselineInspector::ReceiverVector receivers(alloc());
     BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
     if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
@@ -12672,59 +12631,21 @@ IonBuilder::walkEnvironmentChain(unsigne
         MInstruction* ins = MEnclosingEnvironment::New(alloc(), env);
         current->add(ins);
         env = ins;
     }
 
     return env;
 }
 
-static bool
-SearchEnvironmentChainForCallObject(JSObject* environment, JSScript* script, JSObject** pcall)
-{
-    while (environment && !environment->is<GlobalObject>()) {
-        if (environment->is<CallObject>() &&
-            environment->as<CallObject>().callee().nonLazyScript() == script)
-        {
-            *pcall = environment;
-            return true;
-        }
-        environment = environment->enclosingEnvironment();
-    }
-    return false;
-}
-
 bool
 IonBuilder::hasStaticEnvironmentObject(EnvironmentCoordinate ec, JSObject** pcall)
 {
     JSScript* outerScript = EnvironmentCoordinateFunctionScript(script(), pc);
-    if (!outerScript)
-        return false;
-
-    // JSOP_SETALIASEDVAR only emits a cache when the outer script is a run
-    // once script. To avoid problems with the generic jsop_setprop() paths,
-    // only use static environment objects when a baseline cache exists.
-    if (*pc == JSOP_SETALIASEDVAR && !outerScript->treatAsRunOnce())
-        return false;
-
-    // If the callee is a specific JSFunction then there is a specific
-    // environment object on its chain we can use.
-    if (inlineCallInfo_) {
-        MDefinition* calleeDef = inlineCallInfo_->fun();
-        if (calleeDef->isConstant()) {
-            JSFunction* callee = &calleeDef->toConstant()->toObject().template as<JSFunction>();
-            JSObject* environment = callee->environment();
-            if (SearchEnvironmentChainForCallObject(environment, outerScript, pcall))
-                return true;
-        }
-    }
-
-    // Otherwise, if the outer script will only run once then we can go looking
-    // for its call object.
-    if (!outerScript->treatAsRunOnce())
+    if (!outerScript || !outerScript->treatAsRunOnce())
         return false;
 
     TypeSet::ObjectKey* funKey =
         TypeSet::ObjectKey::get(outerScript->functionNonDelazifying());
     if (funKey->hasFlags(constraints(), OBJECT_FLAG_RUNONCE_INVALIDATED))
         return false;
 
     // The script this aliased var operation is accessing will run only once,
@@ -12735,28 +12656,42 @@ IonBuilder::hasStaticEnvironmentObject(E
     // Look for the call object on the current script's function's env chain.
     // If the current script is inner to the outer script and the function has
     // singleton type then it should show up here.
 
     MDefinition* envDef = current->getSlot(info().environmentChainSlot());
     envDef->setImplicitlyUsedUnchecked();
 
     JSObject* environment = script()->functionNonDelazifying()->environment();
-    if (SearchEnvironmentChainForCallObject(environment, outerScript, pcall))
-        return true;
+    while (environment && !environment->is<GlobalObject>()) {
+        if (environment->is<CallObject>() &&
+            environment->as<CallObject>().callee().nonLazyScript() == outerScript)
+        {
+            MOZ_ASSERT(environment->isSingleton());
+            *pcall = environment;
+            return true;
+        }
+        environment = environment->enclosingEnvironment();
+    }
 
     // Look for the call object on the current frame, if we are compiling the
     // outer script itself. Don't do this if we are at entry to the outer
     // script, as the call object we see will not be the real one --- after
     // entering the Ion code a different call object will be created.
 
     if (script() == outerScript && baselineFrame_ && info().osrPc()) {
         JSObject* singletonScope = baselineFrame_->singletonEnvChain;
-        if (SearchEnvironmentChainForCallObject(singletonScope, outerScript, pcall))
+        if (singletonScope &&
+            singletonScope->is<CallObject>() &&
+            singletonScope->as<CallObject>().callee().nonLazyScript() == outerScript)
+        {
+            MOZ_ASSERT(singletonScope->isSingleton());
+            *pcall = singletonScope;
             return true;
+        }
     }
 
     return true;
 }
 
 MDefinition*
 IonBuilder::getAliasedVar(EnvironmentCoordinate ec)
 {
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -241,18 +241,16 @@ class IonBuilder
     AbortReasonOr<Ok> getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
                                              BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
                                                 BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
                                         BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name,
                                              TemporaryTypeSet* types, bool innerized = false);
-    AbortReasonOr<Ok> getPropTryStaticAccess(bool* emitted, MDefinition* obj, PropertyName* name,
-                                             BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
                                              BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> getPropTryTypedObject(bool* emitted, MDefinition* obj, PropertyName* name);
     AbortReasonOr<Ok> getPropTryScalarPropOfTypedObject(bool* emitted, MDefinition* typedObj,
                                                         int32_t fieldOffset,
                                                         TypedObjectPrediction fieldTypeReprs);
     AbortReasonOr<Ok> getPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* typedObj,
                                                            int32_t fieldOffset,
--- a/js/src/jit/IonIC.cpp
+++ b/js/src/jit/IonIC.cpp
@@ -130,22 +130,21 @@ IonGetPropertyIC::update(JSContext* cx, 
         ic->discardStubs(cx->zone());
 
     bool attached = false;
     if (ic->state().canAttachStub()) {
         // IonBuilder calls PropertyReadNeedsTypeBarrier to determine if it
         // needs a type barrier. Unfortunately, PropertyReadNeedsTypeBarrier
         // does not account for getters, so we should only attach a getter
         // stub if we inserted a type barrier.
-        CanAttachGetter canAttachGetter =
-            ic->monitoredResult() ? CanAttachGetter::Yes : CanAttachGetter::No;
         jsbytecode* pc = ic->idempotent() ? nullptr : ic->pc();
         bool isTemporarilyUnoptimizable = false;
         GetPropIRGenerator gen(cx, outerScript, pc, ic->kind(), ic->state().mode(),
-                               &isTemporarilyUnoptimizable, val, idVal, val, canAttachGetter);
+                               &isTemporarilyUnoptimizable, val, idVal, val,
+                               ic->resultFlags());
         if (ic->idempotent() ? gen.tryAttachIdempotentStub() : gen.tryAttachStub())
             ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
 
         if (!attached && !isTemporarilyUnoptimizable)
             ic->state().trackNotAttached();
     }
 
     if (!attached && ic->idempotent()) {
--- a/js/src/jit/IonIC.h
+++ b/js/src/jit/IonIC.h
@@ -173,47 +173,47 @@ class IonIC
 
     void attachCacheIRStub(JSContext* cx, const CacheIRWriter& writer, CacheKind kind,
                            IonScript* ionScript, bool* attached,
                            const PropertyTypeCheckInfo* typeCheckInfo = nullptr);
 };
 
 class IonGetPropertyIC : public IonIC
 {
+  private:
     LiveRegisterSet liveRegs_;
 
     TypedOrValueRegister value_;
     ConstantOrRegister id_;
     TypedOrValueRegister output_;
     Register maybeTemp_; // Might be InvalidReg.
 
-    bool monitoredResult_ : 1;
-    bool allowDoubleResult_ : 1;
+    GetPropertyResultFlags resultFlags_;
 
   public:
     IonGetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, TypedOrValueRegister value,
                      const ConstantOrRegister& id, TypedOrValueRegister output, Register maybeTemp,
-                     bool monitoredResult, bool allowDoubleResult)
+                     GetPropertyResultFlags resultFlags)
       : IonIC(kind),
         liveRegs_(liveRegs),
         value_(value),
         id_(id),
         output_(output),
         maybeTemp_(maybeTemp),
-        monitoredResult_(monitoredResult),
-        allowDoubleResult_(allowDoubleResult)
+        resultFlags_(resultFlags)
     { }
 
-    bool monitoredResult() const { return monitoredResult_; }
     TypedOrValueRegister value() const { return value_; }
     ConstantOrRegister id() const { return id_; }
     TypedOrValueRegister output() const { return output_; }
     Register maybeTemp() const { return maybeTemp_; }
     LiveRegisterSet liveRegs() const { return liveRegs_; }
-    bool allowDoubleResult() const { return allowDoubleResult_; }
+    GetPropertyResultFlags resultFlags() const { return resultFlags_; }
+    bool monitoredResult() const { return resultFlags_ & GetPropertyResultFlags::Monitored; }
+    bool allowDoubleResult() const { return resultFlags_ & GetPropertyResultFlags::AllowDouble; }
 
     static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonGetPropertyIC* ic,
                                     HandleValue val, HandleValue idVal, MutableHandleValue res);
 };
 
 class IonSetPropertyIC : public IonIC
 {
     LiveRegisterSet liveRegs_;
--- a/js/src/jit/IonInstrumentation.h
+++ b/js/src/jit/IonInstrumentation.h
@@ -4,28 +4,28 @@
  * 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 jit_IonInstrumentatjit_h
 #define jit_IonInstrumentatjit_h
 
 namespace js {
 
-class GeckoProfiler;
+class GeckoProfilerRuntime;
 
 namespace jit {
 
 class MacroAssembler;
 
 typedef GeckoProfilerInstrumentation<MacroAssembler, Register> BaseInstrumentation;
 
 class IonInstrumentation : public BaseInstrumentation
 {
   public:
-    IonInstrumentation(GeckoProfiler* profiler, jsbytecode** pc)
+    IonInstrumentation(GeckoProfilerRuntime* profiler, jsbytecode** pc)
       : BaseInstrumentation(profiler)
     {
         MOZ_ASSERT(pc != nullptr);
     }
 };
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -137,19 +137,16 @@ enum BailoutKind
     Bailout_NonStringInputInvalidate,
 
     // Used for integer division, multiplication and modulo.
     // If there's a remainder, bails to return a double.
     // Can also signal overflow or result of -0.
     // Can also signal division by 0 (returns inf, a double).
     Bailout_DoubleOutput,
 
-    // Load of a value from a static object retrieved an unexpected value.
-    Bailout_LoadStaticObject,
-
     // END Invalid assumptions bailouts
 
 
     // A bailout at the very start of a function indicates that there may be
     // a type mismatch in the arguments that necessitates a reflow.
     Bailout_ArgumentCheck,
 
     // A bailout triggered by a bounds-check failure.
@@ -231,18 +228,16 @@ BailoutKindString(BailoutKind kind)
 
       // Bailouts caused by invalid assumptions.
       case Bailout_OverflowInvalidate:
         return "Bailout_OverflowInvalidate";
       case Bailout_NonStringInputInvalidate:
         return "Bailout_NonStringInputInvalidate";
       case Bailout_DoubleOutput:
         return "Bailout_DoubleOutput";
-      case Bailout_LoadStaticObject:
-        return "Bailout_LoadStaticObject";
 
       // Other bailouts.
       case Bailout_ArgumentCheck:
         return "Bailout_ArgumentCheck";
       case Bailout_BoundsCheck:
         return "Bailout_BoundsCheck";
       case Bailout_Detached:
         return "Bailout_Detached";
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3895,17 +3895,17 @@ LIRGenerator::visitCallBindVar(MCallBind
     define(lir, ins);
 }
 
 void
 LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins)
 {
     LGuardObjectIdentity* guard = new(alloc()) LGuardObjectIdentity(useRegister(ins->object()),
                                                                     useRegister(ins->expected()));
-    assignSnapshot(guard, ins->bailoutKind());
+    assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
     add(guard, ins);
     redefine(ins, ins->object());
 }
 
 void
 LIRGenerator::visitGuardClass(MGuardClass* ins)
 {
     LDefinition t = temp();
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -6192,28 +6192,19 @@ jit::PropertyReadNeedsTypeBarrier(JSCont
             if (obj->unknownProperties())
                 break;
 
             HeapTypeSetKey property = obj->property(NameToId(name));
             if (property.maybeTypes()) {
                 TypeSet::TypeList types;
                 if (!property.maybeTypes()->enumerateTypes(&types))
                     break;
-                // If there is a single possible type for the property,
-                // optimistically add it to the observed set. Don't do this
-                // for the special uninitialized lexical type, which will
-                // never actually be observed here and will cause problems
-                // downstream during compilation.
-                if (types.length() == 1 &&
-                    (!types[0].isPrimitive() ||
-                     types[0].primitive() != JSVAL_TYPE_MAGIC))
-                {
+                if (types.length() == 1) {
                     // Note: the return value here is ignored.
                     observed->addType(types[0], GetJitContext()->temp->lifoAlloc());
-                    break;
                 }
                 break;
             }
 
             if (!obj->proto().isObject())
                 break;
             obj = TypeSet::ObjectKey::get(obj->proto().toObject());
         } while (obj);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11485,47 +11485,39 @@ class MGuardObjectGroup
 };
 
 // Guard on an object's identity, inclusively or exclusively.
 class MGuardObjectIdentity
   : public MBinaryInstruction,
     public SingleObjectPolicy::Data
 {
     bool bailOnEquality_;
-    BailoutKind bailoutKind_;
-
-    MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality,
-                         BailoutKind bailoutKind = Bailout_ObjectIdentityOrTypeGuard)
+
+    MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
       : MBinaryInstruction(obj, expected),
-        bailOnEquality_(bailOnEquality),
-        bailoutKind_(bailoutKind)
+        bailOnEquality_(bailOnEquality)
     {
         setGuard();
         setMovable();
         setResultType(MIRType::Object);
     }
 
   public:
     INSTRUCTION_HEADER(GuardObjectIdentity)
     TRIVIAL_NEW_WRAPPERS
     NAMED_OPERANDS((0, object), (1, expected))
 
     bool bailOnEquality() const {
         return bailOnEquality_;
     }
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
     bool congruentTo(const MDefinition* ins) const override {
         if (!ins->isGuardObjectIdentity())
             return false;
         if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
             return false;
-        if (bailoutKind() != ins->toGuardObjectIdentity()->bailoutKind())
-            return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Guard on an object's class.
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -2064,17 +2064,18 @@ DoGetPropFallback(JSContext* cx, Baselin
 
     if (stub->state().maybeTransition())
         stub->discardStubs(cx);
 
     bool attached = false;
     if (stub->state().canAttachStub()) {
         RootedValue idVal(cx, StringValue(name));
         GetPropIRGenerator gen(cx, script, pc, CacheKind::GetProp, stub->state().mode(),
-                               &isTemporarilyUnoptimizable, val, idVal, val, CanAttachGetter::Yes);
+                               &isTemporarilyUnoptimizable, val, idVal, val,
+                               GetPropertyResultFlags::All);
         if (gen.tryAttachStub()) {
             ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
                                                         BaselineCacheIRStubKind::Monitored,
                                                         ICStubEngine::Baseline, script,
                                                         stub, &attached);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 if (gen.shouldNotePreliminaryObjectStub())
@@ -2135,17 +2136,17 @@ DoGetPropSuperFallback(JSContext* cx, Ba
     if (stub->state().maybeTransition())
         stub->discardStubs(cx);
 
     bool attached = false;
     if (stub->state().canAttachStub()) {
         RootedValue idVal(cx, StringValue(name));
         GetPropIRGenerator gen(cx, script, pc, CacheKind::GetPropSuper, stub->state().mode(),
                                &isTemporarilyUnoptimizable, val, idVal, receiver,
-                               CanAttachGetter::Yes);
+                               GetPropertyResultFlags::All);
         if (gen.tryAttachStub()) {
             ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
                                                         BaselineCacheIRStubKind::Monitored,
                                                         ICStubEngine::Baseline, script,
                                                         stub, &attached);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 if (gen.shouldNotePreliminaryObjectStub())
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -28,17 +28,17 @@ static const FloatRegisterSet NonVolatil
                      (1ULL << FloatRegisters::d10) |
                      (1ULL << FloatRegisters::d11) |
                      (1ULL << FloatRegisters::d12) |
                      (1ULL << FloatRegisters::d13) |
                      (1ULL << FloatRegisters::d14) |
                      (1ULL << FloatRegisters::d15));
 
 static void
-GenerateReturn(MacroAssembler& masm, int returnCode, GeckoProfiler* prof)
+GenerateReturn(MacroAssembler& masm, int returnCode)
 {
     // Restore non-volatile floating point registers.
     masm.transferMultipleByRuns(NonVolatileFloatRegs, IsLoad, StackPointer, IA);
 
     // Get rid of padding word.
     masm.addPtr(Imm32(sizeof(void*)), sp);
 
     // Set up return value
@@ -372,17 +372,17 @@ JitRuntime::generateEnterJIT(JSContext* 
     // :TODO: Optimize storeValue with:
     // We're using a load-double here. In order for that to work, the data needs
     // to be stored in two consecutive registers, make sure this is the case
     //   MOZ_ASSERT(JSReturnReg_Type.code() == JSReturnReg_Data.code()+1);
     //   aasm->as_extdtr(IsStore, 64, true, Offset,
     //                   JSReturnReg_Data, EDtrAddr(r5, EDtrOffImm(0)));
 
     // Restore non-volatile registers and return.
-    GenerateReturn(masm, true, &cx->runtime()->geckoProfiler());
+    GenerateReturn(masm, true);
 
     Linker linker(masm);
     AutoFlushICache afc("EnterJIT");
     JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
 
 #ifdef JS_ION_PERF
     writePerfSpewerJitCodeProfile(code, "EnterJIT");
 #endif
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1025,16 +1025,33 @@ JS_ResumeCooperativeContext(JSContext* c
 
 // Create a new context on this thread for cooperative multithreading in the
 // same runtime as siblingContext. Called on a runtime (as indicated by
 // siblingContet) which has no active context, on success the new context will
 // become the runtime's active context.
 extern JS_PUBLIC_API(JSContext*)
 JS_NewCooperativeContext(JSContext* siblingContext);
 
+namespace JS {
+
+// Class to relinquish exclusive access to all zone groups in use by this
+// thread. This allows other cooperative threads to enter the zone groups
+// and modify their contents.
+struct AutoRelinquishZoneGroups
+{
+    explicit AutoRelinquishZoneGroups(JSContext* cx);
+    ~AutoRelinquishZoneGroups();
+
+  private:
+    JSContext* cx;
+    mozilla::Vector<void*> enterList;
+};
+
+} // namespace JS
+
 // Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext.
 // The context must be the current active context in the runtime, and after
 // this call the runtime will have no active context.
 extern JS_PUBLIC_API(void)
 JS_DestroyContext(JSContext* cx);
 
 JS_PUBLIC_API(void*)
 JS_GetContextPrivate(JSContext* cx);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1318,17 +1318,17 @@ ArrayJoinKernel(JSContext* cx, Separator
 // ES2017 draft rev 1b0184bc17fc09a8ddcf4aeec9b6d9fcac4eafce
 // 22.1.3.13 Array.prototype.join ( separator )
 bool
 js::array_join(JSContext* cx, unsigned argc, Value* vp)
 {
     if (!CheckRecursionLimit(cx))
         return false;
 
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.join");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.join");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     AutoCycleDetector detector(cx, obj);
@@ -1578,17 +1578,17 @@ ArrayReverseDenseKernel(JSContext* cx, H
 DefineBoxedOrUnboxedFunctor3(ArrayReverseDenseKernel,
                              JSContext*, HandleObject, uint32_t);
 
 // ES2017 draft rev 1b0184bc17fc09a8ddcf4aeec9b6d9fcac4eafce
 // 22.1.3.21 Array.prototype.reverse ( )
 bool
 js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.reverse");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.reverse");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     // Step 2.
@@ -2283,17 +2283,17 @@ js::NewbornArrayPush(JSContext* cx, Hand
     return true;
 }
 
 // ES2017 draft rev 1b0184bc17fc09a8ddcf4aeec9b6d9fcac4eafce
 // 22.1.3.18 Array.prototype.push ( ...items )
 bool
 js::array_push(JSContext* cx, unsigned argc, Value* vp)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.push");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.push");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     // Step 2.
@@ -2340,17 +2340,17 @@ js::array_push(JSContext* cx, unsigned a
     return SetLengthProperty(cx, obj, newlength);
 }
 
 // ES2017 draft rev 1b0184bc17fc09a8ddcf4aeec9b6d9fcac4eafce
 // 22.1.3.17 Array.prototype.pop ( )
 bool
 js::array_pop(JSContext* cx, unsigned argc, Value* vp)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.pop");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.pop");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     // Step 2.
@@ -2445,17 +2445,17 @@ ArrayShiftDenseKernel(JSContext* cx, Han
 DefineBoxedOrUnboxedFunctor3(ArrayShiftDenseKernel,
                              JSContext*, HandleObject, MutableHandleValue);
 
 // ES2017 draft rev 1b0184bc17fc09a8ddcf4aeec9b6d9fcac4eafce
 // 22.1.3.22 Array.prototype.shift ( )
 bool
 js::array_shift(JSContext* cx, unsigned argc, Value* vp)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.shift");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.shift");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     // Step 2.
@@ -2521,17 +2521,17 @@ js::array_shift(JSContext* cx, unsigned 
     return SetLengthProperty(cx, obj, newlen);
 }
 
 // ES2017 draft rev 1b0184bc17fc09a8ddcf4aeec9b6d9fcac4eafce
 // 22.1.3.29 Array.prototype.unshift ( ...items )
 bool
 js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.unshift");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.unshift");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     // Step 2.
@@ -2764,17 +2764,17 @@ CopyArrayElements(JSContext* cx, HandleO
             return false;
     }
     return true;
 }
 
 static bool
 array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.splice");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.splice");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2. */
@@ -3272,17 +3272,17 @@ ArraySliceOrdinary(JSContext* cx, Handle
     rval.setObject(*narr);
     return true;
 }
 
 /* ES 2016 draft Mar 25, 2016 22.1.3.23. */
 bool
 js::array_slice(JSContext* cx, unsigned argc, Value* vp)
 {
-    AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.slice");
+    AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.slice");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2. */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1585,16 +1585,17 @@ JSContext::sizeOfExcludingThis(mozilla::
      */
     return cycleDetectorVector().sizeOfExcludingThis(mallocSizeOf);
 }
 
 void
 JSContext::trace(JSTracer* trc)
 {
     cycleDetectorVector().trace(trc);
+    geckoProfiler().trace(trc);
 
     if (trc->isMarkingTracer() && compartment_)
         compartment_->mark();
 }
 
 void*
 JSContext::stackLimitAddressForJitCode(JS::StackKind kind)
 {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -385,19 +385,16 @@ struct JSContext : public JS::RootingCon
     }
     static size_t offsetOfActivation() {
         return offsetof(JSContext, activation_);
     }
 
     js::Activation* profilingActivation() const {
         return profilingActivation_;
     }
-    void* addressOfProfilingActivation() {
-        return (void*) &profilingActivation_;
-    }
     static size_t offsetOfProfilingActivation() {
         return offsetof(JSContext, profilingActivation_);
      }
 
   private:
     /* Space for interpreter frames. */
     js::ThreadLocalData<js::InterpreterStack> interpreterStack_;
 
@@ -598,16 +595,22 @@ struct JSContext : public JS::RootingCon
     }
     void disableProfilerSampling() {
         suppressProfilerSampling = true;
     }
     void enableProfilerSampling() {
         suppressProfilerSampling = false;
     }
 
+  private:
+    /* Gecko profiling metadata */
+    js::UnprotectedData<js::GeckoProfilerThread> geckoProfiler_;
+  public:
+    js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_.ref(); }
+
 #if defined(XP_DARWIN)
     js::wasm::MachExceptionHandler wasmMachExceptionHandler;
 #endif
 
     /* Temporary arena pool used while compiling and decompiling. */
     static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
   private:
     js::ThreadLocalData<js::LifoAlloc> tempLifoAlloc_;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -6211,17 +6211,17 @@ AllNurseriesAreEmpty(JSRuntime* rt)
 }
 #endif
 
 /* Start a new heap session. */
 AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
   : lock(rt),
     runtime(rt),
     prevState(TlsContext.get()->heapState),
-    pseudoFrame(rt, HeapStateToLabel(heapState), ProfileEntry::Category::GC)
+    pseudoFrame(TlsContext.get(), HeapStateToLabel(heapState), ProfileEntry::Category::GC)
 {
     MOZ_ASSERT(prevState == JS::HeapState::Idle);
     MOZ_ASSERT(heapState != JS::HeapState::Idle);
     MOZ_ASSERT_IF(heapState == JS::HeapState::MajorCollecting, AllNurseriesAreEmpty(rt));
     TlsContext.get()->heapState = heapState;
 }
 
 AutoTraceSession::~AutoTraceSession()
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -24,21 +24,16 @@ JS_PUBLIC_API(JS::UniqueChars) JS_smprin
 {
     va_list ap;
     va_start(ap, fmt);
     JSSmprintfPointer result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
     va_end(ap);
     return JS::UniqueChars(result.release());
 }
 
-JS_PUBLIC_API(void) JS_smprintf_free(char* mem)
-{
-    mozilla::SmprintfFree<js::SystemAllocPolicy>(mem);
-}
-
 JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last, const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
     JSSmprintfPointer lastPtr(last.release());
     JSSmprintfPointer result =
         mozilla::VsmprintfAppend<js::SystemAllocPolicy>(Move(lastPtr), fmt, ap);
     va_end(ap);
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -15,18 +15,16 @@
 #include "js/Utility.h"
 
 /* Wrappers for mozilla::Smprintf and friends that are used throughout
    JS.  */
 
 extern JS_PUBLIC_API(JS::UniqueChars) JS_smprintf(const char* fmt, ...)
     MOZ_FORMAT_PRINTF(1, 2);
 
-extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem);
-
 extern JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last,
                                                         const char* fmt, ...)
      MOZ_FORMAT_PRINTF(2, 3);
 
 extern JS_PUBLIC_API(JS::UniqueChars) JS_vsmprintf(const char* fmt, va_list ap)
     MOZ_FORMAT_PRINTF(1, 0);
 extern JS_PUBLIC_API(JS::UniqueChars) JS_vsprintf_append(JS::UniqueChars&& last,
                                                          const char* fmt, va_list ap)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -4194,34 +4194,37 @@ JSScript::argumentsOptimizationFailed(JS
      * MagicValue(JS_OPTIMIZED_ARGUMENTS) on the stack. However, there are
      * three things that need fixup:
      *  - there may be any number of activations of this script that don't have
      *    an argsObj that now need one.
      *  - jit code compiled (and possible active on the stack) with the static
      *    assumption of !script->needsArgsObj();
      *  - type inference data for the script assuming script->needsArgsObj
      */
-    for (AllScriptFramesIter i(cx); !i.done(); ++i) {
-        /*
-         * We cannot reliably create an arguments object for Ion activations of
-         * this script.  To maintain the invariant that "script->needsArgsObj
-         * implies fp->hasArgsObj", the Ion bail mechanism will create an
-         * arguments object right after restoring the BaselineFrame and before
-         * entering Baseline code (in jit::FinishBailoutToBaseline).
-         */
-        if (i.isIon())
-            continue;
-        AbstractFramePtr frame = i.abstractFramePtr();
-        if (frame.isFunctionFrame() && frame.script() == script) {
-            /* We crash on OOM since cleaning up here would be complicated. */
-            AutoEnterOOMUnsafeRegion oomUnsafe;
-            ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
-            if (!argsobj)
-                oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
-            SetFrameArgumentsObject(cx, frame, script, argsobj);
+    JSRuntime::AutoProhibitActiveContextChange apacc(cx->runtime());
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        for (AllScriptFramesIter i(cx, target); !i.done(); ++i) {
+            /*
+             * We cannot reliably create an arguments object for Ion activations of
+             * this script.  To maintain the invariant that "script->needsArgsObj
+             * implies fp->hasArgsObj", the Ion bail mechanism will create an
+             * arguments object right after restoring the BaselineFrame and before
+             * entering Baseline code (in jit::FinishBailoutToBaseline).
+             */
+            if (i.isIon())
+                continue;
+            AbstractFramePtr frame = i.abstractFramePtr();
+            if (frame.isFunctionFrame() && frame.script() == script) {
+                /* We crash on OOM since cleaning up here would be complicated. */
+                AutoEnterOOMUnsafeRegion oomUnsafe;
+                ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
+                if (!argsobj)
+                    oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
+                SetFrameArgumentsObject(cx, frame, script, argsobj);
+            }
         }
     }
 
     return true;
 }
 
 bool
 JSScript::formalIsAliased(unsigned argSlot)
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -67,20 +67,16 @@ MOZ_DEFAULT_COMPILER
 
 if test -z "$JS_STANDALONE"; then
   autoconfmk=autoconf-js.mk
 fi
 AC_SUBST(autoconfmk)
 
 MOZ_ANDROID_NDK
 
-if test -n "$gonkdir" ; then
-    LDFLAGS="-L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ -llog $LDFLAGS"
-fi
-
 case "$target" in
 *-apple-darwin*)
     MOZ_IOS_SDK
     ;;
 esac
 
 dnl ========================================================
 dnl Checks for compilers.
@@ -465,26 +461,24 @@ if test "$GNU_CC"; then
     LDFLAGS="$LDFLAGS -Wl,-z,noexecstack"
     AC_TRY_LINK(,,AC_MSG_RESULT([yes]),
                   AC_MSG_RESULT([no])
                   LDFLAGS=$_SAVE_LDFLAGS)
 
     AC_MSG_CHECKING([for -z text option to ld])
     _SAVE_LDFLAGS=$LDFLAGS
     LDFLAGS="$LDFLAGS -Wl,-z,text"
-    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
-                  [NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,-z,text"],
+    AC_TRY_LINK(,,AC_MSG_RESULT([yes]),
                   AC_MSG_RESULT([no])
                   LDFLAGS=$_SAVE_LDFLAGS)
 
     AC_MSG_CHECKING([for --build-id option to ld])
     _SAVE_LDFLAGS=$LDFLAGS
     LDFLAGS="$LDFLAGS -Wl,--build-id"
-    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
-                  [NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,--build-id"],
+    AC_TRY_LINK(,,AC_MSG_RESULT([yes]),
                   AC_MSG_RESULT([no])
                   LDFLAGS=$_SAVE_LDFLAGS)
 
     _DEFINES_CFLAGS='-include $(topobjdir)/js/src/js-confdefs.h -DMOZILLA_CLIENT'
     _USE_CPP_INCLUDE_FLAG=1
 fi
 
 if test "$GNU_CXX"; then
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1483,18 +1483,17 @@ Evaluate(JSContext* cx, unsigned argc, V
     bool saveIncrementalBytecode = false;
     bool assertEqBytecode = false;
     RootedObject callerGlobal(cx, cx->global());
 
     options.setIntroductionType("js shell evaluate")
            .setFileAndLine("@evaluate", 1);
 
     global = JS_GetGlobalForObject(cx, &args.callee());
-    if (!global)
-        return false;
+    MOZ_ASSERT(global);
 
     if (args.length() == 2) {
         RootedObject opts(cx, &args[1].toObject());
         RootedValue v(cx);
 
         if (!ParseCompileOptions(cx, options, opts, fileNameBytes))
             return false;
 
@@ -1524,16 +1523,51 @@ Evaluate(JSContext* cx, unsigned argc, V
             }
             if (!global || !(JS_GetClass(global)->flags & JSCLASS_IS_GLOBAL)) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
                                           "\"global\" passed to evaluate()", "not a global object");
                 return false;
             }
         }
 
+        if (!JS_GetProperty(cx, opts, "zoneGroup", &v))
+            return false;
+        if (!v.isUndefined()) {
+            if (global != JS_GetGlobalForObject(cx, &args.callee())) {
+                JS_ReportErrorASCII(cx, "zoneGroup and global cannot both be specified.");
+                return false;
+            }
+
+            // Find all eligible globals to execute in: any global in another
+            // zone group which has not been entered by a cooperative thread.
+            JS::AutoObjectVector eligibleGlobals(cx);
+            for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
+                if (!c->zone()->group()->ownerContext().context() &&
+                    c->maybeGlobal() &&
+                    !cx->runtime()->isSelfHostingGlobal(c->maybeGlobal()))
+                {
+                    if (!eligibleGlobals.append(c->maybeGlobal()))
+                        return false;
+                }
+            }
+
+            if (eligibleGlobals.empty()) {
+                JS_ReportErrorASCII(cx, "zoneGroup can only be used if another"
+                                    " cooperative thread has called cooperativeYield(true).");
+                return false;
+            }
+
+            // Pick an eligible global to use based on the value of the zoneGroup property.
+            int32_t which;
+            if (!ToInt32(cx, v, &which))
+                return false;
+            which = Min<int32_t>(Max(which, 0), eligibleGlobals.length() - 1);
+            global = eligibleGlobals[which];
+        }
+
         if (!JS_GetProperty(cx, opts, "catchTermination", &v))
             return false;
         if (!v.isUndefined())
             catchTermination = ToBoolean(v);
 
         if (!JS_GetProperty(cx, opts, "loadBytecode", &v))
             return false;
         if (!v.isUndefined())
@@ -3290,19 +3324,39 @@ CooperativeYieldThread(JSContext* cx, un
         return false;
     }
 
     if (cooperationState->singleThreaded) {
         JS_ReportErrorASCII(cx, "Yielding is not allowed while single threaded");
         return false;
     }
 
-    CooperativeBeginWait(cx);
-    CooperativeYield();
-    CooperativeEndWait(cx);
+    // To avoid contention issues between threads, yields are not allowed while
+    // a thread has access to zone groups other than its original one, i.e. if
+    // the thread is inside an evaluate() call with a different zone group.
+    // This is not a limit which the browser has, but is necessary in the
+    // shell: the shell can have arbitrary interleavings between cooperative
+    // threads, whereas the browser has more control over which threads are
+    // running at different times.
+    for (ZoneGroupsIter group(cx->runtime()); !group.done(); group.next()) {
+        if (group->ownerContext().context() == cx && group != cx->zone()->group()) {
+            JS_ReportErrorASCII(cx, "Yielding is not allowed while owning multiple zone groups");
+            return false;
+        }
+    }
+
+    {
+        Maybe<JS::AutoRelinquishZoneGroups> artzg;
+        if ((args.length() > 0) && ToBoolean(args[0]))
+            artzg.emplace(cx);
+
+        CooperativeBeginWait(cx);
+        CooperativeYield();
+        CooperativeEndWait(cx);
+    }
 
     args.rval().setUndefined();
     return true;
 }
 
 static void
 CooperativeBeginSingleThreadedExecution(JSContext* cx)
 {
@@ -3327,16 +3381,35 @@ CooperativeBeginSingleThreadedExecution(
 
 static void
 CooperativeEndSingleThreadedExecution(JSContext* cx)
 {
     if (cooperationState)
         cooperationState->singleThreaded = false;
 }
 
+static bool
+EnsureGeckoProfilingStackInstalled(JSContext* cx, ShellContext* sc)
+{
+    if (cx->geckoProfiler().installed()) {
+        MOZ_ASSERT(sc->geckoProfilingStack);
+        return true;
+    }
+
+    MOZ_ASSERT(!sc->geckoProfilingStack);
+    sc->geckoProfilingStack = MakeUnique<PseudoStack>();
+    if (!sc->geckoProfilingStack) {
+        JS_ReportOutOfMemory(cx);
+        return false;
+    }
+
+    SetContextProfilingStack(cx, sc->geckoProfilingStack.get());
+    return true;
+}
+
 struct WorkerInput
 {
     JSRuntime* parentRuntime;
     JSContext* siblingContext;
     char16_t* chars;
     size_t length;
 
     WorkerInput(JSRuntime* parentRuntime, char16_t* chars, size_t length)
@@ -3395,16 +3468,20 @@ WorkerMain(void* arg)
         js::UseInternalJobQueues(cx);
 
         if (!JS::InitSelfHostedCode(cx))
             return;
 
         environmentPreparer.emplace(cx);
     } else {
         JS_AddInterruptCallback(cx, ShellInterruptCallback);
+
+        // The Gecko Profiler requires that all cooperating contexts have
+        // profiling stacks installed.
+        MOZ_ALWAYS_TRUE(EnsureGeckoProfilingStackInstalled(cx, sc.get()));
     }
 
     do {
         JSAutoRequest ar(cx);
 
         JS::CompartmentOptions compartmentOptions;
         SetStandardCompartmentOptions(compartmentOptions);
         if (input->siblingContext)
@@ -3425,21 +3502,16 @@ WorkerMain(void* arg)
         if (!JS::Compile(cx, options, input->chars, input->length, &script))
             break;
         RootedValue result(cx);
         JS_ExecuteScript(cx, script, &result);
     } while (0);
 
     KillWatchdog(cx);
     JS_SetGrayGCRootsTracer(cx, nullptr, nullptr);
-
-    if (sc->geckoProfilingStack) {
-        MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false));
-        SetContextProfilingStack(cx, nullptr);
-    }
 }
 
 // Workers can spawn other workers, so we need a lock to access workerThreads.
 static Mutex* workerThreadsLock = nullptr;
 static Vector<js::Thread*, 0, SystemAllocPolicy> workerThreads;
 
 class MOZ_RAII AutoLockWorkerThreads : public LockGuard<Mutex>
 {
@@ -5205,116 +5277,80 @@ static bool
 IsLatin1(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     bool isLatin1 = args.get(0).isString() && args[0].toString()->hasLatin1Chars();
     args.rval().setBoolean(isLatin1);
     return true;
 }
 
-static bool
-EnsureGeckoProfilingStackInstalled(JSContext* cx, ShellContext* sc)
-{
-    if (cx->runtime()->geckoProfiler().installed()) {
-        if (!sc->geckoProfilingStack) {
-            JS_ReportErrorASCII(cx, "Profiler already installed by another context");
-            return false;
-        }
-
-        return true;
-    }
-
-    MOZ_ASSERT(!sc->geckoProfilingStack);
-    sc->geckoProfilingStack = MakeUnique<PseudoStack>();
-    if (!sc->geckoProfilingStack) {
-        JS_ReportOutOfMemory(cx);
-        return false;
-    }
-
-    SetContextProfilingStack(cx, sc->geckoProfilingStack.get());
+// Set the profiling stack for each cooperating context in a runtime.
+static bool
+EnsureAllContextProfilingStacks(JSContext* cx)
+{
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        ShellContext* sc = GetShellContext(target.context());
+        if (!EnsureGeckoProfilingStackInstalled(target.context(), sc))
+            return false;
+    }
+
     return true;
 }
 
 static bool
 EnableGeckoProfiling(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    ShellContext* sc = GetShellContext(cx);
-
-    if (!EnsureGeckoProfilingStackInstalled(cx, sc))
-        return false;
-
-    // Disable before re-enabling; see the assertion in
-    // |GeckoProfiler::setProfilingStack|.
-    if (cx->runtime()->geckoProfiler().installed())
-        MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false));
+    if (!EnsureAllContextProfilingStacks(cx))
+        return false;
 
     cx->runtime()->geckoProfiler().enableSlowAssertions(false);
-    if (!cx->runtime()->geckoProfiler().enable(true)) {
-        JS_ReportErrorASCII(cx, "Cannot ensure single threaded execution in profiler");
-        return false;
-    }
+    cx->runtime()->geckoProfiler().enable(true);
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 EnableGeckoProfilingWithSlowAssertions(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setUndefined();
 
-    ShellContext* sc = GetShellContext(cx);
-
-    if (!EnsureGeckoProfilingStackInstalled(cx, sc))
-        return false;
-
     if (cx->runtime()->geckoProfiler().enabled()) {
         // If profiling already enabled with slow assertions disabled,
         // this is a no-op.
         if (cx->runtime()->geckoProfiler().slowAssertionsEnabled())
             return true;
 
         // Slow assertions are off.  Disable profiling before re-enabling
         // with slow assertions on.
-        MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false));
-    }
-
-    // Disable before re-enabling; see the assertion in |GeckoProfiler::setProfilingStack|.
-    if (cx->runtime()->geckoProfiler().installed())
-        MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false));
+        cx->runtime()->geckoProfiler().enable(false);
+    }
+
+    if (!EnsureAllContextProfilingStacks(cx))
+        return false;
 
     cx->runtime()->geckoProfiler().enableSlowAssertions(true);
-    if (!cx->runtime()->geckoProfiler().enable(true)) {
-        JS_ReportErrorASCII(cx, "Cannot ensure single threaded execution in profiler");
-        return false;
-    }
+    cx->runtime()->geckoProfiler().enable(true);
 
     return true;
 }
 
 static bool
 DisableGeckoProfiling(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setUndefined();
 
-    ShellContext* sc = GetShellContext(cx);
-
-    if (!cx->runtime()->geckoProfiler().installed())
+    if (!cx->runtime()->geckoProfiler().enabled())
         return true;
 
-    if (!sc->geckoProfilingStack) {
-        JS_ReportErrorASCII(cx, "Profiler was not installed by this context");
-        return false;
-    }
-
-    MOZ_ALWAYS_TRUE(cx->runtime()->geckoProfiler().enable(false));
+    cx->runtime()->geckoProfiler().enable(false);
     return true;
 }
 
 // Global mailbox that is used to communicate a SharedArrayBuffer
 // value from one worker to another.
 //
 // For simplicity we store only the SharedArrayRawBuffer; retaining
 // the SAB object would require per-runtime storage, and would have no
@@ -6148,16 +6184,18 @@ static const JSFunctionSpecWithHelp shel
 "  Evaluate code as though it were the contents of a file.\n"
 "  options is an optional object that may have these properties:\n"
 "      isRunOnce: use the isRunOnce compiler option (default: false)\n"
 "      noScriptRval: use the no-script-rval compiler option (default: false)\n"
 "      fileName: filename for error messages and debug info\n"
 "      lineNumber: starting line number for error messages and debug info\n"
 "      columnNumber: starting column number for error messages and debug info\n"
 "      global: global in which to execute the code\n"
+"      zoneGroup: pick a global from another zone group with no current context\n"
+"         to execute the code in\n"
 "      newContext: if true, create and use a new cx (default: false)\n"
 "      catchTermination: if true, catch termination (failure without\n"
 "         an exception value, as for slow scripts or out-of-memory)\n"
 "         and return 'terminated'\n"
 "      element: if present with value |v|, convert |v| to an object |o| and\n"
 "         mark the source as being attached to the DOM element |o|. If the\n"
 "         property is omitted or |v| is null, don't attribute the source to\n"
 "         any DOM element.\n"
@@ -6286,19 +6324,21 @@ static const JSFunctionSpecWithHelp shel
     JS_FN_HELP("evalInWorker", EvalInWorker, 1, 0,
 "evalInWorker(str)",
 "  Evaluate 'str' in a separate thread with its own runtime.\n"),
 
     JS_FN_HELP("evalInCooperativeThread", EvalInCooperativeThread, 1, 0,
 "evalInCooperativeThread(str)",
 "  Evaluate 'str' in a separate cooperatively scheduled thread using the same runtime.\n"),
 
-    JS_FN_HELP("cooperativeYield", CooperativeYieldThread, 0, 0,
-"evalInCooperativeThread()",
-"  Yield execution to another cooperatively scheduled thread using the same runtime.\n"),
+    JS_FN_HELP("cooperativeYield", CooperativeYieldThread, 1, 0,
+"cooperativeYield(leaveZoneGroup)",
+"  Yield execution to another cooperatively scheduled thread using the same runtime.\n"
+"  If leaveZoneGroup is specified then other threads may execute code in the\n"
+"  current thread's zone group via evaluate(..., {zoneGroup:N}).\n"),
 
     JS_FN_HELP("getSharedArrayBuffer", GetSharedArrayBuffer, 0, 0,
 "getSharedArrayBuffer()",
 "  Retrieve the SharedArrayBuffer object from the cross-worker mailbox.\n"
 "  The object retrieved may not be identical to the object that was\n"
 "  installed, but it references the same shared memory.\n"
 "  getSharedArrayBuffer performs an ordering memory barrier.\n"),
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2590,31 +2590,33 @@ UpdateExecutionObservabilityOfScriptsInZ
         }
     }
 
     // Code below this point must be infallible to ensure the active bit of
     // BaselineScripts is in a consistent state.
     //
     // Mark active baseline scripts in the observable set so that they don't
     // get discarded. They will be recompiled.
-    for (JitActivationIterator actIter(cx, zone->group()->ownerContext()); !actIter.done(); ++actIter) {
-        if (actIter->compartment()->zone() != zone)
-            continue;
-
-        for (JitFrameIterator iter(actIter); !iter.done(); ++iter) {
-            switch (iter.type()) {
-              case JitFrame_BaselineJS:
-                MarkBaselineScriptActiveIfObservable(iter.script(), obs);
-                break;
-              case JitFrame_IonJS:
-                MarkBaselineScriptActiveIfObservable(iter.script(), obs);
-                for (InlineFrameIterator inlineIter(cx, &iter); inlineIter.more(); ++inlineIter)
-                    MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
-                break;
-              default:;
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        for (JitActivationIterator actIter(cx, target); !actIter.done(); ++actIter) {
+            if (actIter->compartment()->zone() != zone)
+                continue;
+
+            for (JitFrameIterator iter(actIter); !iter.done(); ++iter) {
+                switch (iter.type()) {
+                  case JitFrame_BaselineJS:
+                    MarkBaselineScriptActiveIfObservable(iter.script(), obs);
+                    break;
+                  case JitFrame_IonJS:
+                    MarkBaselineScriptActiveIfObservable(iter.script(), obs);
+                    for (InlineFrameIterator inlineIter(cx, &iter); inlineIter.more(); ++inlineIter)
+                        MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
+                    break;
+                  default:;
+                }
             }
         }
     }
 
     // Iterate through the scripts again and finish discarding
     // BaselineScripts. This must be done as a separate phase as we can only
     // discard the BaselineScript on scripts that have no IonScript.
     for (size_t i = 0; i < scripts.length(); i++) {
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -3242,17 +3242,18 @@ js::GetThisValueForDebuggerMaybeOptimize
                 res.setMagic(JS_OPTIMIZED_OUT);
 
             return true;
         }
 
         MOZ_CRASH("'this' binding must be found");
     }
 
-    return GetNonSyntacticGlobalThis(cx, scopeChain, res);
+    GetNonSyntacticGlobalThis(cx, scopeChain, res);
+    return true;
 }
 
 bool
 js::CheckLexicalNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
                              HandleObject varObj, HandlePropertyName name)
 {
     const char* redeclKind = nullptr;
     RootedId id(cx, NameToId(name));
--- a/js/src/vm/GeckoProfiler-inl.h
+++ b/js/src/vm/GeckoProfiler-inl.h
@@ -4,20 +4,36 @@
  * 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 vm_GeckoProfiler_inl_h
 #define vm_GeckoProfiler_inl_h
 
 #include "vm/GeckoProfiler.h"
 
+#include "jscntxt.h"
+
 #include "vm/Runtime.h"
 
 namespace js {
 
+inline void
+GeckoProfilerThread::updatePC(JSContext* cx, JSScript* script, jsbytecode* pc)
+{
+    if (!cx->runtime()->geckoProfiler().enabled())
+        return;
+
+    uint32_t sp = pseudoStack_->stackPointer;
+    if (sp - 1 < PseudoStack::MaxEntries) {
+        MOZ_ASSERT(sp > 0);
+        MOZ_ASSERT(pseudoStack_->entries[sp - 1].rawScript() == script);
+        pseudoStack_->entries[sp - 1].setPC(pc);
+    }
+}
+
 /*
  * This class is used to suppress profiler sampling during
  * critical sections where stack state is not valid.
  */
 class MOZ_RAII AutoSuppressProfilerSampling
 {
   public:
     explicit AutoSuppressProfilerSampling(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
--- a/js/src/vm/GeckoProfiler.cpp
+++ b/js/src/vm/GeckoProfiler.cpp
@@ -20,48 +20,49 @@
 #include "vm/StringBuffer.h"
 
 #include "jsgcinlines.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
 
-GeckoProfiler::GeckoProfiler(JSRuntime* rt)
+GeckoProfilerThread::GeckoProfilerThread()
+  : pseudoStack_(nullptr)
+{
+}
+
+GeckoProfilerRuntime::GeckoProfilerRuntime(JSRuntime* rt)
   : rt(rt),
     strings(mutexid::GeckoProfilerStrings),
-    pseudoStack_(nullptr),
     slowAssertions(false),
     enabled_(false),
     eventMarker_(nullptr)
 {
     MOZ_ASSERT(rt != nullptr);
 }
 
 bool
-GeckoProfiler::init()
+GeckoProfilerRuntime::init()
 {
     auto locked = strings.lock();
     if (!locked->init())
         return false;
 
     return true;
 }
 
 void
-GeckoProfiler::setProfilingStack(PseudoStack* pseudoStack)
+GeckoProfilerThread::setProfilingStack(PseudoStack* pseudoStack)
 {
-    MOZ_ASSERT_IF(pseudoStack_, !enabled());
-    MOZ_ASSERT(strings.lock()->initialized());
-
     pseudoStack_ = pseudoStack;
 }
 
 void
-GeckoProfiler::setEventMarker(void (*fn)(const char*))
+GeckoProfilerRuntime::setEventMarker(void (*fn)(const char*))
 {
     eventMarker_ = fn;
 }
 
 /* Get a pointer to the top-most profiling frame, given the exit frame pointer. */
 static void*
 GetTopProfilingJitFrame(Activation* act)
 {
@@ -73,34 +74,29 @@ GetTopProfilingJitFrame(Activation* act)
     if (!exitFP)
         return nullptr;
 
     jit::JitProfilingFrameIterator iter(exitFP);
     MOZ_ASSERT(!iter.done());
     return iter.fp();
 }
 
-bool
-GeckoProfiler::enable(bool enabled)
+void
+GeckoProfilerRuntime::enable(bool enabled)
 {
-    MOZ_ASSERT(installed());
+#ifdef DEBUG
+    // All cooperating contexts must have profile stacks installed before the
+    // profiler can be enabled. Cooperating threads created while the profiler
+    // is enabled must have stacks set before they execute any JS.
+    for (const CooperatingContext& target : rt->cooperatingContexts())
+        MOZ_ASSERT(target.context()->geckoProfiler().installed());
+#endif
 
     if (enabled_ == enabled)
-        return true;
-
-    // Execution in the runtime must be single threaded if the Gecko profiler
-    // is enabled. There is only a single profiler stack in the runtime, from
-    // which entries must be added/removed in a LIFO fashion.
-    JSContext* cx = rt->activeContextFromOwnThread();
-    if (enabled) {
-        if (!rt->beginSingleThreadedExecution(cx))
-            return false;
-    } else {
-        rt->endSingleThreadedExecution(cx);
-    }
+        return;
 
     /*
      * Ensure all future generated code will be instrumented, or that all
      * currently instrumented code is discarded
      */
     ReleaseAllJITCode(rt->defaultFreeOp());
 
     // This function is called when the Gecko profiler makes a new Sampler
@@ -158,69 +154,67 @@ GeckoProfiler::enable(bool enabled)
         }
     }
 
     // WebAssembly code does not need to be released, but profiling string
     // labels have to be generated so that they are available during async
     // profiling stack iteration.
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
         c->wasm.ensureProfilingLabels(enabled);
-
-    return true;
 }
 
 /* Lookup the string for the function/script, creating one if necessary */
 const char*
-GeckoProfiler::profileString(JSScript* script, JSFunction* maybeFun)
+GeckoProfilerRuntime::profileString(JSScript* script, JSFunction* maybeFun)
 {
     auto locked = strings.lock();
     MOZ_ASSERT(locked->initialized());
 
     ProfileStringMap::AddPtr s = locked->lookupForAdd(script);
 
     if (!s) {
         auto str = allocProfileString(script, maybeFun);
         if (!str || !locked->add(s, script, mozilla::Move(str)))
             return nullptr;
     }
 
     return s->value().get();
 }
 
 void
-GeckoProfiler::onScriptFinalized(JSScript* script)
+GeckoProfilerRuntime::onScriptFinalized(JSScript* script)
 {
     /*
      * This function is called whenever a script is destroyed, regardless of
      * whether profiling has been turned on, so don't invoke a function on an
      * invalid hash set. Also, even if profiling was enabled but then turned
      * off, we still want to remove the string, so no check of enabled() is
      * done.
      */
     auto locked = strings.lock();
     if (!locked->initialized())
         return;
     if (ProfileStringMap::Ptr entry = locked->lookup(script))
         locked->remove(entry);
 }
 
 void
-GeckoProfiler::markEvent(const char* event)
+GeckoProfilerRuntime::markEvent(const char* event)
 {
     MOZ_ASSERT(enabled());
     if (eventMarker_) {
         JS::AutoSuppressGCAnalysis nogc;
         eventMarker_(event);
     }
 }
 
 bool
-GeckoProfiler::enter(JSContext* cx, JSScript* script, JSFunction* maybeFun)
+GeckoProfilerThread::enter(JSContext* cx, JSScript* script, JSFunction* maybeFun)
 {
-    const char* dynamicString = profileString(script, maybeFun);
+    const char* dynamicString = cx->runtime()->geckoProfiler().profileString(script, maybeFun);
     if (dynamicString == nullptr) {
         ReportOutOfMemory(cx);
         return false;
     }
 
 #ifdef DEBUG
     // In debug builds, assert the JS pseudo frames already on the stack
     // have a non-null pc. Only look at the top frames to avoid quadratic
@@ -233,25 +227,26 @@ GeckoProfiler::enter(JSContext* cx, JSSc
     }
 #endif
 
     pseudoStack_->pushJsFrame("", dynamicString, script, script->code());
     return true;
 }
 
 void
-GeckoProfiler::exit(JSScript* script, JSFunction* maybeFun)
+GeckoProfilerThread::exit(JSScript* script, JSFunction* maybeFun)
 {
     pseudoStack_->pop();
 
 #ifdef DEBUG
     /* Sanity check to make sure push/pop balanced */
     uint32_t sp = pseudoStack_->stackPointer;
     if (sp < PseudoStack::MaxEntries) {
-        const char* dynamicString = profileString(script, maybeFun);
+        JSRuntime* rt = script->runtimeFromActiveCooperatingThread();
+        const char* dynamicString = rt->geckoProfiler().profileString(script, maybeFun);
         /* Can't fail lookup because we should already be in the set */
         MOZ_ASSERT(dynamicString);
 
         // Bug 822041
         if (!pseudoStack_->entries[sp].isJs()) {
             fprintf(stderr, "--- ABOUT TO FAIL ASSERTION ---\n");
             fprintf(stderr, " entries=%p size=%u/%u\n",
                             (void*) pseudoStack_->entries,
@@ -276,17 +271,17 @@ GeckoProfiler::exit(JSScript* script, JS
 
 /*
  * Serializes the script/function pair into a "descriptive string" which is
  * allowed to fail. This function cannot trigger a GC because it could finalize
  * some scripts, resize the hash table of profile strings, and invalidate the
  * AddPtr held while invoking allocProfileString.
  */
 UniqueChars
-GeckoProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
+GeckoProfilerRuntime::allocProfileString(JSScript* script, JSFunction* maybeFun)
 {
     // Note: this profiler string is regexp-matched by
     // devtools/client/profiler/cleopatra/js/parserWorker.js.
 
     // Get the function name, if any.
     JSAtom* atom = maybeFun ? maybeFun->displayAtom() : nullptr;
 
     // Get the script filename, if any, and its length.
@@ -324,44 +319,44 @@ GeckoProfiler::allocProfileString(JSScri
     }
 
     MOZ_ASSERT(ret == len, "Computed length should match actual length!");
 
     return cstr;
 }
 
 void
-GeckoProfiler::trace(JSTracer* trc)
+GeckoProfilerThread::trace(JSTracer* trc)
 {
     if (pseudoStack_) {
         size_t size = pseudoStack_->stackSize();
         for (size_t i = 0; i < size; i++)
             pseudoStack_->entries[i].trace(trc);
     }
 }
 
 void
-GeckoProfiler::fixupStringsMapAfterMovingGC()
+GeckoProfilerRuntime::fixupStringsMapAfterMovingGC()
 {
     auto locked = strings.lock();
     if (!locked->initialized())
         return;
 
     for (ProfileStringMap::Enum e(locked.get()); !e.empty(); e.popFront()) {
         JSScript* script = e.front().key();
         if (IsForwarded(script)) {
             script = Forwarded(script);
             e.rekeyFront(script);
         }
     }
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 void
-GeckoProfiler::checkStringsMapAfterMovingGC()
+GeckoProfilerRuntime::checkStringsMapAfterMovingGC()
 {
     auto locked = strings.lock();
     if (!locked->initialized())
         return;
 
     for (auto r = locked->all(); !r.empty(); r.popFront()) {
         JSScript* script = r.front().key();
         CheckGCThingAfterMovingGC(script);
@@ -376,20 +371,20 @@ ProfileEntry::trace(JSTracer* trc)
 {
     if (isJs()) {
         JSScript* s = rawScript();
         TraceNullableRoot(trc, &s, "ProfileEntry script");
         spOrScript = s;
     }
 }
 
-GeckoProfilerEntryMarker::GeckoProfilerEntryMarker(JSRuntime* rt,
+GeckoProfilerEntryMarker::GeckoProfilerEntryMarker(JSContext* cx,
                                                    JSScript* script
                                                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-    : profiler(&rt->geckoProfiler())
+    : profiler(&cx->geckoProfiler())
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     if (!profiler->installed()) {
         profiler = nullptr;
         return;
     }
     spBefore_ = profiler->stackPointer();
 
@@ -408,20 +403,20 @@ GeckoProfilerEntryMarker::~GeckoProfiler
     if (profiler == nullptr)
         return;
 
     profiler->pseudoStack_->pop();    // the JS frame
     profiler->pseudoStack_->pop();    // the BEGIN_PSEUDO_JS frame
     MOZ_ASSERT(spBefore_ == profiler->stackPointer());
 }
 
-AutoGeckoProfilerEntry::AutoGeckoProfilerEntry(JSRuntime* rt, const char* label,
+AutoGeckoProfilerEntry::AutoGeckoProfilerEntry(JSContext* cx, const char* label,
                                                ProfileEntry::Category category
                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-    : profiler_(&rt->geckoProfiler())
+    : profiler_(&cx->geckoProfiler())
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     if (!profiler_->installed()) {
         profiler_ = nullptr;
         return;
     }
     spBefore_ = profiler_->stackPointer();
 
@@ -434,22 +429,22 @@ AutoGeckoProfilerEntry::~AutoGeckoProfil
 {
     if (!profiler_)
         return;
 
     profiler_->pseudoStack_->pop();
     MOZ_ASSERT(spBefore_ == profiler_->stackPointer());
 }
 
-GeckoProfilerBaselineOSRMarker::GeckoProfilerBaselineOSRMarker(JSRuntime* rt, bool hasProfilerFrame
+GeckoProfilerBaselineOSRMarker::GeckoProfilerBaselineOSRMarker(JSContext* cx, bool hasProfilerFrame
                                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-    : profiler(&rt->geckoProfiler())
+    : profiler(&cx->geckoProfiler())
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    if (!hasProfilerFrame || !profiler->enabled()) {
+    if (!hasProfilerFrame || !cx->runtime()->geckoProfiler().enabled()) {
         profiler = nullptr;
         return;
     }
 
     uint32_t sp = profiler->pseudoStack_->stackPointer;
     if (sp >= PseudoStack::MaxEntries) {
         profiler = nullptr;
         return;
@@ -525,24 +520,23 @@ ProfileEntry::setPC(jsbytecode* pc)
     JSScript* script = this->script();
     MOZ_ASSERT(script); // This should not be called while profiling is suppressed.
     lineOrPcOffset = pcToOffset(script, pc);
 }
 
 JS_FRIEND_API(void)
 js::SetContextProfilingStack(JSContext* cx, PseudoStack* pseudoStack)
 {
-    cx->runtime()->geckoProfiler().setProfilingStack(pseudoStack);
+    cx->geckoProfiler().setProfilingStack(pseudoStack);
 }
 
 JS_FRIEND_API(void)
 js::EnableContextProfilingStack(JSContext* cx, bool enabled)
 {
-    if (!cx->runtime()->geckoProfiler().enable(enabled))
-        MOZ_CRASH("Execution in this runtime should already be single threaded");
+    cx->runtime()->geckoProfiler().enable(enabled);
 }
 
 JS_FRIEND_API(void)
 js::RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*))
 {
     MOZ_ASSERT(cx->runtime()->geckoProfiler().enabled());
     cx->runtime()->geckoProfiler().setEventMarker(fn);
 }
--- a/js/src/vm/GeckoProfiler.h
+++ b/js/src/vm/GeckoProfiler.h
@@ -109,155 +109,155 @@ using ProfileStringMap = HashMap<JSScrip
                                  UniqueChars,
                                  DefaultHasher<JSScript*>,
                                  SystemAllocPolicy>;
 
 class AutoGeckoProfilerEntry;
 class GeckoProfilerEntryMarker;
 class GeckoProfilerBaselineOSRMarker;
 
-class GeckoProfiler
+class GeckoProfilerThread
 {
     friend class AutoGeckoProfilerEntry;
     friend class GeckoProfilerEntryMarker;
     friend class GeckoProfilerBaselineOSRMarker;
 
-    JSRuntime*           rt;
-    ExclusiveData<ProfileStringMap> strings;
     PseudoStack*         pseudoStack_;
-    bool                 slowAssertions;
-    uint32_t             enabled_;
-    void                (*eventMarker_)(const char*);
-
-    UniqueChars allocProfileString(JSScript* script, JSFunction* function);
 
   public:
-    explicit GeckoProfiler(JSRuntime* rt);
-
-    bool init();
+    GeckoProfilerThread();
 
     uint32_t stackPointer() { MOZ_ASSERT(installed()); return pseudoStack_->stackPointer; }
     ProfileEntry* stack() { return pseudoStack_->entries; }
 
     /* management of whether instrumentation is on or off */
-    bool enabled() { MOZ_ASSERT_IF(enabled_, installed()); return enabled_; }
     bool installed() { return pseudoStack_ != nullptr; }
-    MOZ_MUST_USE bool enable(bool enabled);
-    void enableSlowAssertions(bool enabled) { slowAssertions = enabled; }
-    bool slowAssertionsEnabled() { return slowAssertions; }
+
+    void setProfilingStack(PseudoStack* pseudoStack);
+    void trace(JSTracer* trc);
 
     /*
      * Functions which are the actual instrumentation to track run information
      *
      *   - enter: a function has started to execute
      *   - updatePC: updates the pc information about where a function
      *               is currently executing
      *   - exit: this function has ceased execution, and no further
      *           entries/exits will be made
      */
     bool enter(JSContext* cx, JSScript* script, JSFunction* maybeFun);
     void exit(JSScript* script, JSFunction* maybeFun);
-    void updatePC(JSScript* script, jsbytecode* pc) {
-        if (!enabled())
-            return;
+    inline void updatePC(JSContext* cx, JSScript* script, jsbytecode* pc);
+};
+
+class GeckoProfilerRuntime
+{
+    JSRuntime*           rt;
+    ExclusiveData<ProfileStringMap> strings;
+    bool                 slowAssertions;
+    uint32_t             enabled_;
+    void                (*eventMarker_)(const char*);
 
-        uint32_t sp = pseudoStack_->stackPointer;
-        if (sp - 1 < PseudoStack::MaxEntries) {
-            MOZ_ASSERT(sp > 0);
-            MOZ_ASSERT(pseudoStack_->entries[sp - 1].rawScript() == script);
-            pseudoStack_->entries[sp - 1].setPC(pc);
-        }
-    }
+    UniqueChars allocProfileString(JSScript* script, JSFunction* function);
+
+  public:
+    explicit GeckoProfilerRuntime(JSRuntime* rt);
+
+    bool init();
 
-    void setProfilingStack(PseudoStack* pseudoStack);
+    /* management of whether instrumentation is on or off */
+    bool enabled() { return enabled_; }
+    void enable(bool enabled);
+    void enableSlowAssertions(bool enabled) { slowAssertions = enabled; }
+    bool slowAssertionsEnabled() { return slowAssertions; }
+
     void setEventMarker(void (*fn)(const char*));
     const char* profileString(JSScript* script, JSFunction* maybeFun);
     void onScriptFinalized(JSScript* script);
 
     void markEvent(const char* event);
 
     /* meant to be used for testing, not recommended to call in normal code */
     size_t stringsCount();
     void stringsReset();
 
     uint32_t* addressOfEnabled() {
         return &enabled_;
     }
 
-    void trace(JSTracer* trc);
     void fixupStringsMapAfterMovingGC();
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkStringsMapAfterMovingGC();
 #endif
 };
 
 inline size_t
-GeckoProfiler::stringsCount()
+GeckoProfilerRuntime::stringsCount()
 {
     return strings.lock()->count();
 }
 
 inline void
-GeckoProfiler::stringsReset()
+GeckoProfilerRuntime::stringsReset()
 {
     strings.lock()->clear();
 }
 
 /*
  * This class is used in RunScript() to push the marker onto the sampling stack
  * that we're about to enter JS function calls. This is the only time in which a
  * valid stack pointer is pushed to the sampling stack.
  */
 class MOZ_RAII GeckoProfilerEntryMarker
 {
   public:
-    explicit GeckoProfilerEntryMarker(JSRuntime* rt,
+    explicit GeckoProfilerEntryMarker(JSContext* cx,
                                       JSScript* script
                                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     ~GeckoProfilerEntryMarker();
 
   private:
-    GeckoProfiler* profiler;
+    GeckoProfilerThread* profiler;
     mozilla::DebugOnly<uint32_t> spBefore_;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*
  * RAII class to automatically add Gecko Profiler pseudo frame entries.
  *
  * NB: The `label` string must be statically allocated.
  */
 class MOZ_NONHEAP_CLASS AutoGeckoProfilerEntry
 {
   public:
-    explicit AutoGeckoProfilerEntry(JSRuntime* rt, const char* label,
+    explicit AutoGeckoProfilerEntry(JSContext* cx, const char* label,
                                     ProfileEntry::Category category = ProfileEntry::Category::JS
                                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     ~AutoGeckoProfilerEntry();
 
   private:
-    GeckoProfiler* profiler_;
+    GeckoProfilerThread* profiler_;
     mozilla::DebugOnly<uint32_t> spBefore_;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*
  * This class is used in the interpreter to bound regions where the baseline JIT
  * being entered via OSR.  It marks the current top pseudostack entry as
  * OSR-ed
  */
 class MOZ_RAII GeckoProfilerBaselineOSRMarker
 {
   public:
-    explicit GeckoProfilerBaselineOSRMarker(JSRuntime* rt, bool hasProfilerFrame
+    explicit GeckoProfilerBaselineOSRMarker(JSContext* cx, bool hasProfilerFrame
                                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     ~GeckoProfilerBaselineOSRMarker();
 
   private:
-    GeckoProfiler* profiler;
+    GeckoProfilerThread* profiler;
     mozilla::DebugOnly<uint32_t> spBefore_;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*
  * This class manages the instrumentation portion of the profiling for JIT
  * code.
  *
@@ -267,26 +267,26 @@ class MOZ_RAII GeckoProfilerBaselineOSRM
  * manages the instrumentation which needs to be attached to them as well.
  *
  * The basic methods which emit instrumentation are at the end of this class,
  * and the management functions are all described in the middle.
  */
 template<class Assembler, class Register>
 class GeckoProfilerInstrumentation
 {
-    GeckoProfiler* profiler_; // Instrumentation location management
+    GeckoProfilerRuntime* profiler_; // Instrumentation location management
 
   public:
     /*
      * Creates instrumentation which writes information out the the specified
      * profiler's stack and constituent fields.
      */
-    explicit GeckoProfilerInstrumentation(GeckoProfiler* profiler) : profiler_(profiler) {}
+    explicit GeckoProfilerInstrumentation(GeckoProfilerRuntime* profiler) : profiler_(profiler) {}
 
     /* Small proxies around GeckoProfiler */
     bool enabled() { return profiler_ && profiler_->enabled(); }
-    GeckoProfiler* profiler() { MOZ_ASSERT(enabled()); return profiler_; }
+    GeckoProfilerRuntime* profiler() { MOZ_ASSERT(enabled()); return profiler_; }
     void disable() { profiler_ = nullptr; }
 };
 
 } /* namespace js */
 
 #endif /* vm_GeckoProfiler_h */
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -51,16 +51,17 @@
 #include "jsatominlines.h"
 #include "jsboolinlines.h"
 #include "jsfuninlines.h"
 #include "jsscriptinlines.h"
 
 #include "jit/JitFrames-inl.h"
 #include "vm/Debugger-inl.h"
 #include "vm/EnvironmentObject-inl.h"
+#include "vm/GeckoProfiler-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/Probes-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::ArrayLength;
@@ -124,36 +125,34 @@ js::GetFunctionThis(JSContext* cx, Abstr
         res.set(frame.thisArgument());
         return true;
     }
 
     RootedValue thisv(cx, frame.thisArgument());
     return BoxNonStrictThis(cx, thisv, res);
 }
 
-bool
+void
 js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain, MutableHandleValue res)
 {
     RootedObject env(cx, envChain);
     while (true) {
         if (IsExtensibleLexicalEnvironment(env)) {
             res.set(env->as<LexicalEnvironmentObject>().thisValue());
-            return true;
+            return;
         }
         if (!env->enclosingEnvironment()) {
             // This can only happen in Debugger eval frames: in that case we
             // don't always have a global lexical env, see EvaluateInEnv.
             MOZ_ASSERT(env->is<GlobalObject>());
             res.set(GetThisValue(env));
-            return true;
+            return;
         }
         env = env->enclosingEnvironment();
     }
-
-    return true;
 }
 
 bool
 js::Debug_CheckSelfHosted(JSContext* cx, HandleValue fun)
 {
 #ifndef DEBUG
     MOZ_CRASH("self-hosted checks should only be done in Debug builds");
 #endif
@@ -373,17 +372,17 @@ js::RunScript(JSContext* cx, RunState& s
 
     if (!Debugger::checkNoExecute(cx, state.script()))
         return false;
 
 #if defined(MOZ_HAVE_RDTSC)
     js::AutoStopwatch stopwatch(cx);
 #endif // defined(MOZ_HAVE_RDTSC)
 
-    GeckoProfilerEntryMarker marker(cx->runtime(), state.script());
+    GeckoProfilerEntryMarker marker(cx, state.script());
 
     state.script()->ensureNonLazyCanonicalFunction();
 
     if (jit::IsIonEnabled(cx)) {
         jit::MethodStatus status = jit::CanEnter(cx, state);
         if (status == jit::Method_Error)
             return false;
         if (status == jit::Method_Compiled) {
@@ -2012,31 +2011,31 @@ CASE(JSOP_LOOPENTRY)
         jit::MethodStatus status = jit::CanEnterBaselineAtBranch(cx, REGS.fp(), false);
         if (status == jit::Method_Error)
             goto error;
         if (status == jit::Method_Compiled) {
             bool wasProfiler = REGS.fp()->hasPushedGeckoProfilerFrame();
 
             jit::JitExecStatus maybeOsr;
             {
-                GeckoProfilerBaselineOSRMarker osr(cx->runtime(), wasProfiler);
+                GeckoProfilerBaselineOSRMarker osr(cx, wasProfiler);
                 maybeOsr = jit::EnterBaselineAtBranch(cx, REGS.fp(), REGS.pc);
             }
 
             // We failed to call into baseline at all, so treat as an error.
             if (maybeOsr == jit::JitExec_Aborted)
                 goto error;
 
             interpReturnOK = (maybeOsr == jit::JitExec_Ok);
 
             // Pop the profiler frame pushed by the interpreter.  (The compiled
             // version of the function popped a copy of the frame pushed by the
             // OSR trampoline.)
             if (wasProfiler)
-                cx->runtime()->geckoProfiler().exit(script, script->functionNonDelazifying());
+                cx->geckoProfiler().exit(script, script->functionNonDelazifying());
 
             if (activation.entryFrame() != REGS.fp())
                 goto jit_return_pop_frame;
             goto leave_on_safe_point;
         }
     }
 END_CASE(JSOP_LOOPENTRY)
 
@@ -2720,18 +2719,17 @@ CASE(JSOP_FUNCTIONTHIS)
     if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1)))
         goto error;
 END_CASE(JSOP_FUNCTIONTHIS)
 
 CASE(JSOP_GLOBALTHIS)
 {
     if (script->hasNonSyntacticScope()) {
         PUSH_NULL();
-        if (!GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(), REGS.stackHandleAt(-1)))
-            goto error;
+        GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(), REGS.stackHandleAt(-1));
     } else {
         PUSH_COPY(cx->global()->lexicalEnvironment().thisValue());
     }
 }
 END_CASE(JSOP_GLOBALTHIS)
 
 CASE(JSOP_CHECKISOBJ)
 {
@@ -2987,17 +2985,17 @@ CASE(JSOP_STRICTEVAL)
     TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 CASE(JSOP_SPREADNEW)
 CASE(JSOP_SPREADCALL)
 CASE(JSOP_SPREADSUPERCALL)
     if (REGS.fp()->hasPushedGeckoProfilerFrame())
-        cx->runtime()->geckoProfiler().updatePC(script, REGS.pc);
+        cx->geckoProfiler().updatePC(cx, script, REGS.pc);
     /* FALL THROUGH */
 
 CASE(JSOP_SPREADEVAL)
 CASE(JSOP_STRICTSPREADEVAL)
 {
     static_assert(JSOP_SPREADEVAL_LENGTH == JSOP_STRICTSPREADEVAL_LENGTH,
                   "spreadeval and strictspreadeval must be the same size");
     bool construct = JSOp(*REGS.pc) == JSOP_SPREADNEW || JSOp(*REGS.pc) == JSOP_SPREADSUPERCALL;;
@@ -3033,17 +3031,17 @@ CASE(JSOP_FUNAPPLY)
 CASE(JSOP_NEW)
 CASE(JSOP_CALL)
 CASE(JSOP_CALL_IGNORES_RV)
 CASE(JSOP_CALLITER)
 CASE(JSOP_SUPERCALL)
 CASE(JSOP_FUNCALL)
 {
     if (REGS.fp()->hasPushedGeckoProfilerFrame())
-        cx->runtime()->geckoProfiler().updatePC(script, REGS.pc);
+        cx->geckoProfiler().updatePC(cx, script, REGS.pc);
 
     MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
     bool ignoresReturnValue = *REGS.pc == JSOP_CALL_IGNORES_RV;
     unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
 
     MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
     CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
 
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -25,17 +25,17 @@ class EnvironmentIter;
  * compartment, and replace other primitives with boxed versions.
  */
 extern bool
 BoxNonStrictThis(JSContext* cx, HandleValue thisv, MutableHandleValue vp);
 
 extern bool
 GetFunctionThis(JSContext* cx, AbstractFramePtr frame, MutableHandleValue res);
 
-extern bool
+extern void
 GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain, MutableHandleValue res);
 
 /*
  * numToSkip is the number of stack values the expression decompiler should skip
  * before it reaches |v|. If it's -1, the decompiler will search the stack.
  */
 extern bool
 ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
--- a/js/src/vm/Probes-inl.h
+++ b/js/src/vm/Probes-inl.h
@@ -36,17 +36,17 @@ probes::EnterScript(JSContext* cx, JSScr
 {
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
         DTraceEnterJSFun(cx, maybeFun, script);
 #endif
 
     JSRuntime* rt = cx->runtime();
     if (rt->geckoProfiler().enabled()) {
-        if (!rt->geckoProfiler().enter(cx, script, maybeFun))
+        if (!cx->geckoProfiler().enter(cx, script, maybeFun))
             return false;
         MOZ_ASSERT_IF(!fp->script()->isStarGenerator() &&
                       !fp->script()->isLegacyGenerator() &&
                       !fp->script()->isAsync(),
                       !fp->hasPushedGeckoProfilerFrame());
         fp->setPushedGeckoProfilerFrame();
     }
 
@@ -57,17 +57,17 @@ inline void
 probes::ExitScript(JSContext* cx, JSScript* script, JSFunction* maybeFun, bool popProfilerFrame)
 {
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
         DTraceExitJSFun(cx, maybeFun, script);
 #endif
 
     if (popProfilerFrame)
-        cx->runtime()->geckoProfiler().exit(script, maybeFun);
+        cx->geckoProfiler().exit(script, maybeFun);
 }
 
 inline bool
 probes::StartExecution(JSScript* script)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -312,18 +312,16 @@ JSRuntime::destroyRuntime()
         profilerSampleBufferGen_ = UINT32_MAX;
 
         JS::PrepareForFullGC(cx);
         gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
     }
 
     AutoNoteSingleThreadedRegion anstr;
 
-    MOZ_ASSERT_IF(!geckoProfiler().enabled(), !singleThreadedExecutionRequired_);
-
     MOZ_ASSERT(!hasHelperThreadZones());
     AutoLockForExclusiveAccess lock(this);
 
     /*
      * Even though all objects in the compartment are dead, we may have keep
      * some filenames around because of gcKeepAtoms.
      */
     FreeScriptData(this, lock);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -504,19 +504,19 @@ struct JSRuntime : public js::MallocProv
     js::ActiveThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
     js::ActiveThreadData<JSReadPrincipalsOp> readPrincipals;
 
     /* Optional warning reporter. */
     js::ActiveThreadData<JS::WarningReporter> warningReporter;
 
   private:
     /* Gecko profiling metadata */
-    js::UnprotectedData<js::GeckoProfiler> geckoProfiler_;
+    js::UnprotectedData<js::GeckoProfilerRuntime> geckoProfiler_;
   public:
-    js::GeckoProfiler& geckoProfiler() { return geckoProfiler_.ref(); }
+    js::GeckoProfilerRuntime& geckoProfiler() { return geckoProfiler_.ref(); }
 
     // Heap GC roots for PersistentRooted pointers.
     js::ActiveThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
                                                  mozilla::LinkedList<JS::PersistentRooted<void*>>>> heapRoots;
 
     void tracePersistentRoots(JSTracer* trc);
     void finishPersistentRoots();
 
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1168,17 +1168,17 @@ SavedStacks::saveCurrentStack(JSContext*
         cx->isExceptionPending() ||
         !cx->global() ||
         !cx->global()->isStandardClassResolved(JSProto_Object))
     {
         frame.set(nullptr);
         return true;
     }
 
-    AutoGeckoProfilerEntry psuedoFrame(cx->runtime(), "js::SavedStacks::saveCurrentStack");
+    AutoGeckoProfilerEntry psuedoFrame(cx, "js::SavedStacks::saveCurrentStack");
     FrameIter iter(cx);
     return insertFrames(cx, iter, frame, mozilla::Move(capture));
 }
 
 bool
 SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
                             MutableHandleSavedFrame adoptedStack, uint32_t maxFrameCount)
 {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -592,30 +592,55 @@ FrameIter::Data::Data(JSContext* cx, Deb
     interpFrames_(nullptr),
     activations_(cx),
     jitFrames_(),
     ionInlineFrameNo_(0),
     wasmFrames_()
 {
 }
 
+FrameIter::Data::Data(JSContext* cx, const CooperatingContext& target,
+                      DebuggerEvalOption debuggerEvalOption)
+  : cx_(cx),
+    debuggerEvalOption_(debuggerEvalOption),
+    principals_(nullptr),
+    state_(DONE),
+    pc_(nullptr),
+    interpFrames_(nullptr),
+    activations_(cx, target),
+    jitFrames_(),
+    ionInlineFrameNo_(0),
+    wasmFrames_()
+{
+}
+
 FrameIter::Data::Data(const FrameIter::Data& other)
   : cx_(other.cx_),
     debuggerEvalOption_(other.debuggerEvalOption_),
     principals_(other.principals_),
     state_(other.state_),
     pc_(other.pc_),
     interpFrames_(other.interpFrames_),
     activations_(other.activations_),
     jitFrames_(other.jitFrames_),
     ionInlineFrameNo_(other.ionInlineFrameNo_),
     wasmFrames_(other.wasmFrames_)
 {
 }
 
+FrameIter::FrameIter(JSContext* cx, const CooperatingContext& target,
+                     DebuggerEvalOption debuggerEvalOption)
+  : data_(cx, target, debuggerEvalOption),
+    ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
+{
+    // settleOnActivation can only GC if principals are given.
+    JS::AutoSuppressGCAnalysis nogc;
+    settleOnActivation();
+}
+
 FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption)
   : data_(cx, debuggerEvalOption, nullptr),
     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 {
     // settleOnActivation can only GC if principals are given.
     JS::AutoSuppressGCAnalysis nogc;
     settleOnActivation();
 }
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -47,17 +47,17 @@ class JS_PUBLIC_API(AutoEntryMonitor);
 
 namespace js {
 
 class InterpreterRegs;
 class CallObject;
 class FrameIter;
 class EnvironmentObject;
 class ScriptFrameIter;
-class GeckoProfiler;
+class GeckoProfilerRuntime;
 class InterpreterFrame;
 class LexicalEnvironmentObject;
 class EnvironmentIter;
 class EnvironmentCoordinate;
 
 class SavedFrame;
 
 namespace jit {
@@ -1810,21 +1810,23 @@ class FrameIter
         InterpreterFrameIterator interpFrames_;
         ActivationIterator activations_;
 
         jit::JitFrameIterator jitFrames_;
         unsigned ionInlineFrameNo_;
         wasm::FrameIterator wasmFrames_;
 
         Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
+        Data(JSContext* cx, const CooperatingContext& target, DebuggerEvalOption debuggerEvalOption);
         Data(const Data& other);
     };
 
     explicit FrameIter(JSContext* cx,
                        DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
+    FrameIter(JSContext* cx, const CooperatingContext&, DebuggerEvalOption);
     FrameIter(JSContext* cx, DebuggerEvalOption, JSPrincipals*);
     FrameIter(const FrameIter& iter);
     MOZ_IMPLICIT FrameIter(const Data& data);
     MOZ_IMPLICIT FrameIter(AbstractFramePtr frame);
 
     bool done() const { return data_.state_ == DONE; }
 
     // -------------------------------------------------------
@@ -1970,16 +1972,24 @@ class ScriptFrameIter : public FrameIter
     explicit ScriptFrameIter(JSContext* cx,
                              DebuggerEvalOption debuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK)
       : FrameIter(cx, debuggerEvalOption)
     {
         settle();
     }
 
     ScriptFrameIter(JSContext* cx,
+                     const CooperatingContext& target,
+                     DebuggerEvalOption debuggerEvalOption)
+       : FrameIter(cx, target, debuggerEvalOption)
+    {
+        settle();
+    }
+
+    ScriptFrameIter(JSContext* cx,
                     DebuggerEvalOption debuggerEvalOption,
                     JSPrincipals* prin)
       : FrameIter(cx, debuggerEvalOption, prin)
     {
         settle();
     }
 
     ScriptFrameIter(const ScriptFrameIter& iter) : FrameIter(iter) { settle(); }
@@ -2091,16 +2101,20 @@ class AllFramesIter : public FrameIter
  * See also AllFramesIter and ScriptFrameIter.
  */
 class AllScriptFramesIter : public ScriptFrameIter
 {
   public:
     explicit AllScriptFramesIter(JSContext* cx)
       : ScriptFrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
     {}
+
+    explicit AllScriptFramesIter(JSContext* cx, const CooperatingContext& target)
+      : ScriptFrameIter(cx, target, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
+    {}
 };
 
 /* Popular inline definitions. */
 
 inline JSScript*
 FrameIter::script() const
 {
     MOZ_ASSERT(!done());
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -580,17 +580,17 @@ JSRope::flattenInternal(JSContext* maybe
     return flattenInternal<b, Latin1Char>(maybecx);
 }
 
 JSFlatString*
 JSRope::flatten(JSContext* maybecx)
 {
     mozilla::Maybe<AutoGeckoProfilerEntry> entry;
     if (maybecx && !maybecx->helperThread())
-        entry.emplace(maybecx->runtime(), "JSRope::flatten");
+        entry.emplace(maybecx, "JSRope::flatten");
 
     if (zone()->needsIncrementalBarrier())
         return flattenInternal<WithIncrementalBarrier>(maybecx);
     return flattenInternal<NoBarrier>(maybecx);
 }
 
 template <AllowGC allowGC>
 static JSLinearString*
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2106,17 +2106,17 @@ class ConstraintDataConstantProperty
     JSCompartment* maybeCompartment() { return nullptr; }
 };
 
 } /* anonymous namespace */
 
 bool
 HeapTypeSetKey::constant(CompilerConstraintList* constraints, Value* valOut)
 {
-    if (nonData(constraints) || !object()->isSingleton())
+    if (nonData(constraints))
         return false;
 
     // Only singleton object properties can be marked as constants.
     JSObject* obj = object()->singleton();
     if (!obj || !obj->isNative())
         return false;
 
     if (maybeTypes() && maybeTypes()->nonConstantProperty())
@@ -3994,99 +3994,102 @@ TypeNewScript::rollbackPartiallyInitiali
 
     if (!initializerList)
         return false;
 
     bool found = false;
 
     RootedFunction function(cx, this->function());
     Vector<uint32_t, 32> pcOffsets(cx);
-    for (ScriptFrameIter iter(cx); !iter.done(); ++iter) {
-        {
-            AutoEnterOOMUnsafeRegion oomUnsafe;
-            if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
-                oomUnsafe.crash("rollbackPartiallyInitializedObjects");
-        }
-
-        if (!iter.isConstructing() || !iter.matchCallee(cx, function))
-            continue;
-
-        // Derived class constructors initialize their this-binding later and
-        // we shouldn't run the definite properties analysis on them.
-        MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
-
-        Value thisv = iter.thisArgument(cx);
-        if (!thisv.isObject() ||
-            thisv.toObject().hasLazyGroup() ||
-            thisv.toObject().group() != group)
-        {
-            continue;
-        }
-
-        if (thisv.toObject().is<UnboxedPlainObject>()) {
-            AutoEnterOOMUnsafeRegion oomUnsafe;
-            if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject()))
-                oomUnsafe.crash("rollbackPartiallyInitializedObjects");
-        }
-
-        // Found a matching frame.
-        RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
-
-        // Whether all identified 'new' properties have been initialized.
-        bool finished = false;
-
-        // If not finished, number of properties that have been added.
-        uint32_t numProperties = 0;
-
-        // Whether the current SETPROP is within an inner frame which has
-        // finished entirely.
-        bool pastProperty = false;
-
-        // Index in pcOffsets of the outermost frame.
-        int callDepth = pcOffsets.length() - 1;
-
-        // Index in pcOffsets of the frame currently being checked for a SETPROP.
-        int setpropDepth = callDepth;
-
-        for (Initializer* init = initializerList;; init++) {
-            if (init->kind == Initializer::SETPROP) {
-                if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
-                    // Have not yet reached this setprop.
+    JSRuntime::AutoProhibitActiveContextChange apacc(cx->runtime());
+    for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
+        for (AllScriptFramesIter iter(cx, target); !iter.done(); ++iter) {
+            {
+                AutoEnterOOMUnsafeRegion oomUnsafe;
+                if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
+                    oomUnsafe.crash("rollbackPartiallyInitializedObjects");
+            }
+
+            if (!iter.isConstructing() || !iter.matchCallee(cx, function))
+                continue;
+
+            // Derived class constructors initialize their this-binding later and
+            // we shouldn't run the definite properties analysis on them.
+            MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
+
+            Value thisv = iter.thisArgument(cx);
+            if (!thisv.isObject() ||
+                thisv.toObject().hasLazyGroup() ||
+                thisv.toObject().group() != group)
+            {
+                continue;
+            }
+
+            if (thisv.toObject().is<UnboxedPlainObject>()) {
+                AutoEnterOOMUnsafeRegion oomUnsafe;
+                if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject()))
+                    oomUnsafe.crash("rollbackPartiallyInitializedObjects");
+            }
+
+            // Found a matching frame.
+            RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
+
+            // Whether all identified 'new' properties have been initialized.
+            bool finished = false;
+
+            // If not finished, number of properties that have been added.
+            uint32_t numProperties = 0;
+
+            // Whether the current SETPROP is within an inner frame which has
+            // finished entirely.
+            bool pastProperty = false;
+
+            // Index in pcOffsets of the outermost frame.
+            int callDepth = pcOffsets.length() - 1;
+
+            // Index in pcOffsets of the frame currently being checked for a SETPROP.
+            int setpropDepth = callDepth;
+
+            for (Initializer* init = initializerList;; init++) {
+                if (init->kind == Initializer::SETPROP) {
+                    if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
+                        // Have not yet reached this setprop.
+                        break;
+                    }
+                    // This setprop has executed, reset state for the next one.
+                    numProperties++;
+                    pastProperty = false;
+                    setpropDepth = callDepth;
+                } else if (init->kind == Initializer::SETPROP_FRAME) {
+                    if (!pastProperty) {
+                        if (pcOffsets[setpropDepth] < init->offset) {
+                            // Have not yet reached this inner call.
+                            break;
+                        } else if (pcOffsets[setpropDepth] > init->offset) {
+                            // Have advanced past this inner call.
+                            pastProperty = true;
+                        } else if (setpropDepth == 0) {
+                            // Have reached this call but not yet in it.
+                            break;
+                        } else {
+                            // Somewhere inside this inner call.
+                            setpropDepth--;
+                        }
+                    }
+                } else {
+                    MOZ_ASSERT(init->kind == Initializer::DONE);
+                    finished = true;
                     break;
                 }
-                // This setprop has executed, reset state for the next one.
-                numProperties++;
-                pastProperty = false;
-                setpropDepth = callDepth;
-            } else if (init->kind == Initializer::SETPROP_FRAME) {
-                if (!pastProperty) {
-                    if (pcOffsets[setpropDepth] < init->offset) {
-                        // Have not yet reached this inner call.
-                        break;
-                    } else if (pcOffsets[setpropDepth] > init->offset) {
-                        // Have advanced past this inner call.
-                        pastProperty = true;
-                    } else if (setpropDepth == 0) {
-                        // Have reached this call but not yet in it.
-                        break;
-                    } else {
-                        // Somewhere inside this inner call.
-                        setpropDepth--;
-                    }
-                }
-            } else {
-                MOZ_ASSERT(init->kind == Initializer::DONE);
-                finished = true;
-                break;
             }
-        }
-
-        if (!finished) {
-            (void) NativeObject::rollbackProperties(cx, obj, numProperties);
-            found = true;
+
+            if (!finished) {
+                (void) NativeObject::rollbackProperties(cx, obj, numProperties);
+                found = true;
+            }
         }
     }
 
     return found;
 }
 
 void
 TypeNewScript::trace(JSTracer* trc)
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -261,35 +261,51 @@ ScriptPreloader::Cleanup()
         // the main thread, or we will deadlock.
         MOZ_RELEASE_ASSERT(!mBlockedOnSyncDispatch);
 
         while (!mSaveComplete && mSaveThread) {
             mal.Wait();
         }
     }
 
-    mScripts.Clear();
+    // Wait for any pending parses to finish before clearing the mScripts
+    // hashtable, since the parse tasks depend on memory allocated by those
+    // scripts.
+    {
+        MonitorAutoLock mal(mMonitor);
+        FinishPendingParses(mal);
+
+        mScripts.Clear();
+    }
 
     AutoSafeJSAPI jsapi;
     JS_RemoveExtraGCRootsTracer(jsapi.cx(), TraceOp, this);
 
     UnregisterWeakMemoryReporter(this);
 }
 
 void
 ScriptPreloader::InvalidateCache()
 {
     mMonitor.AssertNotCurrentThreadOwns();
     MonitorAutoLock mal(mMonitor);
 
     mCacheInvalidated = true;
 
-    mParsingScripts.clearAndFree();
-    while (auto script = mPendingScripts.getFirst())
-        script->remove();
+    // Wait for pending off-thread parses to finish, since they depend on the
+    // memory allocated by our CachedScripts, and can't be canceled
+    // asynchronously.
+    FinishPendingParses(mal);
+
+    // Pending scripts should have been cleared by the above, and new parses
+    // should not have been queued.
+    MOZ_ASSERT(mParsingScripts.empty());
+    MOZ_ASSERT(mParsingSources.empty());
+    MOZ_ASSERT(mPendingScripts.isEmpty());
+
     for (auto& script : IterHash(mScripts))
         script.Remove();
 
     // If we've already finished saving the cache at this point, start a new
     // delayed save operation. This will write out an empty cache file in place
     // of any cache file we've already written out this session, which will
     // prevent us from falling back to the current session's cache file on the
     // next startup.
@@ -543,18 +559,16 @@ ScriptPreloader::PrepareCacheWriteIntern
 
         if (!(script->mProcessTypes == script->mOriginalProcessTypes)) {
             // Note: EnumSet doesn't support operator!=, hence the weird form above.
             found = true;
         }
 
         if (!script->mSize && !script->XDREncode(jsapi.cx())) {
             script.Remove();
-        } else {
-            script->mSize = script->Range().length();
         }
     }
 
     if (!found) {
         mSaveComplete = true;
         return;
     }
 
@@ -617,16 +631,21 @@ ScriptPreloader::WriteCache()
     if (exists) {
         NS_TRY(cacheFile->Remove(false));
     }
 
     {
         AutoFDClose fd;
         NS_TRY(cacheFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 0644, &fd.rwget()));
 
+        // We also need to hold mMonitor while we're touching scripts in
+        // mScripts, or they may be freed before we're done with them.
+        mMonitor.AssertNotCurrentThreadOwns();
+        MonitorAutoLock mal(mMonitor);
+
         nsTArray<CachedScript*> scripts;
         for (auto& script : IterHash(mScripts, Match<ScriptStatus::Saved>())) {
             scripts.AppendElement(script);
         }
 
         // Sort scripts by load time, with async loaded scripts before sync scripts.
         // Since async scripts are always loaded immediately at startup, it helps to
         // have them stored contiguously.
@@ -691,17 +710,17 @@ ScriptPreloader::Run()
 }
 
 void
 ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath,
                             JS::HandleScript jsscript)
 {
     // Don't bother trying to cache any URLs with cache-busting query
     // parameters.
-    if (mStartupFinished || !mCacheInitialized || cachePath.FindChar('?') >= 0) {
+    if (!Active() || cachePath.FindChar('?') >= 0) {
         return;
     }
 
     // Don't bother caching files that belong to the mochitest harness.
     NS_NAMED_LITERAL_CSTRING(mochikitPrefix, "chrome://mochikit/");
     if (StringHead(url, mochikitPrefix.Length()) == mochikitPrefix) {
         return;
     }
@@ -709,16 +728,31 @@ ScriptPreloader::NoteScript(const nsCStr
     auto script = mScripts.LookupOrAdd(cachePath, *this, url, cachePath, jsscript);
 
     if (!script->mScript) {
         MOZ_ASSERT(jsscript);
         script->mScript = jsscript;
         script->mReadyToExecute = true;
     }
 
+    // If we don't already have bytecode for this script, and it doesn't already
+    // exist in the child cache, encode it now, before it's ever executed.
+    //
+    // Ideally, we would like to do the encoding lazily, during idle slices.
+    // There are subtle issues with encoding scripts which have already been
+    // executed, though, which makes that somewhat risky. So until that
+    // situation is improved, and thoroughly tested, we need to encode eagerly.
+    //
+    // (See also the TranscodeResult_Failure_RunOnceNotSupported failure case in
+    // js::XDRScript)
+    if (!script->mSize && !(mChildCache && mChildCache->mScripts.Get(cachePath))) {
+        AutoSafeJSAPI jsapi;
+        Unused << script->XDREncode(jsapi.cx());
+    }
+
     script->UpdateLoadTime(TimeStamp::Now());
     script->mProcessTypes += CurrentProcessType();
 }
 
 void
 ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath,
                             ProcessType processType, nsTArray<uint8_t>&& xdrData,
                             TimeStamp loadTime)
@@ -777,40 +811,40 @@ ScriptPreloader::GetCachedScript(JSConte
 JSScript*
 ScriptPreloader::WaitForCachedScript(JSContext* cx, CachedScript* script)
 {
     // Check for finished operations before locking so that we can move onto
     // decoding the next batch as soon as possible after the pending batch is
     // ready. If we wait until we hit an unfinished script, we wind up having at
     // most one batch of buffered scripts, and occasionally under-running that
     // buffer.
-    FinishOffThreadDecode();
+    MaybeFinishOffThreadDecode();
 
     if (!script->mReadyToExecute) {
         LOG(Info, "Must wait for async script load: %s\n", script->mURL.get());
         auto start = TimeStamp::Now();
 
         mMonitor.AssertNotCurrentThreadOwns();
         MonitorAutoLock mal(mMonitor);
 
         // Check for finished operations again *after* locking, or we may race
         // against mToken being set between our last check and the time we
         // entered the mutex.
-        FinishOffThreadDecode();
+        MaybeFinishOffThreadDecode();
 
         if (!script->mReadyToExecute && script->mSize < MAX_MAINTHREAD_DECODE_SIZE) {
             LOG(Info, "Script is small enough to recompile on main thread\n");
 
             script->mReadyToExecute = true;
         } else {
             while (!script->mReadyToExecute) {
                 mal.Wait();
 
                 MonitorAutoUnlock mau(mMonitor);
-                FinishOffThreadDecode();
+                MaybeFinishOffThreadDecode();
             }
         }
 
         LOG(Debug, "Waited %fms\n", (TimeStamp::Now() - start).ToMilliseconds());
     }
 
     return script->GetJSScript(cx);
 }
@@ -838,24 +872,40 @@ ScriptPreloader::OffThreadDecodeCallback
         NS_DispatchToMainThread(
           NewRunnableMethod("ScriptPreloader::DoFinishOffThreadDecode",
                             cache,
                             &ScriptPreloader::DoFinishOffThreadDecode));
     }
 }
 
 void
+ScriptPreloader::FinishPendingParses(MonitorAutoLock& aMal)
+{
+    mMonitor.AssertCurrentThreadOwns();
+
+    mPendingScripts.clear();
+
+    MaybeFinishOffThreadDecode();
+
+    // Loop until all pending decode operations finish.
+    while (!mParsingScripts.empty()) {
+        aMal.Wait();
+        MaybeFinishOffThreadDecode();
+    }
+}
+
+void
 ScriptPreloader::DoFinishOffThreadDecode()
 {
     mFinishDecodeRunnablePending = false;
-    FinishOffThreadDecode();
+    MaybeFinishOffThreadDecode();
 }
 
 void
-ScriptPreloader::FinishOffThreadDecode()
+ScriptPreloader::MaybeFinishOffThreadDecode()
 {
     if (!mToken) {
         return;
     }
 
     auto cleanup = MakeScopeExit([&] () {
         mToken = nullptr;
         mParsingSources.clear();
@@ -935,17 +985,18 @@ ScriptPreloader::DecodeNextBatch(size_t 
         return;
     }
 
     AutoJSAPI jsapi;
     MOZ_RELEASE_ASSERT(jsapi.Init(xpc::CompilationScope()));
     JSContext* cx = jsapi.cx();
 
     JS::CompileOptions options(cx, JSVERSION_LATEST);
-    options.setNoScriptRval(true);
+    options.setNoScriptRval(true)
+           .setSourceIsLazy(true);
 
     if (!JS::CanCompileOffThread(cx, options, size) ||
         !JS::DecodeMultiOffThreadScripts(cx, options, mParsingSources,
                                          OffThreadDecodeCallback,
                                          static_cast<void*>(this))) {
         // If we fail here, we don't move on to process the next batch, so make
         // sure we don't have any other scripts left to process.
         MOZ_ASSERT(mPendingScripts.isEmpty());
@@ -985,18 +1036,20 @@ ScriptPreloader::CachedScript::XDREncode
     JSAutoCompartment ac(cx, mScript);
     JS::RootedScript jsscript(cx, mScript);
 
     mXDRData.construct<JS::TranscodeBuffer>();
 
     JS::TranscodeResult code = JS::EncodeScript(cx, Buffer(), jsscript);
     if (code == JS::TranscodeResult_Ok) {
         mXDRRange.emplace(Buffer().begin(), Buffer().length());
+        mSize = Range().length();
         return true;
     }
+    mXDRData.destroy();
     JS_ClearPendingException(cx);
     return false;
 }
 
 JSScript*
 ScriptPreloader::CachedScript::GetJSScript(JSContext* cx)
 {
     MOZ_ASSERT(mReadyToExecute);
--- a/js/xpconnect/loader/ScriptPreloader.h
+++ b/js/xpconnect/loader/ScriptPreloader.h
@@ -86,16 +86,21 @@ public:
                     ProcessType processType, nsTArray<uint8_t>&& xdrData,
                     TimeStamp loadTime);
 
     // Initializes the script cache from the startup script cache file.
     Result<Ok, nsresult> InitCache(const nsAString& = NS_LITERAL_STRING("scriptCache"));
 
     Result<Ok, nsresult> InitCache(const Maybe<ipc::FileDescriptor>& cacheFile, ScriptCacheChild* cacheChild);
 
+    bool Active()
+    {
+      return mCacheInitialized && !mStartupFinished;
+    }
+
 private:
     Result<Ok, nsresult> InitCacheInternal();
 
 public:
     void Trace(JSTracer* trc);
 
     static ProcessType CurrentProcessType()
     {
@@ -350,16 +355,17 @@ private:
     // thread for quite as long.
     static constexpr int MAX_MAINTHREAD_DECODE_SIZE = 50 * 1024;
 
     ScriptPreloader();
 
     void ForceWriteCacheFile();
     void Cleanup();
 
+    void FinishPendingParses(MonitorAutoLock& aMal);
     void InvalidateCache();
 
     // Opens the cache file for reading.
     Result<Ok, nsresult> OpenCache();
 
     // Writes a new cache file to disk. Must not be called on the main thread.
     Result<Ok, nsresult> WriteCache();
 
@@ -376,17 +382,17 @@ private:
 
     // Waits for the given cached script to finish compiling off-thread, or
     // decodes it synchronously on the main thread, as appropriate.
     JSScript* WaitForCachedScript(JSContext* cx, CachedScript* script);
 
     void DecodeNextBatch(size_t chunkSize);
 
     static void OffThreadDecodeCallback(void* token, void* context);
-    void FinishOffThreadDecode();
+    void MaybeFinishOffThreadDecode();
     void DoFinishOffThreadDecode();
 
     size_t ShallowHeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
     {
         return (mallocSizeOf(this) + mScripts.ShallowSizeOfExcludingThis(mallocSizeOf) +
                 mallocSizeOf(mSaveThread.get()) + mallocSizeOf(mProfD.get()));
     }
 
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -643,17 +643,17 @@ mozJSComponentLoader::ObjectForLocation(
         // XDR encoded modules in omni.ja). Also, XDR decoding is relatively
         // fast. When we're not using the startup cache, we want to use non-lazy
         // source code so that we can use lazy parsing.
         // See bug 1303754.
         CompileOptions options(cx);
         options.setNoScriptRval(true)
                .setVersion(JSVERSION_LATEST)
                .setFileAndLine(nativePath.get(), 1)
-               .setSourceIsLazy(!!cache);
+               .setSourceIsLazy(cache || ScriptPreloader::GetSingleton().Active());
 
         if (realFile) {
             AutoMemMap map;
             MOZ_TRY(map.init(aComponentFile));
 
             // Note: exceptions will get handled further down;
             // don't early return for them here.
             auto buf = map.get<char>();
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -135,17 +135,17 @@ public:
           mActive = false;
       }
       return NS_OK;
   }
 
   nsresult Dispatch()
   {
       nsCOMPtr<nsIRunnable> self(this);
-      return NS_IdleDispatchToCurrentThread(self.forget(), 1000);
+      return NS_IdleDispatchToCurrentThread(self.forget(), 2500);
   }
 
   void Start(bool aContinuation = false, bool aPurge = false)
   {
       if (mContinuation) {
           mContinuation = aContinuation;
       }
       mPurge = aPurge;
--- a/js/xpconnect/src/XPCThrower.cpp
+++ b/js/xpconnect/src/XPCThrower.cpp
@@ -80,17 +80,17 @@ XPCThrower::Throw(nsresult rv, XPCCallCo
     NS_ENSURE_TRUE_VOID(sz);
 
     if (sz && sVerbose)
         Verbosify(ccx, &sz, false);
 
     dom::Throw(ccx, rv, nsDependentCString(sz));
 
     if (sz && sz != format)
-        JS_smprintf_free(sz);
+        js_free(sz);
 }
 
 
 // static
 void
 XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx)
 {
     char* sz;
@@ -122,17 +122,17 @@ XPCThrower::ThrowBadResult(nsresult rv, 
     NS_ENSURE_TRUE_VOID(sz);
 
     if (sz && sVerbose)
         Verbosify(ccx, &sz, true);
 
     dom::Throw(ccx, result, nsDependentCString(sz));
 
     if (sz)
-        JS_smprintf_free(sz);
+        js_free(sz);
 }
 
 // static
 void
 XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx)
 {
     char* sz;
     const char* format;
@@ -144,17 +144,17 @@ XPCThrower::ThrowBadParam(nsresult rv, u
     NS_ENSURE_TRUE_VOID(sz);
 
     if (sz && sVerbose)
         Verbosify(ccx, &sz, true);
 
     dom::Throw(ccx, rv, nsDependentCString(sz));
 
     if (sz)
-        JS_smprintf_free(sz);
+        js_free(sz);
 }
 
 
 // static
 void
 XPCThrower::Verbosify(XPCCallContext& ccx,
                       char** psz, bool own)
 {
@@ -168,12 +168,12 @@ XPCThrower::Verbosify(XPCCallContext& cc
         if (!name) {
             name = "";
         }
         sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name).release();
     }
 
     if (sz) {
         if (own)
-            JS_smprintf_free(*psz);
+            js_free(*psz);
         *psz = sz;
     }
 }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1725,17 +1725,18 @@ public:
     static void Trace(JSTracer* trc, JSObject* obj);
 
     void AutoTrace(JSTracer* trc) {
         TraceSelf(trc);
     }
 
     inline void SweepTearOffs();
 
-    // Returns a string that shuld be free'd using JS_smprintf_free (or null).
+    // Returns a string that should be freed with js_free, or nullptr on
+    // failure.
     char* ToString(XPCWrappedNativeTearOff* to = nullptr) const;
 
     static nsIXPCScriptable* GatherProtoScriptable(nsIClassInfo* classInfo);
 
     bool HasExternalReference() const {return mRefCnt > 1;}
 
     void Suspect(nsCycleCollectionNoteRootCallback& cb);
     void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
--- a/js/xpco