Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 20 Sep 2017 17:18:21 -0700
changeset 382008 61340c7debf6dccec3b863d1bc00426feac42fe7
parent 381938 319a34bea9e4f3459886b5b9e835bd338320f1fd (current diff)
parent 382007 789e21a08030b00acd832a58268680dede2e7a1b (diff)
child 382009 f8dd3f21e434be32fe5901849f1723b0e64cf668
push id32543
push userkwierso@gmail.com
push dateThu, 21 Sep 2017 00:18:37 +0000
treeherdermozilla-central@61340c7debf6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to central, a=merge MozReview-Commit-ID: JpqY5uEi1nf
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderCanvasLayer.cpp
gfx/layers/wr/WebRenderColorLayer.cpp
gfx/layers/wr/WebRenderContainerLayer.cpp
gfx/layers/wr/WebRenderImageLayer.cpp
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderPaintedLayer.cpp
gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
gfx/layers/wr/WebRenderTextLayer.cpp
gfx/layers/wr/WebRenderUserData.cpp
gfx/layers/wr/WebRenderUserData.h
layout/forms/nsButtonFrameRenderer.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsTextFrame.cpp
layout/ipc/RenderFrameParent.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/painting/nsImageRenderer.cpp
layout/style/ServoBindings.cpp
layout/tables/nsTableFrame.cpp
layout/xul/nsImageBoxFrame.cpp
taskcluster/ci/test/tests.yml
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1497,17 +1497,17 @@ DocAccessible::DoInitialUpdate()
       if (RefPtr<dom::TabChild> tabChild = dom::TabChild::GetFrom(docShell)) {
         DocAccessibleChild* ipcDoc = new DocAccessibleChild(this, tabChild);
         SetIPCDoc(ipcDoc);
         if (IsRoot()) {
           tabChild->SetTopLevelDocAccessibleChild(ipcDoc);
         }
 
 #if defined(XP_WIN)
-        IAccessibleHolder holder(CreateHolderFromAccessible(this));
+        IAccessibleHolder holder(CreateHolderFromAccessible(WrapNotNull(this)));
         MOZ_DIAGNOSTIC_ASSERT(!holder.IsNull());
         int32_t childID = AccessibleWrap::GetChildIDFor(this);
 #else
         int32_t holder = 0, childID = 0;
 #endif
         tabChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0, childID,
                                                 holder);
       }
--- a/accessible/ipc/win/COMPtrTypes.cpp
+++ b/accessible/ipc/win/COMPtrTypes.cpp
@@ -6,41 +6,39 @@
 
 #include "mozilla/a11y/COMPtrTypes.h"
 
 #include "Accessible2_3.h"
 #include "MainThreadUtils.h"
 #include "mozilla/a11y/Accessible.h"
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/a11y/HandlerProvider.h"
+#include "mozilla/Assertions.h"
 #include "mozilla/Move.h"
 #include "mozilla/mscom/MainThreadHandoff.h"
 #include "mozilla/mscom/Utils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/RefPtr.h"
 #include "nsXULAppAPI.h"
 
 using mozilla::mscom::MainThreadHandoff;
 using mozilla::mscom::ProxyUniquePtr;
 using mozilla::mscom::STAUniquePtr;
 
 namespace mozilla {
 namespace a11y {
 
 IAccessibleHolder
-CreateHolderFromAccessible(Accessible* aAccToWrap)
+CreateHolderFromAccessible(NotNull<Accessible*> aAccToWrap)
 {
-  MOZ_ASSERT(aAccToWrap && NS_IsMainThread());
-  if (!aAccToWrap) {
-    return nullptr;
-  }
+  MOZ_ASSERT(NS_IsMainThread());
 
   STAUniquePtr<IAccessible> iaToProxy;
   aAccToWrap->GetNativeInterface(mscom::getter_AddRefs(iaToProxy));
-  MOZ_ASSERT(iaToProxy);
+  MOZ_DIAGNOSTIC_ASSERT(iaToProxy);
   if (!iaToProxy) {
     return nullptr;
   }
 
   static const bool useHandler =
     Preferences::GetBool("accessibility.handler.enabled", false) &&
     IsHandlerRegistered();
 
@@ -48,17 +46,17 @@ CreateHolderFromAccessible(Accessible* a
   if (useHandler) {
     payload = new HandlerProvider(IID_IAccessible,
                                   mscom::ToInterceptorTargetPtr(iaToProxy));
   }
 
   ProxyUniquePtr<IAccessible> intercepted;
   HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), payload,
                                                 (IAccessible**) mscom::getter_AddRefs(intercepted));
-  MOZ_ASSERT(SUCCEEDED(hr));
+  MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr));
   if (FAILED(hr)) {
     return nullptr;
   }
 
   return IAccessibleHolder(Move(intercepted));
 }
 
 IHandlerControlHolder
--- a/accessible/ipc/win/COMPtrTypes.h
+++ b/accessible/ipc/win/COMPtrTypes.h
@@ -4,29 +4,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_COMPtrTypes_h
 #define mozilla_a11y_COMPtrTypes_h
 
 #include "mozilla/a11y/AccessibleHandler.h"
 #include "mozilla/mscom/COMPtrHolder.h"
+#include "mozilla/NotNull.h"
 
 #include <oleacc.h>
 
 namespace mozilla {
 namespace a11y {
 
 typedef mozilla::mscom::COMPtrHolder<IAccessible, IID_IAccessible> IAccessibleHolder;
 typedef mozilla::mscom::COMPtrHolder<IDispatch, IID_IDispatch> IDispatchHolder;
 
 class Accessible;
 
 IAccessibleHolder
-CreateHolderFromAccessible(Accessible* aAccToWrap);
+CreateHolderFromAccessible(NotNull<Accessible*> aAccToWrap);
 
 typedef mozilla::mscom::COMPtrHolder<IHandlerControl, IID_IHandlerControl> IHandlerControlHolder;
 
 IHandlerControlHolder
 CreateHolderFromHandlerControl(mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl);
 
 } // namespace a11y
 } // namespace mozilla
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
@@ -18,19 +18,16 @@ requestLongerTimeout(5);
 const EXPECTED_REFLOWS_FIRST_OPEN = [
   // Bug 1357054
   {
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_onChanged@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult/<@chrome://global/content/bindings/autocomplete.xml",
-      "setTimeout handler*_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
-      "_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml"
     ],
     times: 18, // This number should only ever go down - never up.
   },
 
   {
     stack: [
       "_rebuild@chrome://browser/content/search/search.xml",
       "set_popup@chrome://browser/content/search/search.xml",
@@ -62,18 +59,16 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
     ],
     times: 6, // This number should only ever go down - never up.
   },
 
   {
     stack: [
       "adjustHeight@chrome://global/content/bindings/autocomplete.xml",
       "_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
-      "setTimeout handler*_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml",
     ],
     times: 51, // This number should only ever go down - never up.
   },
 
   {
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
--- a/browser/branding/official/content/about-wordmark.svg
+++ b/browser/branding/official/content/about-wordmark.svg
@@ -1,8 +1,13 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="142" height="38" viewBox="0 0 142 38">
+<svg xmlns="http://www.w3.org/2000/svg" width="338" height="42" viewBox="0 0 338 42">
   <path d="M136.837 10.212H131.5l-5.7 9.9-5.645-9.9h-5.542l8.364 12.778-9.437 14.265h5.337l6.723-11.443 6.62 11.444h5.7l-9.391-14.471zM22.844 37.255h4.721V10.212h-4.721zm15.42-21.339l-.462-5.7h-4.054v27.039h4.721V23.306c0-4.205 3.079-8.878 6.466-8.878a8.485 8.485 0 0 1 2.36.308l.872-4.618A11.5 11.5 0 0 0 45.5 9.81c-3.284 0-5.8 2.053-7.236 6.106zM0 37.255h4.875V21.707h11.546v-3.849H4.875V5.8h13.342l.564-3.9H0zM25.153.163A3.14 3.14 0 0 0 21.869 3.4a3.128 3.128 0 0 0 3.284 3.182A3.143 3.143 0 0 0 28.489 3.4 3.154 3.154 0 0 0 25.153.163zm76.491 9.647c-7.7 0-12.111 5.585-12.111 13.949 0 8.57 4.362 14.112 12.059 14.112 7.646 0 12.059-5.8 12.059-14.163.001-8.57-4.309-13.898-12.007-13.898zm-.051 24.264c-4.516 0-6.979-3.284-6.979-10.315 0-7.082 2.515-10.152 7.03-10.152 4.464 0 6.928 3.07 6.928 10.1 0 7.083-2.463 10.367-6.979 10.367zM82.47 8.339c0-2.617 1.026-4.541 4-4.541a11.567 11.567 0 0 1 4.721 1.026l1.488-3.438A14.913 14.913 0 0 0 86.216 0c-5.491 0-8.467 3.447-8.467 7.963v2.249h-4.824v3.643h4.824v23.4h4.721v-23.4h6.055l.513-3.643H82.47zM59.952 9.81c-6.979 0-11.238 5.79-11.238 14.206 0 8.57 4.413 13.855 11.957 13.855a14.741 14.741 0 0 0 9.442-3.387l-2.053-2.822a11.384 11.384 0 0 1-7.03 2.361c-3.9 0-6.825-2.412-7.287-8.672h17.242c.051-.616.1-1.488.1-2.412.003-8.263-3.846-13.129-11.133-13.129zm6.466 12.051H53.743c.359-6 2.72-8.3 6.312-8.3 4.259 0 6.363 2.711 6.363 8z" fill="#fff"/>
-  <path d="M139.854 10.228a2.134 2.134 0 0 0-2.128 2.155 2.093 2.093 0 0 0 2.128 2.12 2.137 2.137 0 1 0 0-4.275zm0 3.954a1.755 1.755 0 0 1-1.772-1.8 1.783 1.783 0 0 1 1.772-1.826 1.761 1.761 0 0 1 1.79 1.808 1.779 1.779 0 0 1-1.79 1.819zm.891-2.333c0-.481-.33-.721-1.015-.721h-.614v2.422h.374v-.988h.321l.579.988h.445l-.659-1.051a.659.659 0 0 0 .568-.65zm-1.256.4v-.81h.294c.374 0 .579.1.579.41 0 .294-.2.4-.525.4z" fill="#fff"/>
+  <path d="M182.953 39.384L180.9 42c-3.8-3.386-7.284-4.309-13.542-4.309-8.464 0-14.312-6.258-14.312-17.954 0-11.593 5.9-18.21 14.312-18.21 8.566 0 14.363 6.309 14.363 18.159 0 9.644-3.693 14.414-8.874 16.312a16.2 16.2 0 0 1 10.106 3.386zm-15.594-4.206c6.874 0 11.131-4.924 11.131-15.491 0-10.67-4.36-15.543-11.131-15.543-6.617 0-11.08 4.924-11.08 15.594 0 10.515 4.566 15.44 11.08 15.44z" fill="#fff"/>
+  <path d="M206.037 37.229h-2.565l-.154-4.771c-1.9 3.18-4.617 5.335-8.772 5.335-4.822 0-7.592-2.924-7.592-8.207V10.4h2.975v18.879c0 4.258 1.8 6.053 5.283 6.053 3.539 0 6-2.308 7.848-5.489V10.4h2.975z" fill="#fff"/>
+  <path d="M232.505 35.691l-.667 2.1a4.731 4.731 0 0 1-4.155-4.463 9.45 9.45 0 0 1-8.361 4.463c-5.181 0-8.31-3.232-8.31-8 0-5.643 4.258-8.669 11.131-8.669h5.13v-2.615c0-4.258-1.744-6.155-6.207-6.155a21.849 21.849 0 0 0-7.284 1.539l-.769-2.257a22.421 22.421 0 0 1 8.464-1.8c6.1 0 8.772 3.026 8.772 8.515v12.93c-.001 2.975.82 3.847 2.256 4.412zm-5.232-5.13v-7.284h-4.668c-5.386 0-8.413 2.1-8.413 6.361 0 3.693 2.1 5.745 5.643 5.745 3.437 0 5.797-1.693 7.438-4.822z" fill="#fff"/>
+  <path d="M256.82 18.045v19.184h-2.975V18.455c0-4.411-1.8-6.207-5.078-6.207-3.642 0-6.1 2.257-8.31 5.54v19.441h-2.975V10.4h2.565l.256 4.565c2.154-3.026 5.13-5.13 9.028-5.13 4.869.003 7.489 3.029 7.489 8.21z" fill="#fff"/>
+  <path d="M276.312 36.1a10.026 10.026 0 0 1-5.643 1.693c-4.052 0-6.566-2.411-6.566-7.079v-17.9h-4.513V10.4h4.51V3.99l2.975-.359V10.4H274l-.359 2.411h-6.566v17.75c0 3.129 1.231 4.668 3.95 4.668a7.523 7.523 0 0 0 4.1-1.231z" fill="#fff"/>
+  <path d="M297.856 37.229h-2.565l-.154-4.771c-1.9 3.18-4.617 5.335-8.772 5.335-4.822 0-7.592-2.924-7.592-8.207V10.4h2.975v18.879c0 4.258 1.8 6.053 5.284 6.053 3.539 0 6-2.308 7.848-5.489V10.4h2.975z" fill="#fff"/>
+  <path d="M337.251 18.045v19.184h-2.975V18.455c0-4.36-1.8-6.207-4.565-6.207-3.232 0-5.489 2.257-7.54 5.54v19.441H319.2V18.455c0-4.36-1.8-6.207-4.565-6.207-3.232 0-5.54 2.257-7.541 5.54v19.441h-2.975V10.4h2.565l.256 4.514c2-3.026 4.771-5.078 8.259-5.078a6.432 6.432 0 0 1 6.617 5.335c2.1-3.18 4.873-5.335 8.464-5.335 4.304.002 6.971 3.131 6.971 8.209z" fill="#fff"/>
 </svg>
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -860,16 +860,21 @@ var MessageQueue = {
    * Sends queued data when the remaining idle time is enough or waiting too
    * long; otherwise, request an idle time again. If the |deadline| is not
    * given, this function is going to schedule the first request.
    *
    * @param deadline (object)
    *        An IdleDeadline object passed by requestIdleCallback().
    */
   sendWhenIdle(deadline) {
+    if (!content) {
+      // The frameloader is being torn down. Nothing more to do.
+      return;
+    }
+
     if (deadline) {
       if (deadline.didTimeout || deadline.timeRemaining() > MessageQueue.NEEDED_IDLE_PERIOD_MS) {
         MessageQueue.send();
         return;
       }
     } else if (MessageQueue._idleCallbackID) {
       // Bail out if there's a pending run.
       return;
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -215,17 +215,17 @@
   list-style-image: url(chrome://global/skin/icons/arrow-dropdown-16.svg);
   transition: opacity 0.15s ease;
 }
 
 #urlbar[switchingtabs] > .urlbar-textbox-container > .urlbar-history-dropmarker {
   transition: none;
 }
 
-#navigator-toolbox:not(:hover) > #nav-bar:not([customizing="true"]) > #nav-bar-customization-target > #urlbar-container > #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+#nav-bar:not([customizing="true"]) > #nav-bar-customization-target > #urlbar-container:not(:hover) > #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 #pageActionButton {
   list-style-image: url("chrome://browser/skin/page-action.svg");
 }
 
 @keyframes bookmark-animation {
--- a/build/valgrind/x86_64-redhat-linux-gnu.sup
+++ b/build/valgrind/x86_64-redhat-linux-gnu.sup
@@ -225,16 +225,47 @@
    Skia and CPUID, Jan 2017, #2
    Memcheck:Cond
    fun:_ZN6SkOpts4InitEv
    fun:_ZN11gfxPlatform4InitEv
    fun:_ZN11gfxPlatform11GetPlatformEv
    fun:_ZN7mozilla3dom*Content*
 }
 
+# False positives triggered by rust 1.20.0 (at least) builds of stylo.
+# See bug 1394696. The diagnosis is an llvm optimization transforming
+# `if A && B` to `if B && A` if is can be proven that A is false
+# whenever B is uninitialized. Confusing, but valid.
+#
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0x113ED01E: selectors::matching::matches_complex_selector_internal (option.rs:421)
+#    by 0x113ECF19: selectors::matching::matches_complex_selector (matching.rs:501)
+#    by 0x113EBAC0: <style::selector_map::SelectorMap<style::stylist::Rule>>::get_matching_rules (matching.rs:397)
+{
+  Bug 1394696 Stylo selector, Sept 2017, part 1
+  Memcheck:Cond
+  fun:_ZN9selectors8matching33matches_complex_selector_internal*
+  fun:_ZN9selectors8matching24matches_complex_selector*
+  ...
+  fun:_ZN69_$LT$style..selector_map..SelectorMap$LT$style..stylist..Rule$GT$$GT$18get_matching_rules*
+}
+
+# Conditional jump or move depends on uninitialised value(s)
+#    at 0x113EFFDE: selectors::matching::matches_complex_selector_internal (option.rs:421)
+#    by 0x113EFED9: selectors::matching::matches_complex_selector (matching.rs:501)
+#    by 0x113DFE55: style::stylist::Stylist::match_revalidation_selectors::{{closure}} (matching.rs:397)
+{
+  Bug 1394696 Stylo selector, Sept 2017, part 2
+  Memcheck:Cond
+  fun:_ZN9selectors8matching33matches_complex_selector_internal*
+  fun:_ZN9selectors8matching24matches_complex_selector*
+  ...
+  fun:_ZN5style9traversal13compute_style*
+  fun:recalc_style_at<style::gecko::wrapper::GeckoElement,style::gecko::traversal::RecalcStyleOnly,closure>
+}
 
 ###################################################
 #  For valgrind-mochitest ("tc-M-V [tier 2]") runs on taskcluster.
 #  See bug 1248365.
 #  These are specific to Ubuntu 12.04.5, 64-bit.
 ###################################################
 
 
--- a/client.py
+++ b/client.py
@@ -107,32 +107,34 @@ def update_nspr_or_nss(tag, depfile, des
   destination = destination.rstrip('/')
   permanent_patch_dir = destination + '/patches'
   temporary_patch_dir = destination + '.patches'
   if os.path.exists(temporary_patch_dir):
     print "please clean up leftover directory " + temporary_patch_dir
     sys.exit(2)
   warn_if_patch_exists(permanent_patch_dir)
   # protect patch directory from being removed by do_hg_replace
-  shutil.move(permanent_patch_dir, temporary_patch_dir)
+  if os.path.exists(permanent_patch_dir):
+    shutil.move(permanent_patch_dir, temporary_patch_dir)
   # now update the destination
   print "reverting to HG version of %s to get its blank line state" % depfile
   check_call_noisy([options.hg, 'revert', depfile])
   old_state = get_trailing_blank_line_state(depfile)
   print "old state of %s is: %s" % (depfile, old_state)
   do_hg_replace(destination, hgpath, tag, HG_EXCLUSIONS, options.hg)
   new_state = get_trailing_blank_line_state(depfile)
   print "new state of %s is: %s" % (depfile, new_state)
   if old_state == new_state:
     print "toggling blank line in: ", depfile
     toggle_trailing_blank_line(depfile)
   tag_file = destination + "/TAG-INFO"
   print >>file(tag_file, "w"), tag
   # move patch directory back to a subdirectory
-  shutil.move(temporary_patch_dir, permanent_patch_dir)
+  if os.path.exists(temporary_patch_dir):
+    shutil.move(temporary_patch_dir, permanent_patch_dir)
 
 def warn_if_patch_exists(path):
   # If the given patch directory exists and contains at least one file,
   # then print warning and wait for the user to acknowledge.
   if os.path.isdir(path) and os.listdir(path):
     print "========================================"
     print "WARNING: At least one patch file exists"
     print "in directory: " + path
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -14980,65 +14980,66 @@ nsDocShell::ShouldPrepareForIntercept(ns
     return NS_OK;
   }
 
   if (mSandboxFlags) {
     // If we're sandboxed, don't intercept.
     return NS_OK;
   }
 
+  uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
+  if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
+    // If cookies are disabled, don't intercept.
+    return NS_OK;
+  }
+
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (!swm) {
     return NS_OK;
   }
 
-  nsresult result;
-  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
-    do_GetService(THIRDPARTYUTIL_CONTRACTID, &result);
-  NS_ENSURE_SUCCESS(result, result);
-
-  if (mCurrentURI &&
-      nsContentUtils::CookiesBehavior() == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
-    nsAutoCString uriSpec;
-    if (!(mCurrentURI->GetSpecOrDefault().EqualsLiteral("about:blank"))) {
-      // Reject the interception of third-party iframes if the cookie behaviour
-      // is set to reject all third-party cookies (1). In case that this pref
-      // is not set or can't be read, we default to allow all cookies (0) as
-      // this is the default value in all.js.
+  if (!aIsNonSubresourceRequest) {
+    nsCOMPtr<nsIDocument> doc = GetDocument();
+    if (!doc) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    ErrorResult rv;
+    *aShouldIntercept = swm->IsControlled(doc, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.StealNSResult();
+    }
+
+    return NS_OK;
+  }
+
+  // If the user has set a cookie policy that restricts cookies, then
+  // avoid intercepting 3rd party iframes.
+  if (cookieBehavior != nsICookieService::BEHAVIOR_ACCEPT) {
+    nsCOMPtr<nsIDocShellTreeItem> parent;
+    GetSameTypeParent(getter_AddRefs(parent));
+    nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
+                                                       : nullptr;
+    if (parentWindow) {
+      nsresult rv = NS_OK;
+      nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
+        do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
+      NS_ENSURE_SUCCESS(rv, rv);
+
       bool isThirdPartyURI = true;
-      result = thirdPartyUtil->IsThirdPartyURI(mCurrentURI, aURI,
-                                               &isThirdPartyURI);
-      if (NS_FAILED(result)) {
-          return result;
-      }
-
-      if (isThirdPartyURI) {
+      rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI, &isThirdPartyURI);
+      if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
         return NS_OK;
       }
     }
   }
 
-  if (aIsNonSubresourceRequest) {
-    nsCOMPtr<nsIPrincipal> principal =
-      BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
-    *aShouldIntercept = swm->IsAvailable(principal, aURI);
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIDocument> doc = GetDocument();
-  if (!doc) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  ErrorResult rv;
-  *aShouldIntercept = swm->IsControlled(doc, rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
-  }
-
+  nsCOMPtr<nsIPrincipal> principal =
+    BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
+  *aShouldIntercept = swm->IsAvailable(principal, aURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
 {
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (!swm) {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -9057,16 +9057,30 @@ nsContentUtils::StorageAllowedForWindow(
     return InternalStorageAllowedForPrincipal(principal, aWindow);
   }
 
   return StorageAccess::eDeny;
 }
 
 // static, public
 nsContentUtils::StorageAccess
+nsContentUtils::StorageAllowedForDocument(nsIDocument* aDoc)
+{
+  MOZ_ASSERT(aDoc);
+
+  if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) {
+    nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
+    return InternalStorageAllowedForPrincipal(principal, inner);
+  }
+
+  return StorageAccess::eDeny;
+}
+
+// static, public
+nsContentUtils::StorageAccess
 nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal)
 {
   return InternalStorageAllowedForPrincipal(aPrincipal, nullptr);
 }
 
 // static, private
 void
 nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
@@ -9134,17 +9148,17 @@ nsContentUtils::InternalStorageAllowedFo
   // calling context is chrome.
   if (aPrincipal->GetIsNullPrincipal()) {
     return StorageAccess::eDeny;
   }
 
   if (aWindow) {
     // If the document is sandboxed, then it is not permitted to use storage
     nsIDocument* document = aWindow->GetExtantDoc();
-    if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
+    if (document && document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
       return StorageAccess::eDeny;
     }
 
     // Check if we are in private browsing, and record that fact
     if (IsInPrivateBrowsing(document)) {
       access = StorageAccess::ePrivateBrowsing;
     }
   }
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2921,16 +2921,27 @@ public:
    *
    * This logic is intended to be shared between the different forms of
    * persistent storage which are available to web pages. Cookies don't use
    * this logic, and security logic related to them must be updated separately.
    */
   static StorageAccess StorageAllowedForWindow(nsPIDOMWindowInner* aWindow);
 
   /*
+   * Checks if storage for the given document is permitted by a combination of
+   * the user's preferences, and whether the document's window is a third-party
+   * iframe.
+   *
+   * Note, this may be used on documents during the loading process where
+   * the window's extant document has not been set yet.  The code in
+   * StorageAllowedForWindow(), however, will not work in these cases.
+   */
+  static StorageAccess StorageAllowedForDocument(nsIDocument* aDoc);
+
+  /*
    * Checks if storage for the given principal is permitted by the user's
    * preferences. The caller is assumed to not be a third-party iframe.
    * (if that is possible, the caller should use StorageAllowedForWindow)
    */
   static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal);
 
   /*
    * Serializes a HTML nsINode into its markup representation.
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -46,8 +46,9 @@ support-files =
 [test_cache_orphaned_body.html]
 scheme=https
 [test_cache_padding.html]
 [test_cache_untrusted.html]
 [test_cache_updateUsage.html]
 [test_chrome_constructor.html]
 [test_cache_worker_gc.html]
 scheme=https
+[test_cache_tons_of_fd.html]
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/test_cache_tons_of_fd.html
@@ -0,0 +1,111 @@
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test cache to create tons of fds</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="driver.js"></script>
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+  function setupTestIframe() {
+  return new Promise(function(resolve) {
+    var iframe = document.createElement("iframe");
+    iframe.src = "empty.html";
+    iframe.onload = function() {
+      window.caches = iframe.contentWindow.caches;
+      resolve();
+    };
+    document.body.appendChild(iframe);
+  });
+}
+
+function clearStorage() {
+  return new Promise(function(resolve, reject) {
+    var qms = SpecialPowers.Services.qms;
+    var principal = SpecialPowers.wrap(document).nodePrincipal;
+    var request = qms.clearStoragesForPrincipal(principal);
+    var cb = SpecialPowers.wrapCallback(resolve);
+    request.callback = cb;
+  });
+}
+
+async function testCreateTonsOfFD() {
+  const number_of_fd = 5120;
+  const name = 'cacheTonsOfFD';
+  const url = "foo.com"
+  const body = "This is a body";
+
+  info("Stage A: Cached a Request/Response pairs");
+  let cache = await caches.open(name);
+  let request = new Request(url);
+  let response = new Response(body);
+  await cache.put(request, response);
+
+  info("Stage B: Read the cached response mutliple times");
+  let promise_array = [];
+  for (let i = 0; i < number_of_fd; ++i) {
+    let promise = cache.match(request);
+    promise_array.push(promise);
+  }
+  let cached_response_array = [];
+  try {
+    cached_response_array = await Promise.all(promise_array);
+  } catch (e) {
+    throw("Fail to open tons of files with error: " + e);
+  }
+
+  if (cached_response_array.length != number_of_fd) {
+    throw("Fail to cache.match the cached responses");
+  }
+
+  info("Stage C: Consume the cached body")
+  for (let i = 0; i < number_of_fd; ++i) {
+    if (!cached_response_array[i]) {
+      // Reduce the checking message.
+      throw("The cached response doesn't exist");
+    }
+
+    let bodyText = "";
+    try {
+      bodyText = await cached_response_array[i].text();
+    } catch (e) {
+      throw("Fail to consume the cached response's body with error: " + e);
+    }
+
+    if (bodyText != body) {
+      // Reduce the checking message.
+      throw("The cached body doeen't be the same as original one");
+    }
+  }
+
+  ok(true, "Doesn't crash or timeout");
+  return Promise.resolve();
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({
+  "set": [["dom.caches.enabled", true],
+          ["dom.caches.testing.enabled", true],
+          ["dom.quotaManager.testing", true]]
+}, async function() {
+  await setupTestIframe();
+
+  info("Stage 1: Clean storage.");
+  await clearStorage();
+
+  info("Stage 2: Verify open lots of files at the same time doesn't crash " +
+       "the browser");
+  try {
+    await testCreateTonsOfFD();
+  } catch (e) {
+    ok(false, e);
+  }
+
+  await SimpleTest.finish();
+});
+</script>
+</body>
+</html>
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -690,17 +690,20 @@ IDBDatabase::Transaction(JSContext* aCx,
       return NS_ERROR_DOM_TYPE_ERR;
 
     default:
       MOZ_CRASH("Unknown mode!");
   }
 
   RefPtr<IDBTransaction> transaction =
     IDBTransaction::Create(aCx, this, sortedStoreNames, mode);
-  MOZ_ASSERT(transaction);
+  if (NS_WARN_IF(!transaction)) {
+    IDB_REPORT_INTERNAL_ERR();
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
 
   BackgroundTransactionChild* actor =
     new BackgroundTransactionChild(transaction);
 
   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld]: "
                  "database(%s).transaction(%s)",
                "IndexedDB %s: C T[%lld]: IDBDatabase.transaction()",
                IDB_LOG_ID_STRING(),
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -225,34 +225,39 @@ IDBTransaction::Create(JSContext* aCx, I
 
   RefPtr<IDBTransaction> transaction =
     new IDBTransaction(aDatabase, aObjectStoreNames, aMode);
   IDBRequest::CaptureCaller(aCx, transaction->mFilename, &transaction->mLineNo,
                             &transaction->mColumn);
 
   transaction->SetScriptOwner(aDatabase->GetScriptOwner());
 
+  if (!NS_IsMainThread()) {
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(workerPrivate);
+
+    workerPrivate->AssertIsOnWorkerThread();
+
+    nsAutoPtr<WorkerHolder> workerHolder(
+      new WorkerHolder(workerPrivate, transaction));
+    if (NS_WARN_IF(!workerHolder->HoldWorker(workerPrivate, Canceling))) {
+      return nullptr;
+    }
+
+    transaction->mWorkerHolder = Move(workerHolder);
+  }
+
   nsCOMPtr<nsIRunnable> runnable = do_QueryObject(transaction);
   nsContentUtils::RunInMetastableState(runnable.forget());
 
   transaction->mCreating = true;
 
   aDatabase->RegisterTransaction(transaction);
   transaction->mRegistered = true;
 
-  if (!NS_IsMainThread()) {
-    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(workerPrivate);
-
-    workerPrivate->AssertIsOnWorkerThread();
-
-    transaction->mWorkerHolder = new WorkerHolder(workerPrivate, transaction);
-    MOZ_ALWAYS_TRUE(transaction->mWorkerHolder->HoldWorker(workerPrivate, Canceling));
-  }
-
   return transaction.forget();
 }
 
 // static
 IDBTransaction*
 IDBTransaction::GetCurrent()
 {
   using namespace mozilla::ipc;
--- a/dom/workers/ServiceWorker.cpp
+++ b/dom/workers/ServiceWorker.cpp
@@ -88,16 +88,22 @@ ServiceWorker::PostMessage(JSContext* aC
 
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetParentObject());
   if (!window || !window->GetExtantDoc()) {
     NS_WARNING("Trying to call post message from an invalid dom object.");
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
+  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
+  if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
   UniquePtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
   ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
   aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));
 }
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -823,20 +823,26 @@ ServiceWorkerManager::Register(mozIDOMWi
 {
   AssertIsOnMainThread();
 
   if (NS_WARN_IF(!aWindow)) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   auto* window = nsPIDOMWindowInner::From(aWindow);
+
+  // Don't allow a service worker to be registered if storage is restricted
+  // for the window.
+  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
+  if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  if (!doc) {
-    return NS_ERROR_FAILURE;
-  }
+  MOZ_ASSERT(doc);
 
   // Don't allow service workers to register when the *document* is chrome.
   if (NS_WARN_IF(nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()))) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> outerWindow = window->GetOuterWindow();
   bool serviceWorkersTestingEnabled =
@@ -1069,24 +1075,29 @@ ServiceWorkerManager::GetRegistrations(m
 {
   AssertIsOnMainThread();
 
   if (NS_WARN_IF(!aWindow)) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   auto* window = nsPIDOMWindowInner::From(aWindow);
-  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  if (NS_WARN_IF(!doc)) {
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+
+  // Don't allow a service worker to access service worker registrations
+  // from a window with storage disabled.  If these windows can access
+  // the registration it increases the chance they can bypass the storage
+  // block via postMessage(), etc.
+  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
+  if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
+    return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // Don't allow service workers to register when the *document* is chrome for
   // now.
-  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
+  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(window->GetExtantDoc()->NodePrincipal()));
 
   nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
   ErrorResult result;
   RefPtr<Promise> promise = Promise::Create(sgo, result);
   if (result.Failed()) {
     return result.StealNSResult();
   }
 
@@ -1182,24 +1193,29 @@ ServiceWorkerManager::GetRegistration(mo
 {
   AssertIsOnMainThread();
 
   if (NS_WARN_IF(!aWindow)) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   auto* window = nsPIDOMWindowInner::From(aWindow);
-  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  if (NS_WARN_IF(!doc)) {
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+
+  // Don't allow a service worker to access service worker registrations
+  // from a window with storage disabled.  If these windows can access
+  // the registration it increases the chance they can bypass the storage
+  // block via postMessage(), etc.
+  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
+  if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
+    return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // Don't allow service workers to register when the *document* is chrome for
   // now.
-  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
+  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(window->GetExtantDoc()->NodePrincipal()));
 
   nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
   ErrorResult result;
   RefPtr<Promise> promise = Promise::Create(sgo, result);
   if (result.Failed()) {
     return result.StealNSResult();
   }
 
@@ -2173,17 +2189,25 @@ ServiceWorkerManager::GetServiceWorkerRe
 }
 
 already_AddRefed<ServiceWorkerRegistrationInfo>
 ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIDocument* aDoc)
 {
   MOZ_ASSERT(aDoc);
   nsCOMPtr<nsIURI> documentURI = aDoc->GetDocumentURI();
   nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
-  return GetServiceWorkerRegistrationInfo(principal, documentURI);
+  RefPtr<ServiceWorkerRegistrationInfo> reg =
+    GetServiceWorkerRegistrationInfo(principal, documentURI);
+  if (reg) {
+    auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
+    if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
+      reg = nullptr;
+    }
+  }
+  return reg.forget();
 }
 
 already_AddRefed<ServiceWorkerRegistrationInfo>
 ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal,
                                                        nsIURI* aURI)
 {
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aURI);
@@ -2466,16 +2490,21 @@ ServiceWorkerManager::MaybeCheckNavigati
 void
 ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
                                                 nsIDocument* aDoc,
                                                 const nsAString& aDocumentId)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aDoc);
 
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+  auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
+  MOZ_DIAGNOSTIC_ASSERT(storageAllowed == nsContentUtils::StorageAccess::eAllow);
+#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
+
   aRegistration->StartControllingADocument();
   mControlledDocuments.Put(aDoc, aRegistration);
   if (!aDocumentId.IsEmpty()) {
     aDoc->SetId(aDocumentId);
   }
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
 }
 
@@ -3276,31 +3305,39 @@ ServiceWorkerManager::GetClient(nsIPrinc
                                      PromiseFlatString(aClientId).get());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return clientInfo;
   }
 
   nsCOMPtr<nsISupports> ptr;
   ifptr->GetData(getter_AddRefs(ptr));
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
-  if (NS_WARN_IF(!doc)) {
+  if (NS_WARN_IF(!doc || !doc->GetInnerWindow())) {
     return clientInfo;
   }
 
   bool equals = false;
   aPrincipal->Equals(doc->NodePrincipal(), &equals);
   if (!equals) {
     return clientInfo;
   }
 
   if (!IsFromAuthenticatedOrigin(doc)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return clientInfo;
   }
 
+  // Don't let service worker see 3rd party iframes that are denied storage
+  // access.  We don't want these to communicate.
+  auto storageAccess =
+    nsContentUtils::StorageAllowedForWindow(doc->GetInnerWindow());
+  if (storageAccess != nsContentUtils::StorageAccess::eAllow) {
+    return clientInfo;
+  }
+
   clientInfo.reset(new ServiceWorkerClientInfo(doc));
   return clientInfo;
 }
 
 void
 ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
                                     const nsCString& aScope,
                                     uint64_t aServiceWorkerID,
@@ -3335,17 +3372,17 @@ ServiceWorkerManager::GetAllClients(nsIP
   while (NS_SUCCEEDED(enumerator->HasMoreElements(&loop)) && loop) {
     nsCOMPtr<nsISupports> ptr;
     rv = enumerator->GetNext(getter_AddRefs(ptr));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       continue;
     }
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
-    if (!doc || !doc->GetWindow()) {
+    if (!doc || !doc->GetWindow() || !doc->GetInnerWindow()) {
       continue;
     }
 
     bool equals = false;
     Unused << aPrincipal->Equals(doc->NodePrincipal(), &equals);
     if (!equals) {
       continue;
     }
@@ -3353,16 +3390,24 @@ ServiceWorkerManager::GetAllClients(nsIP
     // Treat http windows with devtools opened as secure if the correct devtools
     // setting is enabled.
     if (!doc->GetWindow()->GetServiceWorkersTestingEnabled() &&
         !Preferences::GetBool("dom.serviceWorkers.testing.enabled") &&
         !IsFromAuthenticatedOrigin(doc)) {
       continue;
     }
 
+    // Don't let service worker find 3rd party iframes that are denied storage
+    // access.  We don't want these to communicate.
+    auto storageAccess =
+      nsContentUtils::StorageAllowedForWindow(doc->GetInnerWindow());
+    if (storageAccess != nsContentUtils::StorageAccess::eAllow) {
+      continue;
+    }
+
     // If we are only returning controlled Clients then skip any documents
     // that are for different registrations.  We also skip service workers
     // that don't match the ID of our calling service worker.  We should
     // only return Clients controlled by that precise service worker.
     if (!aIncludeUncontrolled) {
       ServiceWorkerRegistrationInfo* reg = mControlledDocuments.GetWeak(doc);
       if (!reg || reg->mScope != aScope || !reg->GetActive() ||
           reg->GetActive()->ID() != aServiceWorkerID) {
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -175,16 +175,17 @@ support-files =
   strict_mode_warning.js
   skip_waiting_installed_worker.js
   skip_waiting_scope/index.html
   thirdparty/iframe1.html
   thirdparty/iframe2.html
   thirdparty/register.html
   thirdparty/unregister.html
   thirdparty/sw.js
+  thirdparty/worker.js
   register_https.html
   gzip_redirect_worker.js
   sw_clients/navigator.html
   eval_worker.js
   test_eval_allowed.html^headers^
   opaque_intercept_worker.js
   notify_loaded.js
   test_request_context.js
@@ -233,16 +234,18 @@ skip-if = debug # Bug 1262224
 [test_csp_upgrade-insecure_intercept.html]
 [test_empty_serviceworker.html]
 [test_error_reporting.html]
 [test_escapedSlashes.html]
 [test_eval_allowed.html]
 [test_eventsource_intercept.html]
 [test_fetch_event.html]
 skip-if = (debug && e10s) # Bug 1262224
+[test_fetch_event_with_thirdpartypref.html]
+skip-if = (debug && e10s) # Bug 1262224
 [test_fetch_integrity.html]
 [test_file_blob_response.html]
 [test_file_blob_upload.html]
 [test_force_refresh.html]
 [test_gzip_redirect.html]
 [test_hsts_upgrade_intercept.html]
 [test_https_fetch.html]
 [test_https_fetch_cloned_response.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_fetch_event_with_thirdpartypref.html
@@ -0,0 +1,93 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 94048 - test install event.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script src="utils.js"></script>
+<script class="testbody" type="text/javascript">
+
+  // NOTE: This is just test_fetch_event.html but with an alternate cookie
+  //       mode preference set to make sure that setting the preference does
+  //       not break interception as observed in bug 1336364.
+  // TODO: Refactor this test so it doesn't duplicate so much code logic.
+
+  SimpleTest.requestCompleteLog();
+
+  var registration;
+  function simpleRegister() {
+    return navigator.serviceWorker.register("fetch_event_worker.js", { scope: "./fetch" })
+      .then(swr => {
+        registration = swr;
+        return waitForState(swr.installing, 'activated');
+      });
+  }
+
+  function unregister() {
+    return registration.unregister().then(function(success) {
+      ok(success, "Service worker should be unregistered successfully");
+    }, function(e) {
+      dump("SW unregistration error: " + e + "\n");
+    });
+  }
+
+  function testController() {
+    var p = new Promise(function(resolve, reject) {
+      var reloaded = false;
+      window.onmessage = function(e) {
+        if (e.data.status == "ok") {
+          ok(e.data.result, e.data.message);
+        } else if (e.data.status == "done") {
+          if (reloaded) {
+            window.onmessage = null;
+            w.close();
+            resolve();
+          } else {
+            w.location.reload();
+            reloaded = true;
+          }
+        }
+      }
+    });
+
+    var w = window.open("fetch/index.html");
+    return p;
+  }
+
+  function runTest() {
+    simpleRegister()
+      .then(testController)
+      .then(unregister)
+      .then(function() {
+        SimpleTest.finish();
+      }).catch(function(e) {
+        ok(false, "Some test failed with error " + e);
+        SimpleTest.finish();
+      });
+  }
+
+  const COOKIE_BEHAVIOR_REJECTFOREIGN = 1;
+
+  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", true],
+    ["javascript.options.streams", true],
+    ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECTFOREIGN],
+    ["dom.streams.enabled", true],
+  ]}, runTest);
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/workers/test/serviceworkers/test_third_party_iframes.html
+++ b/dom/workers/test/serviceworkers/test_third_party_iframes.html
@@ -75,101 +75,165 @@ function runTest(aExpectedResponses) {
       }
     } else {
       ok(false, "Expected " + expected.status + " got " + status);
     }
     responsesIndex++;
   };
 }
 
-function testShouldIntercept(done) {
-  runTest([{
-    status: "ok"
-  }, {
-    status: "registrationdone",
-    next: function() {
-      iframe.addEventListener("load", testIframeLoaded);
-      iframe.src = origin + basePath + "iframe1.html";
-    }
-  }, {
-    status: "networkresponse",
-    next: loadThirdPartyIframe
-  }, {
-    status: "swresponse",
-    next: function() {
-      iframe.src = thirdPartyOrigin + basePath + "unregister.html";
-    }
-  }, {
-    status: "unregistrationdone",
-    next: function() {
-      window.onmessage = null;
-      ok(true, "Test finished successfully");
-      done();
-    }
-  }]);
+// Verify that we can register and intercept a 3rd party iframe with
+// the given cookie policy.
+function testShouldIntercept(policy, done) {
+  SpecialPowers.pushPrefEnv({"set": [
+      ["network.cookie.cookieBehavior", policy]
+  ]}, function() {
+    runTest([{
+      status: "ok"
+    }, {
+      status: "registrationdone",
+      next: function() {
+        iframe.addEventListener("load", testIframeLoaded);
+        iframe.src = origin + basePath + "iframe1.html";
+      }
+    }, {
+      status: "networkresponse",
+    }, {
+      status: "worker-networkresponse",
+      next: loadThirdPartyIframe
+    }, {
+      status: "swresponse",
+    }, {
+      status: "worker-swresponse",
+      next: function() {
+        iframe.src = thirdPartyOrigin + basePath + "unregister.html";
+      }
+    }, {
+      status: "controlled",
+    }, {
+      status: "unregistrationdone",
+      next: function() {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        done();
+      }
+    }]);
+  });
 }
 
-function testShouldNotIntercept(done) {
-  runTest([{
-    status: "ok"
-  }, {
-    status: "registrationdone",
-    next: function() {
-      iframe.addEventListener("load", testIframeLoaded);
-      iframe.src = origin + basePath + "iframe1.html";
-    }
-  }, {
-    status: "networkresponse",
-    next: loadThirdPartyIframe
-  }, {
-    status: "networkresponse",
-    next: function() {
-      iframe.src = thirdPartyOrigin + basePath + "unregister.html";
-    }
-  }, {
-    status: "unregistrationdone",
-    next: function() {
-      window.onmessage = null;
-      ok(true, "Test finished successfully");
-      done();
-    }
-  }]);
+// Verify that we cannot register a service worker in a 3rd party
+// iframe with the given cookie policy.
+function testShouldNotRegister(policy, done) {
+  SpecialPowers.pushPrefEnv({"set": [
+      ["network.cookie.cookieBehavior", policy]
+  ]}, function() {
+    runTest([{
+      status: "registrationfailed",
+      next: function() {
+        iframe.addEventListener("load", testIframeLoaded);
+        iframe.src = origin + basePath + "iframe1.html";
+      }
+    }, {
+      status: "networkresponse",
+    }, {
+      status: "worker-networkresponse",
+      next: loadThirdPartyIframe
+    }, {
+      status: "networkresponse",
+    }, {
+      status: "worker-networkresponse",
+      next: function() {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        done();
+      }
+    }]);
+  });
+}
+
+// Verify that if a service worker is already registered a 3rd
+// party iframe will still not be intercepted with the given cookie
+// policy.
+function testShouldNotIntercept(policy, done) {
+  SpecialPowers.pushPrefEnv({"set": [
+      ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
+  ]}, function() {
+    runTest([{
+      status: "ok"
+    }, {
+      status: "registrationdone",
+      next: function() {
+        iframe.addEventListener("load", testIframeLoaded);
+        SpecialPowers.pushPrefEnv({"set": [
+            ["network.cookie.cookieBehavior", policy],
+          ]}, function() {
+            iframe.src = origin + basePath + "iframe1.html";
+          });
+      }
+    }, {
+      status: "networkresponse",
+    }, {
+      status: "worker-networkresponse",
+      next: loadThirdPartyIframe
+    }, {
+      status: "networkresponse",
+    }, {
+      status: "worker-networkresponse",
+      next: function() {
+        iframe.src = thirdPartyOrigin + basePath + "unregister.html";
+      }
+    }, {
+      status: "uncontrolled",
+    }, {
+      status: "getregistrationfailed",
+      next: function() {
+        SpecialPowers.pushPrefEnv({"set": [
+            ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT],
+          ]}, function() {
+            iframe.src = thirdPartyOrigin + basePath + "unregister.html";
+          });
+      }
+    }, {
+      status: "controlled",
+    }, {
+      status: "unregistrationdone",
+      next: function() {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        done();
+      }
+    }]);
+  });
 }
 
 const COOKIE_BEHAVIOR_ACCEPT        = 0;
 const COOKIE_BEHAVIOR_REJECTFOREIGN = 1;
 const COOKIE_BEHAVIOR_REJECT        = 2;
 const COOKIE_BEHAVIOR_LIMITFOREIGN  = 3;
 
 let steps = [() => {
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true],
     ["browser.dom.window.dump.enabled", true],
     ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
   ]}, next);
 }, () => {
-  testShouldIntercept(next);
+  testShouldIntercept(COOKIE_BEHAVIOR_ACCEPT, next);
 }, () => {
-  SpecialPowers.pushPrefEnv({"set": [
-    ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECTFOREIGN]
-  ]}, next);
+  testShouldNotRegister(COOKIE_BEHAVIOR_REJECTFOREIGN, next);
 }, () => {
-  testShouldNotIntercept(next);
+  testShouldNotIntercept(COOKIE_BEHAVIOR_REJECTFOREIGN, next);
 }, () => {
-  SpecialPowers.pushPrefEnv({"set": [
-    ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECT]
-  ]}, next);
+  testShouldNotRegister(COOKIE_BEHAVIOR_REJECT, next);
 }, () => {
-  testShouldIntercept(next);
+  testShouldNotIntercept(COOKIE_BEHAVIOR_REJECT, next);
 }, () => {
-  SpecialPowers.pushPrefEnv({"set": [
-    ["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_LIMITFOREIGN]
-  ]}, next);
+  testShouldNotRegister(COOKIE_BEHAVIOR_LIMITFOREIGN, next);
 }, () => {
-  testShouldIntercept(next);
+  testShouldNotIntercept(COOKIE_BEHAVIOR_LIMITFOREIGN, next);
 }];
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/workers/test/serviceworkers/thirdparty/iframe1.html
+++ b/dom/workers/test/serviceworkers/thirdparty/iframe1.html
@@ -12,16 +12,18 @@
       let message = eval(event.data);
 
       dump("got message " + JSON.stringify(message) + "\n");
       if (message.source == "parent") {
         document.getElementById("iframe2").src = message.href;
       }
       else if (message.source == "iframe") {
         parent.postMessage(event.data, "*");
+      } else if (message.source == "worker") {
+        parent.postMessage(event.data, "*");
       }
     }
   </script>
 
 </head>
 
 <body onload="window.addEventListener('message', messageListener, false);">
   <iframe id="iframe2"></iframe>
--- a/dom/workers/test/serviceworkers/thirdparty/iframe2.html
+++ b/dom/workers/test/serviceworkers/thirdparty/iframe2.html
@@ -1,7 +1,14 @@
 <!DOCTYPE html>
 <script>
   window.parent.postMessage({
     source: "iframe",
     status: "networkresponse"
   }, "*");
+  var w = new Worker('worker.js');
+  w.onmessage = function(evt) {
+    window.parent.postMessage({
+      source: 'worker',
+      status: evt.data,
+    }, '*');
+  };
 </script>
--- a/dom/workers/test/serviceworkers/thirdparty/register.html
+++ b/dom/workers/test/serviceworkers/thirdparty/register.html
@@ -18,10 +18,12 @@
     .then(function(registration) {
       if (registration.installing) {
         registration.installing.onstatechange = function(e) {
           done(registration);
         };
       } else {
         done(registration);
       }
+    }).catch(function(e) {
+      window.parent.postMessage({status: "registrationfailed"}, "*");
     });
 </script>
--- a/dom/workers/test/serviceworkers/thirdparty/sw.js
+++ b/dom/workers/test/serviceworkers/thirdparty/sw.js
@@ -1,14 +1,29 @@
 self.addEventListener("fetch", function(event) {
   dump("fetch " + event.request.url + "\n");
-  if (event.request.url.indexOf("iframe2.html") >= 0) {
+  if (event.request.url.includes("iframe2.html")) {
     var body =
       "<script>" +
         "window.parent.postMessage({" +
           "source: 'iframe', status: 'swresponse'" +
         "}, '*');" +
+        "var w = new Worker('worker.js');" +
+        "w.onmessage = function(evt) {" +
+          "window.parent.postMessage({" +
+            "source: 'worker'," +
+            "status: evt.data," +
+          "}, '*');" +
+      "};" +
       "</script>";
     event.respondWith(new Response(body, {
       headers: {'Content-Type': 'text/html'}
     }));
+    return;
+  }
+  if (event.request.url.includes("worker.js")) {
+    var body = "self.postMessage('worker-swresponse');";
+    event.respondWith(new Response(body, {
+      headers: {'Content-Type': 'application/javascript'}
+    }));
+    return;
   }
 });
--- a/dom/workers/test/serviceworkers/thirdparty/unregister.html
+++ b/dom/workers/test/serviceworkers/thirdparty/unregister.html
@@ -1,11 +1,19 @@
 <!DOCTYPE html>
 <script>
+  if (navigator.serviceWorker.controller) {
+    window.parent.postMessage({status: "controlled"}, "*");
+  } else {
+    window.parent.postMessage({status: "uncontrolled"}, "*");
+  }
+
   navigator.serviceWorker.getRegistration(".").then(function(registration) {
     if(!registration) {
       return;
     }
     registration.unregister().then(() => {
       window.parent.postMessage({status: "unregistrationdone"}, "*");
     });
+  }).catch(function(e) {
+    window.parent.postMessage({status: "getregistrationfailed"}, "*");
   });
 </script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/thirdparty/worker.js
@@ -0,0 +1,1 @@
+self.postMessage('worker-networkresponse');
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -2738,23 +2738,24 @@ EditorBase::SetTextImpl(Selection& aSele
   // We don't support undo here, so we don't really need all of the transaction
   // machinery, therefore we can run our transaction directly, breaking all of
   // the rules!
   nsresult rv = aCharData.SetData(aString);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  // Only set selection to insertion point if editor gives permission
-  if (GetShouldTxnSetSelection()) {
+  {
+    // Create a nested scope to not overwrite rv from the outer scope.
     RefPtr<Selection> selection = GetSelection();
-    DebugOnly<nsresult> rv = selection->Collapse(&aCharData, length);
+    DebugOnly<nsresult> rv = selection->Collapse(&aCharData, aString.Length());
     NS_ASSERTION(NS_SUCCEEDED(rv),
                  "Selection could not be collapsed after insert");
   }
+
   mRangeUpdater.SelAdjDeleteText(&aCharData, 0, length);
   mRangeUpdater.SelAdjInsertText(aCharData, 0, aString);
 
   // Let listeners know what happened
   {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
       if (length) {
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -868,19 +868,16 @@ TextEditRules::WillSetText(Selection& aS
     return NS_OK;
   }
 
   nsINode* curNode = rootElement->GetFirstChild();
   if (NS_WARN_IF(!EditorBase::IsTextNode(curNode))) {
     return NS_OK;
   }
 
-  // don't change my selection in subtransactions
-  AutoTransactionsConserveSelection dontChangeMySelection(textEditor);
-
   // Even if empty text, we don't remove text node and set empty text
   // for performance
   nsresult rv = textEditor->SetTextImpl(aSelection, tString,
                                         *curNode->GetAsText());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -248,16 +248,17 @@ skip-if = toolkit == 'android' # bug 131
 [test_bug1332876.html]
 [test_bug1352799.html]
 [test_bug1355792.html]
 [test_bug1358025.html]
 [test_bug1361008.html]
 [test_bug1368544.html]
 [test_bug1385905.html]
 [test_bug1394758.html]
+[test_bug1399722.html]
 
 [test_CF_HTML_clipboard.html]
 subsuite = clipboard
 [test_composition_event_created_in_chrome.html]
 [test_contenteditable_focus.html]
 [test_documentCharacterSet.html]
 [test_dom_input_event_on_htmleditor.html]
 skip-if = toolkit == 'android' # bug 1054087
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1399722.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1399722
+-->
+<html>
+<head>
+  <title>Test for Bug 1399722</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1399722">Mozilla Bug 1399722</a>
+<p id="display"></p>
+<div id="content" style="display: none;">
+
+</div>
+
+<input spellcheck="true" onkeypress="if (event.key=='Enter')this.value='';">
+<pre id="test">
+
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  let elm = document.querySelector("input");
+
+  elm.focus();
+  synthesizeKey("A", {});
+  synthesizeKey("B", {});
+  synthesizeKey("KEY_Enter", {});
+  synthesizeKey("C", {});
+  synthesizeKey("D", {});
+  is(elm.value, "CD", "Can type into the textbox successfully after the onkeypress handler deleting the value");
+
+  SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -233,18 +233,17 @@ DrawTargetD2D1::DrawSurface(SourceSurfac
                                                      D2D1_EXTEND_MODE_CLAMP,
                                                      D2D1_EXTEND_MODE_CLAMP,
                                                      D2DInterpolationMode(aSurfOptions.mSamplingFilter)),
                           D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)),
                           getter_AddRefs(brush));
     mDC->FillRectangle(D2DRect(aDest), brush);
   }
 
-  Rect destBounds = mTransform.TransformBounds(aDest);
-  FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()), &destBounds);
+  FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
 }
 
 void
 DrawTargetD2D1::DrawFilter(FilterNode *aNode,
                            const Rect &aSourceRect,
                            const Point &aDestPoint,
                            const DrawOptions &aOptions)
 {
@@ -1340,17 +1339,17 @@ DrawTargetD2D1::PrepareForDrawing(Compos
   if (ShouldClipTemporarySurfaceDrawing(aOp, aPattern, clipIsComplex)) {
     PushClipsToDC(mDC);
   }
 
   FlushTransformToDC();
 }
 
 void
-DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern, const Rect* aAffectedRect /* = nullptr */)
+DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
 {
   bool patternSupported = IsPatternSupportedByD2D(aPattern);
 
   if (D2DSupportsPrimitiveBlendMode(aOp) && patternSupported) {
     if (aOp != CompositionOp::OP_OVER)
       mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
     return;
   }
@@ -1403,35 +1402,25 @@ DrawTargetD2D1::FinalizeDrawing(Composit
     RefPtr<ID2D1Effect> blendEffect;
     HRESULT hr = mDC->CreateEffect(CLSID_D2D1Blend, getter_AddRefs(blendEffect));
 
     if (FAILED(hr) || !blendEffect) {
       gfxWarning() << "Failed to create blend effect!";
       return;
     }
 
-    Point outOffset;
-    // We don't need to preserve the current content of this layer if the output
+    // We don't need to preserve the current content of this layer as the output
     // of the blend effect should completely replace it.
-    bool shouldPreserveContent = !!aAffectedRect && !aAffectedRect->Contains(Rect(0, 0, mSize.width, mSize.height));
-    RefPtr<ID2D1Image> tmpImage = GetImageForLayerContent(shouldPreserveContent, aAffectedRect, &outOffset);
+    RefPtr<ID2D1Image> tmpImage = GetImageForLayerContent(false);
     if (!tmpImage) {
       return;
     }
 
     blendEffect->SetInput(0, tmpImage);
     blendEffect->SetInput(1, source);
-
-    if (outOffset != Point()) {
-      RefPtr<ID2D1Effect> transformEffect;
-      mDC->CreateEffect(CLSID_D2D12DAffineTransform, getter_AddRefs(transformEffect));
-      transformEffect->SetInput(0, tmpImage);
-      transformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, D2D1::Matrix3x2F::Translation(outOffset.x, outOffset.y));
-      blendEffect->SetInputEffect(0, transformEffect);
-    }
     blendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
 
     mDC->DrawImage(blendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
 
     // This may seem a little counter intuitive. If this is false, we go through the regular
     // codepaths and set it to true. When this was true, GetImageForLayerContent will return
     // a bitmap for the current command list and we will no longer have a complex blend
     // with a list for tmpImage. Therefore we can set it to false again.
@@ -1513,24 +1502,20 @@ DrawTargetD2D1::GetDeviceSpaceClipRect(D
     if (!iter->mIsPixelAligned) {
       aIsPixelAligned = false;
     }
   }
   return true;
 }
 
 already_AddRefed<ID2D1Image>
-DrawTargetD2D1::GetImageForLayerContent(bool aShouldPreserveContent, const Rect* aBounds /* = nullptr */, Point* aOutOffset /* = nullptr */) 
+DrawTargetD2D1::GetImageForLayerContent(bool aShouldPreserveContent)
 {
   PopAllClips();
 
-  if (aOutOffset) {
-    *aOutOffset = Point();
-  }
-
   if (!CurrentLayer().mCurrentList) {
     RefPtr<ID2D1Bitmap> tmpBitmap;
     HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), getter_AddRefs(tmpBitmap));
     if (FAILED(hr)) {
       gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 6CreateBitmap failure " << mSize << " Code: " << hexa(hr) << " format " << (int)mFormat;
       // If it's a recreate target error, return and handle it elsewhere.
       if (hr == D2DERR_RECREATE_TARGET) {
         mDC->Flush();
@@ -1550,30 +1535,20 @@ DrawTargetD2D1::GetImageForLayerContent(
     list->Close();
 
     RefPtr<ID2D1Bitmap1> tmpBitmap;
     if (mDidComplexBlendWithListInList) {
       D2D1_BITMAP_PROPERTIES1 props =
         D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET,
                                 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
                                                   D2D1_ALPHA_MODE_PREMULTIPLIED));
-      D2D1_SIZE_U size = mBitmap->GetPixelSize();
-      D2D1_POINT_2F offset = D2D1::Point2F();
-      if (aBounds) {
-        size.width = aBounds->width;
-        size.height = aBounds->height;
-        offset.x = -aBounds->x;
-        offset.y = -aBounds->y;
-        aOutOffset->x = aBounds->x;
-        aOutOffset->y = aBounds->y;
-      }
-      mDC->CreateBitmap(size, nullptr, 0, &props, getter_AddRefs(tmpBitmap));
+      mDC->CreateBitmap(mBitmap->GetPixelSize(), nullptr, 0, &props, getter_AddRefs(tmpBitmap));
       mDC->SetTransform(D2D1::IdentityMatrix());
       mDC->SetTarget(tmpBitmap);
-      mDC->DrawImage(list, offset, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
+      mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
       mDC->SetTarget(CurrentTarget());
     }
 
     DCCommandSink sink(mDC);
 
     if (aShouldPreserveContent) {
       list->Stream(&sink);
       PushAllClips();
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -175,33 +175,27 @@ private:
 
   typedef std::unordered_set<DrawTargetD2D1*> TargetSet;
 
   // This function will mark the surface as changing, and make sure any
   // copy-on-write snapshots are notified.
   void MarkChanged();
   bool ShouldClipTemporarySurfaceDrawing(CompositionOp aOp, const Pattern& aPattern, bool aClipIsComplex);
   void PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern);
-  // aAffectedRect may be used to supply the bounds of the drawing operations in order to prevent
-  // excessive surface area being operated on
-  void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern, const Rect* aAffectedRect = nullptr);
+  void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern);
   void FlushTransformToDC() {
     if (mTransformDirty) {
       mDC->SetTransform(D2DMatrix(mTransform));
       mTransformDirty = false;
     }
   }
   void AddDependencyOnSource(SourceSurfaceD2D1* aSource);
 
   // Must be called with all clips popped and an identity matrix set.
-  // aBounds can be specified to allow the function to return only part of the layer contents
-  // aOutOffset will return the offset that should be applied to move the ID2D1Image onto the
-  // correct portion of the destination layer. If !aBounds this will always be 0,0 and can be
-  // ignored.
-  already_AddRefed<ID2D1Image> GetImageForLayerContent(bool aShouldPreserveContent = true, const Rect* aBounds = nullptr, Point* aOutOffset = nullptr);
+  already_AddRefed<ID2D1Image> GetImageForLayerContent(bool aShouldPreserveContent = true);
 
   ID2D1Image* CurrentTarget()
   {
     if (CurrentLayer().mCurrentList) {
       return CurrentLayer().mCurrentList;
     }
     return mBitmap;
   }
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -59,16 +59,17 @@ ImageBridgeParent::Setup()
   }
 }
 
 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
                                      ProcessId aChildProcessId)
   : mMessageLoop(aLoop)
   , mSetChildThreadPriority(false)
   , mClosed(false)
+  , mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // creates the map only if it has not been created already, so it is safe
   // with several bridges
   {
     MonitorAutoLock lock(*sImageBridgesLock);
     sImageBridges[aChildProcessId] = this;
@@ -359,23 +360,16 @@ RefPtr<ImageBridgeParent>
 ImageBridgeParent::GetInstance(ProcessId aId)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   MonitorAutoLock lock(*sImageBridgesLock);
   NS_ASSERTION(sImageBridges.count(aId) == 1, "ImageBridgeParent for the process");
   return sImageBridges[aId];
 }
 
-void
-ImageBridgeParent::OnChannelConnected(int32_t aPid)
-{
-  mCompositorThreadHolder = GetCompositorThreadHolder();
-}
-
-
 bool
 ImageBridgeParent::AllocShmem(size_t aSize,
                       ipc::SharedMemory::SharedMemoryType aType,
                       ipc::Shmem* aShmem)
 {
   if (mClosed) {
     return false;
   }
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -117,18 +117,16 @@ public:
 
   static bool NotifyImageComposites(nsTArray<ImageCompositeNotificationInfo>& aNotifications);
 
   virtual bool UsesImageBridge() const override { return true; }
 
   virtual bool IPCOpen() const override { return !mClosed; }
 
 protected:
-  void OnChannelConnected(int32_t pid) override;
-
   void Bind(Endpoint<PImageBridgeParent>&& aEndpoint);
 
 private:
   void DeferredDestroy();
   MessageLoop* mMessageLoop;
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   RefPtr<ImageBridgeParent> mSelfRef;
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -46,24 +46,24 @@ parent:
   // next Update call.
   async InitReadLocks(ReadLockInit[] locks);
 
   sync Create(IntSize aSize);
   async DeleteCompositorAnimations(uint64_t[] aIds);
   async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                        LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                        WebRenderScrollData aScrollData,
-                       OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData,
+                       OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                        IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   sync SetDisplayListSync(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                           LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                           WebRenderScrollData aScrollData,
-                          OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData,
+                          OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                           IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
-  async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData);
+  async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems);
   async ParentCommands(WebRenderParentCommand[] commands);
   sync GetSnapshot(PTexture texture);
   async AddPipelineIdForCompositable(PipelineId aImageId, CompositableHandle aHandle, bool aAsync);
   async RemovePipelineIdForCompositable(PipelineId aPipelineId);
   async AddExternalImageIdForCompositable(ExternalImageId aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(ExternalImageId aImageId);
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
   async ClearCachedResources();
--- a/gfx/layers/ipc/WebRenderMessages.ipdlh
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -57,23 +57,23 @@ struct OpUpdateAsyncImagePipeline {
   LayerRect scBounds;
   Matrix4x4 scTransform;
   MaybeIntSize scaleToSize;
   ImageRendering filter;
   MixBlendMode mixBlendMode;
 };
 
 union WebRenderParentCommand {
-  OpAddExternalImage;
   OpUpdateAsyncImagePipeline;
   CompositableOperation;
   OpAddCompositorAnimations;
 };
 
 struct OffsetRange {
+  uint32_t source;
   uint32_t start;
   uint32_t length;
 };
 
 struct OpAddImage {
   ImageDescriptor descriptor;
   OffsetRange bytes;
   uint16_t tiling;
@@ -130,12 +130,13 @@ union OpUpdateResource {
   OpAddBlobImage;
   OpUpdateImage;
   OpUpdateBlobImage;
   OpDeleteImage;
   OpAddRawFont;
   OpDeleteFont;
   OpAddFontInstance;
   OpDeleteFontInstance;
+  OpAddExternalImage;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -25,127 +25,189 @@ ShmSegmentsWriter::~ShmSegmentsWriter()
 }
 
 layers::OffsetRange
 ShmSegmentsWriter::Write(Range<uint8_t> aBytes)
 {
   const size_t start = mCursor;
   const size_t length = aBytes.length();
 
+  if (length >= mChunkSize * 4) {
+    auto range = AllocLargeChunk(length);
+    uint8_t* dstPtr = mLargeAllocs.LastElement().get<uint8_t>();
+    memcpy(dstPtr, aBytes.begin().get(), length);
+    return range;
+  }
+
   int remainingBytesToCopy = length;
 
   size_t srcCursor = 0;
   size_t dstCursor = mCursor;
 
   while (remainingBytesToCopy > 0) {
-    if (dstCursor >= mData.Length() * mChunkSize) {
+    if (dstCursor >= mSmallAllocs.Length() * mChunkSize) {
       AllocChunk();
       continue;
     }
 
-    const size_t dstMaxOffset = mChunkSize * mData.Length();
-    const size_t dstBaseOffset = mChunkSize * (mData.Length() - 1);
+    const size_t dstMaxOffset = mChunkSize * mSmallAllocs.Length();
+    const size_t dstBaseOffset = mChunkSize * (mSmallAllocs.Length() - 1);
 
     MOZ_ASSERT(dstCursor >= dstBaseOffset);
     MOZ_ASSERT(dstCursor <= dstMaxOffset);
 
     size_t availableRange = dstMaxOffset - dstCursor;
     size_t copyRange = std::min<int>(availableRange, remainingBytesToCopy);
 
     uint8_t* srcPtr = &aBytes[srcCursor];
-    uint8_t* dstPtr = mData.LastElement().get<uint8_t>() + (dstCursor - dstBaseOffset);
+    uint8_t* dstPtr = mSmallAllocs.LastElement().get<uint8_t>() + (dstCursor - dstBaseOffset);
 
     memcpy(dstPtr, srcPtr, copyRange);
 
     srcCursor += copyRange;
     dstCursor += copyRange;
     remainingBytesToCopy -= copyRange;
 
     // sanity check
     MOZ_ASSERT(remainingBytesToCopy >= 0);
   }
 
   mCursor += length;
 
-  return layers::OffsetRange(start, length);
+  return layers::OffsetRange(0, start, length);
 }
 
 void
 ShmSegmentsWriter::AllocChunk()
 {
   ipc::Shmem shm;
   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
   if (!mShmAllocator->AllocShmem(mChunkSize, shmType, &shm)) {
-    MOZ_CRASH("Shared memory allocation failed");
+    gfxCriticalError() << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
+    MOZ_CRASH();
   }
-  mData.AppendElement(shm);
+  mSmallAllocs.AppendElement(shm);
+}
+
+layers::OffsetRange
+ShmSegmentsWriter::AllocLargeChunk(size_t aSize)
+{
+  ipc::Shmem shm;
+  auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
+  if (!mShmAllocator->AllocShmem(aSize, shmType, &shm)) {
+    gfxCriticalError() << "ShmSegmentsWriter failed to allocate large chunk of size " << aSize;
+    MOZ_CRASH();
+  }
+  mLargeAllocs.AppendElement(shm);
+
+  return layers::OffsetRange(mLargeAllocs.Length(), 0, aSize);
 }
 
 void
-ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aInto)
+ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs)
 {
-  aInto.Clear();
-  mData.SwapElements(aInto);
+  aSmallAllocs.Clear();
+  aLargeAllocs.Clear();
+  mSmallAllocs.SwapElements(aSmallAllocs);
+  mLargeAllocs.SwapElements(aLargeAllocs);
 }
 
 void
 ShmSegmentsWriter::Clear()
 {
   if (mShmAllocator) {
-    for (auto& shm : mData) {
+    for (auto& shm : mSmallAllocs) {
+      mShmAllocator->DeallocShmem(shm);
+    }
+    for (auto& shm : mLargeAllocs) {
       mShmAllocator->DeallocShmem(shm);
     }
   }
-  mData.Clear();
+  mSmallAllocs.Clear();
+  mLargeAllocs.Clear();
   mCursor = 0;
 }
 
-ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems)
-: mData(aShmems)
+ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
+                                     const nsTArray<ipc::Shmem>& aLargeShmems)
+: mSmallAllocs(aSmallShmems)
+, mLargeAllocs(aLargeShmems)
 , mChunkSize(0)
 {
-  if (mData.IsEmpty()) {
+  if (mSmallAllocs.IsEmpty()) {
     return;
   }
 
-  mChunkSize = mData[0].Size<uint8_t>();
+  mChunkSize = mSmallAllocs[0].Size<uint8_t>();
 
   // Check that all shmems are readable and have the same size. If anything
   // isn't right, set mChunkSize to zero which signifies that the reader is
   // in an invalid state and Read calls will return false;
-  for (const auto& shm : mData) {
+  for (const auto& shm : mSmallAllocs) {
     if (!shm.IsReadable()
         || shm.Size<uint8_t>() != mChunkSize
         || shm.get<uint8_t>() == nullptr) {
       mChunkSize = 0;
       return;
     }
   }
+
+  for (const auto& shm : mLargeAllocs) {
+    if (!shm.IsReadable()
+        || shm.get<uint8_t>() == nullptr) {
+      mChunkSize = 0;
+      return;
+    }
+  }
 }
 
 bool
-ShmSegmentsReader::Read(layers::OffsetRange aRange, wr::Vec_u8& aInto)
+ShmSegmentsReader::ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
 {
+  // source = zero is for small allocs.
+  MOZ_RELEASE_ASSERT(aRange.source() != 0);
+  if (aRange.source() > mLargeAllocs.Length()) {
+    return false;
+  }
+  size_t id = aRange.source() - 1;
+  const ipc::Shmem& shm = mLargeAllocs[id];
+  if (shm.Size<uint8_t>() < aRange.length()) {
+    return false;
+  }
+
+  uint8_t* srcPtr = shm.get<uint8_t>();
+  aInto.PushBytes(Range<uint8_t>(srcPtr, aRange.length()));
+
+  return true;
+}
+
+bool
+ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
+{
+  if (aRange.source() != 0) {
+    return ReadLarge(aRange, aInto);
+  }
+
   if (mChunkSize == 0) {
     return false;
   }
 
-  if (aRange.start() + aRange.length() > mChunkSize * mData.Length()) {
+  if (aRange.start() + aRange.length() > mChunkSize * mSmallAllocs.Length()) {
     return false;
   }
 
   size_t initialLength = aInto.Length();
 
   size_t srcCursor = aRange.start();
   int remainingBytesToCopy = aRange.length();
   while (remainingBytesToCopy > 0) {
     const size_t shm_idx = srcCursor / mChunkSize;
     const size_t ptrOffset = srcCursor % mChunkSize;
     const size_t copyRange = std::min<int>(remainingBytesToCopy, mChunkSize - ptrOffset);
-    uint8_t* srcPtr = mData[shm_idx].get<uint8_t>() + ptrOffset;
+    uint8_t* srcPtr = mSmallAllocs[shm_idx].get<uint8_t>() + ptrOffset;
 
     aInto.PushBytes(Range<uint8_t>(srcPtr, copyRange));
 
     srcCursor += copyRange;
     remainingBytesToCopy -= copyRange;
   }
 
   return aInto.Length() - initialLength == aRange.length();
@@ -168,16 +230,22 @@ void
 IpcResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
                                      Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
   mUpdates.AppendElement(layers::OpAddBlobImage(aDescriptor, bytes, 0, key));
 }
 
 void
+IpcResourceUpdateQueue::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey)
+{
+  mUpdates.AppendElement(layers::OpAddExternalImage(aExtId, aKey));
+}
+
+void
 IpcResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
                                           const ImageDescriptor& aDescriptor,
                                           Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
   mUpdates.AppendElement(layers::OpUpdateImage(aDescriptor, bytes, aKey));
 }
 
@@ -227,21 +295,22 @@ IpcResourceUpdateQueue::AddFontInstance(
 void
 IpcResourceUpdateQueue::DeleteFontInstance(wr::FontInstanceKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteFontInstance(aKey));
 }
 
 void
 IpcResourceUpdateQueue::Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
-                              nsTArray<ipc::Shmem>& aResourceData)
+                              nsTArray<ipc::Shmem>& aSmallAllocs,
+                              nsTArray<ipc::Shmem>& aLargeAllocs)
 {
   aUpdates.Clear();
   mUpdates.SwapElements(aUpdates);
-  mWriter.Flush(aResourceData);
+  mWriter.Flush(aSmallAllocs, aLargeAllocs);
 }
 
 void
 IpcResourceUpdateQueue::Clear()
 {
   mWriter.Clear();
   mUpdates.Clear();
 }
--- a/gfx/layers/wr/IpcResourceUpdateQueue.h
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.h
@@ -9,65 +9,73 @@
 #include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace ipc {
 class IShmemAllocator;
 }
 namespace wr {
 
+/// ShmSegmentsWriter pushes bytes in a sequence of fixed size shmems for small
+/// allocations and creates dedicated shmems for large allocations.
 class ShmSegmentsWriter {
 public:
   ShmSegmentsWriter(ipc::IShmemAllocator* aAllocator, size_t aChunkSize);
   ~ShmSegmentsWriter();
 
   layers::OffsetRange Write(Range<uint8_t> aBytes);
 
-  void Flush(nsTArray<ipc::Shmem>& aData);
+  void Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
 
   void Clear();
 
 protected:
   void AllocChunk();
+  layers::OffsetRange AllocLargeChunk(size_t aSize);
 
-  nsTArray<ipc::Shmem> mData;
+  nsTArray<ipc::Shmem> mSmallAllocs;
+  nsTArray<ipc::Shmem> mLargeAllocs;
   ipc::IShmemAllocator* mShmAllocator;
   size_t mCursor;
   size_t mChunkSize;
 };
 
 class ShmSegmentsReader {
 public:
-  explicit ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems);
+  ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
+                    const nsTArray<ipc::Shmem>& aLargeShmems);
 
-  bool Read(layers::OffsetRange aRange, wr::Vec_u8& aInto);
+  bool Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
 
 protected:
-  void AllocChunk();
+  bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
 
-  const nsTArray<ipc::Shmem>& mData;
+  const nsTArray<ipc::Shmem>& mSmallAllocs;
+  const nsTArray<ipc::Shmem>& mLargeAllocs;
   size_t mChunkSize;
 };
 
 class IpcResourceUpdateQueue {
 public:
-  // TODO: 8192 is completely arbitrary, needs some adjustments.
+  // TODO: 32768 is completely arbitrary, needs some adjustments.
   // Because we are using shmems, the size should be a multiple of the page size, and keep in mind
   // that each shmem has guard pages, one of which contains meta-data so at least an extra page
   // is mapped under the hood (so having a lot of smaller shmems = overhead).
-  explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 8192);
+  explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 32768);
 
   void AddImage(wr::ImageKey aKey,
                 const ImageDescriptor& aDescriptor,
                 Range<uint8_t> aBytes);
 
   void AddBlobImage(wr::ImageKey aKey,
                     const ImageDescriptor& aDescriptor,
                     Range<uint8_t> aBytes);
 
+  void AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
+
   void UpdateImageBuffer(wr::ImageKey aKey,
                          const ImageDescriptor& aDescriptor,
                          Range<uint8_t> aBytes);
 
   void UpdateBlobImage(wr::ImageKey aKey,
                        const ImageDescriptor& aDescriptor,
                        Range<uint8_t> aBytes);
 
@@ -89,17 +97,18 @@ public:
                        const wr::FontInstanceOptions* aOptions,
                        const wr::FontInstancePlatformOptions* aPlatformOptions);
 
   void DeleteFontInstance(wr::FontInstanceKey aKey);
 
   void Clear();
 
   void Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
-             nsTArray<ipc::Shmem>& aResources);
+             nsTArray<ipc::Shmem>& aSmallAllocs,
+             nsTArray<ipc::Shmem>& aLargeAllocs);
 
 protected:
   ShmSegmentsWriter mWriter;
   nsTArray<layers::OpUpdateResource> mUpdates;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/wr/ScrollingLayersHelper.cpp
+++ b/gfx/layers/wr/ScrollingLayersHelper.cpp
@@ -12,59 +12,60 @@
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "UnitTransforms.h"
 
 namespace mozilla {
 namespace layers {
 
 ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
                                              wr::DisplayListBuilder& aBuilder,
+                                             wr::IpcResourceUpdateQueue& aResources,
                                              const StackingContextHelper& aStackingContext)
   : mLayer(aLayer)
   , mBuilder(&aBuilder)
   , mPushedLayerLocalClip(false)
   , mPushedClipAndScroll(false)
 {
   if (!mLayer->WrManager()->AsyncPanZoomEnabled()) {
     // If APZ is disabled then we don't need to push the scrolling clips. We
     // still want to push the layer's local clip though.
-    PushLayerLocalClip(aStackingContext);
+    PushLayerLocalClip(aStackingContext, aResources);
     return;
   }
 
   Layer* layer = mLayer->GetLayer();
   for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; i--) {
     const ScrollMetadata& metadata = layer->GetScrollMetadata(i - 1);
     // The scroll clip on a given metadata is affected by all async transforms
     // from metadatas "above" it, but not the async transform on the metadata
     // itself. Therefore we need to push this clip before we push the
     // corresponding scroll layer, so that when we set an async scroll position
     // on the scroll layer, the clip isn't affected by it.
     if (const Maybe<LayerClip>& clip = metadata.GetScrollClip()) {
-      PushLayerClip(clip.ref(), aStackingContext);
+      PushLayerClip(clip.ref(), aStackingContext, aResources);
     }
 
     const FrameMetrics& fm = layer->GetFrameMetrics(i - 1);
     if (layer->GetIsFixedPosition() &&
         layer->GetFixedPositionScrollContainerId() == fm.GetScrollId()) {
       // If the layer contents are fixed for this metadata onwards, we need
       // to insert the layer's local clip at this point in the clip tree,
       // as a child of whatever's on the stack.
-      PushLayerLocalClip(aStackingContext);
+      PushLayerLocalClip(aStackingContext, aResources);
     }
 
     DefineAndPushScrollLayer(fm, aStackingContext);
   }
 
   // The scrolled clip on the layer is "inside" all of the scrollable metadatas
   // on that layer. That is, the clip scrolls along with the content in
   // child layers. So we need to apply this after pushing all the scroll layers,
   // which we do above.
   if (const Maybe<LayerClip>& scrolledClip = layer->GetScrolledClip()) {
-    PushLayerClip(scrolledClip.ref(), aStackingContext);
+    PushLayerClip(scrolledClip.ref(), aStackingContext, aResources);
   }
 
   // If the layer is marked as fixed-position, it is fixed relative to something
   // (the scroll layer referred to by GetFixedPositionScrollContainerId, hereafter
   // referred to as the "scroll container"). What this really means is that we
   // don't want this content to scroll with any scroll layer on the stack up to
   // and including the scroll container, but we do want it to scroll with any
   // ancestor scroll layers.
@@ -77,17 +78,17 @@ ScrollingLayersHelper::ScrollingLayersHe
   // to the ancestor of the scroll container.
   if (layer->GetIsFixedPosition()) {
     FrameMetrics::ViewID fixedFor = layer->GetFixedPositionScrollContainerId();
     Maybe<FrameMetrics::ViewID> scrollsWith = mBuilder->ParentScrollIdFor(fixedFor);
     Maybe<wr::WrClipId> clipId = mBuilder->TopmostClipId();
     // Default to 0 if there is no ancestor, because 0 refers to the root scrollframe.
     mBuilder->PushClipAndScrollInfo(scrollsWith.valueOr(0), clipId.ptrOr(nullptr));
   } else {
-    PushLayerLocalClip(aStackingContext);
+    PushLayerLocalClip(aStackingContext, aResources);
   }
 }
 
 ScrollingLayersHelper::ScrollingLayersHelper(nsDisplayItem* aItem,
                                              wr::DisplayListBuilder& aBuilder,
                                              const StackingContextHelper& aStackingContext,
                                              WebRenderLayerManager::ClipIdMap& aCache,
                                              bool aApzEnabled)
@@ -268,49 +269,51 @@ ScrollingLayersHelper::DefineAndPushScro
   mBuilder->DefineScrollLayer(aMetrics.GetScrollId(),
       aStackingContext.ToRelativeLayoutRect(contentRect),
       aStackingContext.ToRelativeLayoutRect(clipBounds));
   mBuilder->PushScrollLayer(aMetrics.GetScrollId());
   return true;
 }
 
 void
-ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStackingContext)
+ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStackingContext,
+                                          wr::IpcResourceUpdateQueue& aResources)
 {
   Layer* layer = mLayer->GetLayer();
   Maybe<ParentLayerRect> clip;
   if (const Maybe<ParentLayerIntRect>& rect = layer->GetClipRect()) {
     clip = Some(IntRectToRect(rect.ref()));
   } else if (layer->GetMaskLayer()) {
     // this layer has a mask, but no clip rect. so let's use the transformed
     // visible bounds as the clip rect.
     clip = Some(layer->GetLocalTransformTyped().TransformBounds(mLayer->Bounds()));
   }
   if (clip) {
-    Maybe<wr::WrImageMask> mask = mLayer->BuildWrMaskLayer(aStackingContext);
+    Maybe<wr::WrImageMask> mask = mLayer->BuildWrMaskLayer(aStackingContext, aResources);
     LayerRect clipRect = ViewAs<LayerPixel>(clip.ref(),
         PixelCastJustification::MovingDownToChildren);
     mBuilder->PushClip(mBuilder->DefineClip(
         aStackingContext.ToRelativeLayoutRect(clipRect), nullptr, mask.ptrOr(nullptr)));
     mPushedLayerLocalClip = true;
   }
 }
 
 void
 ScrollingLayersHelper::PushLayerClip(const LayerClip& aClip,
-                                     const StackingContextHelper& aSc)
+                                     const StackingContextHelper& aSc,
+                                     wr::IpcResourceUpdateQueue& aResources)
 {
   LayerRect clipRect = IntRectToRect(ViewAs<LayerPixel>(aClip.GetClipRect(),
         PixelCastJustification::MovingDownToChildren));
   Maybe<wr::WrImageMask> mask;
   if (Maybe<size_t> maskLayerIndex = aClip.GetMaskLayerIndex()) {
     Layer* maskLayer = mLayer->GetLayer()->GetAncestorMaskLayerAt(maskLayerIndex.value());
     WebRenderLayer* maskWrLayer = WebRenderLayer::ToWebRenderLayer(maskLayer);
     // TODO: check this transform is correct in all cases
-    mask = maskWrLayer->RenderMaskLayer(aSc, maskLayer->GetTransform());
+    mask = maskWrLayer->RenderMaskLayer(aSc, maskLayer->GetTransform(), aResources);
   }
   mBuilder->PushClip(mBuilder->DefineClip(
       aSc.ToRelativeLayoutRect(clipRect), nullptr, mask.ptrOr(nullptr)));
 }
 
 ScrollingLayersHelper::~ScrollingLayersHelper()
 {
   if (!mLayer) {
--- a/gfx/layers/wr/ScrollingLayersHelper.h
+++ b/gfx/layers/wr/ScrollingLayersHelper.h
@@ -24,16 +24,17 @@ struct LayerClip;
 class StackingContextHelper;
 class WebRenderLayer;
 
 class MOZ_RAII ScrollingLayersHelper
 {
 public:
   ScrollingLayersHelper(WebRenderLayer* aLayer,
                         wr::DisplayListBuilder& aBuilder,
+                        wr::IpcResourceUpdateQueue& aResources,
                         const StackingContextHelper& aSc);
   ScrollingLayersHelper(nsDisplayItem* aItem,
                         wr::DisplayListBuilder& aBuilder,
                         const StackingContextHelper& aStackingContext,
                         WebRenderLayerManager::ClipIdMap& aCache,
                         bool aApzEnabled);
   ~ScrollingLayersHelper();
 
@@ -47,19 +48,21 @@ private:
                                  WebRenderLayerManager::ClipIdMap& aCache);
   void DefineAndPushChain(const DisplayItemClipChain* aChain,
                           wr::DisplayListBuilder& aBuilder,
                           const StackingContextHelper& aStackingContext,
                           int32_t aAppUnitsPerDevPixel,
                           WebRenderLayerManager::ClipIdMap& aCache);
   bool DefineAndPushScrollLayer(const FrameMetrics& aMetrics,
                                 const StackingContextHelper& aStackingContext);
-  void PushLayerLocalClip(const StackingContextHelper& aStackingContext);
+  void PushLayerLocalClip(const StackingContextHelper& aStackingContext,
+                          wr::IpcResourceUpdateQueue& aResources);
   void PushLayerClip(const LayerClip& aClip,
-                     const StackingContextHelper& aSc);
+                     const StackingContextHelper& aSc,
+                     wr::IpcResourceUpdateQueue& aResources);
 
   WebRenderLayer* mLayer;
   wr::DisplayListBuilder* mBuilder;
   bool mPushedLayerLocalClip;
   bool mPushedClipAndScroll;
   std::vector<wr::ScrollOrClipId> mPushedClips;
 };
 
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -102,20 +102,21 @@ void
 WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources)
 {
   if (!IPCOpen()) {
     aResources.Clear();
     return;
   }
 
   nsTArray<OpUpdateResource> resourceUpdates;
-  nsTArray<ipc::Shmem> resourceData;
-  aResources.Flush(resourceUpdates, resourceData);
+  nsTArray<ipc::Shmem> smallShmems;
+  nsTArray<ipc::Shmem> largeShmems;
+  aResources.Flush(resourceUpdates, smallShmems, largeShmems);
 
-  this->SendUpdateResources(resourceUpdates, resourceData);
+  this->SendUpdateResources(resourceUpdates, Move(smallShmems), Move(largeShmems));
 }
 
 void
 WebRenderBridgeChild::EndTransaction(wr::DisplayListBuilder &aBuilder,
                                      wr::IpcResourceUpdateQueue& aResources,
                                      const gfx::IntSize& aSize,
                                      bool aIsSync,
                                      uint64_t aTransactionId,
@@ -131,30 +132,31 @@ WebRenderBridgeChild::EndTransaction(wr:
   ByteBuffer dlData(Move(dl.dl));
 
   TimeStamp fwdTime;
 #if defined(ENABLE_FRAME_LATENCY_LOG)
   fwdTime = TimeStamp::Now();
 #endif
 
   nsTArray<OpUpdateResource> resourceUpdates;
-  nsTArray<ipc::Shmem> resourceData;
-  aResources.Flush(resourceUpdates, resourceData);
+  nsTArray<ipc::Shmem> smallShmems;
+  nsTArray<ipc::Shmem> largeShmems;
+  aResources.Flush(resourceUpdates, smallShmems, largeShmems);
 
   if (aIsSync) {
     this->SendSetDisplayListSync(aSize, mParentCommands, mDestroyedActors,
                                  GetFwdTransactionId(), aTransactionId,
                                  contentSize, dlData, dl.dl_desc, aScrollData,
-                                 Move(resourceUpdates), Move(resourceData),
+                                 Move(resourceUpdates), Move(smallShmems), Move(largeShmems),
                                  mIdNamespace, aTxnStartTime, fwdTime);
   } else {
     this->SendSetDisplayList(aSize, mParentCommands, mDestroyedActors,
                              GetFwdTransactionId(), aTransactionId,
                              contentSize, dlData, dl.dl_desc, aScrollData,
-                             Move(resourceUpdates), Move(resourceData),
+                             Move(resourceUpdates), Move(smallShmems), Move(largeShmems),
                              mIdNamespace, aTxnStartTime, fwdTime);
   }
 
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -230,20 +230,21 @@ WebRenderBridgeParent::DeallocShmems(nsT
       DeallocShmem(shm);
     }
   }
   aShmems.Clear();
 }
 
 bool
 WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
-                                       const nsTArray<ipc::Shmem>& aResourceData,
+                                       const nsTArray<ipc::Shmem>& aSmallShmems,
+                                       const nsTArray<ipc::Shmem>& aLargeShmems,
                                        wr::ResourceUpdateQueue& aUpdates)
 {
-  wr::ShmSegmentsReader reader(aResourceData);
+  wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
 
   for (const auto& cmd : aResourceUpdates) {
     switch (cmd.type()) {
       case OpUpdateResource::TOpAddImage: {
         const auto& op = cmd.get_OpAddImage();
         wr::Vec_u8 bytes;
         if (!reader.Read(op.bytes(), bytes)) {
           return false;
@@ -273,16 +274,23 @@ WebRenderBridgeParent::UpdateResources(c
         const auto& op = cmd.get_OpUpdateBlobImage();
         wr::Vec_u8 bytes;
         if (!reader.Read(op.bytes(), bytes)) {
           return false;
         }
         aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes);
         break;
       }
+      case OpUpdateResource::TOpAddExternalImage: {
+        const auto& op = cmd.get_OpAddExternalImage();
+        if (!AddExternalImage(op.externalImageId(), op.key(), aUpdates)) {
+          return false;
+        }
+        break;
+      }
       case OpUpdateResource::TOpAddRawFont: {
         const auto& op = cmd.get_OpAddRawFont();
         wr::Vec_u8 bytes;
         if (!reader.Read(op.bytes(), bytes)) {
           return false;
         }
         aUpdates.AddRawFont(op.key(), bytes, op.fontIndex());
         break;
@@ -312,34 +320,88 @@ WebRenderBridgeParent::UpdateResources(c
       }
       case OpUpdateResource::T__None: break;
     }
   }
 
   return true;
 }
 
+bool
+WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
+                                        wr::ResourceUpdateQueue& aResources)
+{
+  Range<const wr::ImageKey> keys(&aKey, 1);
+  // Check if key is obsoleted.
+  if (keys[0].mNamespace != mIdNamespace) {
+    return true;
+  }
+  MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(aExtId)).get());
+
+  RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(aExtId));
+  if (!host) {
+    NS_ERROR("CompositableHost does not exist");
+    return false;
+  }
+  if (!gfxEnv::EnableWebRenderRecording()) {
+    TextureHost* texture = host->GetAsTextureHostForComposite();
+    if (!texture) {
+      NS_ERROR("TextureHost does not exist");
+      return false;
+    }
+    WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
+    if (wrTexture) {
+      wrTexture->AddWRImage(aResources, keys, wrTexture->GetExternalImageKey());
+      return true;
+    }
+  }
+  RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
+  if (!dSurf) {
+    NS_ERROR("TextureHost does not return DataSourceSurface");
+    return false;
+  }
+
+  DataSourceSurface::MappedSurface map;
+  if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
+    NS_ERROR("DataSourceSurface failed to map");
+    return false;
+  }
+
+  IntSize size = dSurf->GetSize();
+  wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
+  wr::Vec_u8 data;
+  data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
+  aResources.AddImage(keys[0], descriptor, data);
+  dSurf->Unmap();
+
+  return true;
+}
+
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                           nsTArray<ipc::Shmem>&& aResourceData)
+                                           nsTArray<ipc::Shmem>&& aSmallShmems,
+                                           nsTArray<ipc::Shmem>&& aLargeShmems)
 {
   if (mDestroyed) {
-    DeallocShmems(aResourceData);
+    DeallocShmems(aSmallShmems);
+    DeallocShmems(aLargeShmems);
     return IPC_OK();
   }
 
   wr::ResourceUpdateQueue updates;
 
-  if (!UpdateResources(aResourceUpdates, aResourceData, updates)) {
-    DeallocShmems(aResourceData);
+  if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, updates)) {
+    DeallocShmems(aSmallShmems);
+    DeallocShmems(aLargeShmems);
     IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
   }
 
   mApi->UpdateResources(updates);
-  DeallocShmems(aResourceData);
+  DeallocShmems(aSmallShmems);
+  DeallocShmems(aLargeShmems);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds)
 {
   if (mDestroyed) {
     return IPC_OK();
@@ -435,79 +497,110 @@ WebRenderBridgeParent::RecvSetDisplayLis
                                           InfallibleTArray<OpDestroy>&& aToDestroy,
                                           const uint64_t& aFwdTransactionId,
                                           const uint64_t& aTransactionId,
                                           const wr::LayoutSize& aContentSize,
                                           const wr::ByteBuffer& dl,
                                           const wr::BuiltDisplayListDescriptor& dlDesc,
                                           const WebRenderScrollData& aScrollData,
                                           nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                          nsTArray<ipc::Shmem>&& aResourceData,
+                                          nsTArray<ipc::Shmem>&& aSmallShmems,
+                                          nsTArray<ipc::Shmem>&& aLargeShmems,
                                           const wr::IdNamespace& aIdNamespace,
                                           const TimeStamp& aTxnStartTime,
                                           const TimeStamp& aFwdTime)
 {
   if (mDestroyed) {
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
-    DeallocShmems(aResourceData);
+    DeallocShmems(aSmallShmems);
+    DeallocShmems(aLargeShmems);
     return IPC_OK();
   }
 
   AutoProfilerTracing tracing("Paint", "SetDisplayList");
   UpdateFwdTransactionId(aFwdTransactionId);
   AutoClearReadLocks clearLocks(mReadLocks);
 
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvDPEnd without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
+  uint32_t wrEpoch = GetNextWrEpoch();
+
+
   wr::ResourceUpdateQueue resources;
-  UpdateResources(aResourceUpdates, aResourceData, resources);
+
+  mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
+  ProcessWebRenderParentCommands(aCommands, resources);
+
+  if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, resources)) {
+    return IPC_FAIL(this, "Failed to deserialize resource updates");
+  }
 
-  uint32_t wrEpoch = GetNextWrEpoch();
-  ProcessWebRenderCommands(aSize, aCommands, wr::NewEpoch(wrEpoch),
-                           aContentSize, dl, dlDesc, resources, aIdNamespace);
+  // If id namespaces do not match, it means the command is obsolete, probably
+  // because the tab just moved to a new window.
+  // In that case do not send the commands to webrender.
+  if (mIdNamespace == aIdNamespace) {
+    if (mWidget) {
+      LayoutDeviceIntSize size = mWidget->GetClientSize();
+      mApi->SetWindowParameters(size);
+    }
+    gfx::Color color = mWidget ? gfx::Color(0.3f, 0.f, 0.f, 1.f) : gfx::Color(0.f, 0.f, 0.f, 0.f);
+    mApi->SetDisplayList(color, wr::NewEpoch(wrEpoch), LayerSize(aSize.width, aSize.height),
+                        mPipelineId, aContentSize,
+                        dlDesc, dl.mData, dl.mLength,
+                        resources);
+
+    ScheduleComposition();
+
+    if (ShouldParentObserveEpoch()) {
+      mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
+    }
+  }
+
   HoldPendingTransactionId(wrEpoch, aTransactionId, aTxnStartTime, aFwdTime);
 
   mScrollData = aScrollData;
   UpdateAPZ();
 
   if (mIdNamespace != aIdNamespace) {
     // Pretend we composited since someone is wating for this event,
     // though DisplayList was not pushed to webrender.
     TimeStamp now = TimeStamp::Now();
     mCompositorBridge->DidComposite(wr::AsUint64(mPipelineId), now, now);
   }
 
-  DeallocShmems(aResourceData);
+  DeallocShmems(aSmallShmems);
+  DeallocShmems(aLargeShmems);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetDisplayListSync(const gfx::IntSize &aSize,
                                               InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                               InfallibleTArray<OpDestroy>&& aToDestroy,
                                               const uint64_t& aFwdTransactionId,
                                               const uint64_t& aTransactionId,
                                               const wr::LayoutSize& aContentSize,
                                               const wr::ByteBuffer& dl,
                                               const wr::BuiltDisplayListDescriptor& dlDesc,
                                               const WebRenderScrollData& aScrollData,
                                               nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                              nsTArray<ipc::Shmem>&& aResourceData,
+                                              nsTArray<ipc::Shmem>&& aSmallShmems,
+                                              nsTArray<ipc::Shmem>&& aLargeShmems,
                                               const wr::IdNamespace& aIdNamespace,
                                               const TimeStamp& aTxnStartTime,
                                               const TimeStamp& aFwdTime)
 {
   return RecvSetDisplayList(aSize, Move(aCommands), Move(aToDestroy),
                             aFwdTransactionId, aTransactionId,
                             aContentSize, dl, dlDesc, aScrollData,
-                            Move(aResourceUpdates), Move(aResourceData),
+                            Move(aResourceUpdates), Move(aSmallShmems), Move(aLargeShmems),
                             aIdNamespace, aTxnStartTime, aFwdTime);
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvParentCommands(nsTArray<WebRenderParentCommand>&& aCommands)
 {
   if (mDestroyed) {
     return IPC_OK();
@@ -520,63 +613,16 @@ WebRenderBridgeParent::RecvParentCommand
 
 void
 WebRenderBridgeParent::ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands,
                                                       wr::ResourceUpdateQueue& aResources)
 {
   for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
     const WebRenderParentCommand& cmd = aCommands[i];
     switch (cmd.type()) {
-      case WebRenderParentCommand::TOpAddExternalImage: {
-        const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
-        Range<const wr::ImageKey> keys(&op.key(), 1);
-        // Check if key is obsoleted.
-        if (keys[0].mNamespace != mIdNamespace) {
-          break;
-        }
-        MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
-
-        RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId()));
-        if (!host) {
-          NS_ERROR("CompositableHost does not exist");
-          break;
-        }
-        if (!gfxEnv::EnableWebRenderRecording()) {
-          TextureHost* texture = host->GetAsTextureHostForComposite();
-          if (!texture) {
-            NS_ERROR("TextureHost does not exist");
-            break;
-          }
-          WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
-          if (wrTexture) {
-            wrTexture->AddWRImage(aResources, keys, wrTexture->GetExternalImageKey());
-            break;
-          }
-        }
-        RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
-        if (!dSurf) {
-          NS_ERROR("TextureHost does not return DataSourceSurface");
-          break;
-        }
-
-        DataSourceSurface::MappedSurface map;
-        if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
-          NS_ERROR("DataSourceSurface failed to map");
-          break;
-        }
-
-        IntSize size = dSurf->GetSize();
-        wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
-        wr::Vec_u8 data;
-        data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
-        aResources.AddImage(keys[0], descriptor, data);
-
-        dSurf->Unmap();
-        break;
-      }
       case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
         const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline();
         mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(),
                                                       op.scBounds(),
                                                       op.scTransform(),
                                                       op.scaleToSize(),
                                                       op.filter(),
                                                       op.mixBlendMode());
@@ -609,50 +655,16 @@ WebRenderBridgeParent::ProcessWebRenderP
       default: {
         // other commands are handle on the child
         break;
       }
     }
   }
 }
 
-void
-WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
-                                                InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
-                                                const wr::LayoutSize& aContentSize, const wr::ByteBuffer& dl,
-                                                const wr::BuiltDisplayListDescriptor& dlDesc,
-                                                wr::ResourceUpdateQueue& aResourceUpdates,
-                                                const wr::IdNamespace& aIdNamespace)
-{
-  mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
-  ProcessWebRenderParentCommands(aCommands, aResourceUpdates);
-
-  // The command is obsoleted.
-  // Do not set the command to webrender since it causes crash in webrender.
-  if (mIdNamespace != aIdNamespace) {
-    return;
-  }
-
-  if (mWidget) {
-    LayoutDeviceIntSize size = mWidget->GetClientSize();
-    mApi->SetWindowParameters(size);
-  }
-  gfx::Color color = mWidget ? gfx::Color(0.3f, 0.f, 0.f, 1.f) : gfx::Color(0.f, 0.f, 0.f, 0.f);
-  mApi->SetDisplayList(color, aEpoch, LayerSize(aSize.width, aSize.height),
-                       mPipelineId, aContentSize,
-                       dlDesc, dl.mData, dl.mLength,
-                       aResourceUpdates);
-
-  ScheduleComposition();
-
-  if (ShouldParentObserveEpoch()) {
-    mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
-  }
-}
-
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvGetSnapshot(PTextureParent* aTexture)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   MOZ_ASSERT(!mPaused);
 
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -69,42 +69,45 @@ public:
 
   mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override;
 
   mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override;
   mozilla::ipc::IPCResult RecvShutdown() override;
   mozilla::ipc::IPCResult RecvShutdownSync() override;
   mozilla::ipc::IPCResult RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds) override;
   mozilla::ipc::IPCResult RecvUpdateResources(nsTArray<OpUpdateResource>&& aUpdates,
-                                              nsTArray<ipc::Shmem>&& aResourceData) override;
+                                              nsTArray<ipc::Shmem>&& aSmallShmems,
+                                              nsTArray<ipc::Shmem>&& aLargeShmems) override;
   mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize,
                                              InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                              InfallibleTArray<OpDestroy>&& aToDestroy,
                                              const uint64_t& aFwdTransactionId,
                                              const uint64_t& aTransactionId,
                                              const wr::LayoutSize& aContentSize,
                                              const wr::ByteBuffer& dl,
                                              const wr::BuiltDisplayListDescriptor& dlDesc,
                                              const WebRenderScrollData& aScrollData,
                                              nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                             nsTArray<ipc::Shmem>&& aResourceData,
+                                             nsTArray<ipc::Shmem>&& aSmallShmems,
+                                             nsTArray<ipc::Shmem>&& aLargeShmems,
                                              const wr::IdNamespace& aIdNamespace,
                                              const TimeStamp& aTxnStartTime,
                                              const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvSetDisplayListSync(const gfx::IntSize& aSize,
                                                  InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                                  const uint64_t& aFwdTransactionId,
                                                  const uint64_t& aTransactionId,
                                                  const wr::LayoutSize& aContentSize,
                                                  const wr::ByteBuffer& dl,
                                                  const wr::BuiltDisplayListDescriptor& dlDesc,
                                                  const WebRenderScrollData& aScrollData,
                                                  nsTArray<OpUpdateResource>&& aResourceUpdates,
-                                                 nsTArray<ipc::Shmem>&& aResourceData,
+                                                 nsTArray<ipc::Shmem>&& aSmallShmems,
+                                                 nsTArray<ipc::Shmem>&& aLargeShmems,
                                                  const wr::IdNamespace& aIdNamespace,
                                                  const TimeStamp& aTxnStartTime,
                                                  const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvParentCommands(nsTArray<WebRenderParentCommand>&& commands) override;
   mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
                                                            const CompositableHandle& aHandle,
@@ -185,30 +188,26 @@ public:
 
 private:
   void DeallocShmems(nsTArray<ipc::Shmem>& aShmems);
 
   explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId);
   virtual ~WebRenderBridgeParent();
 
   bool UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
-                       const nsTArray<ipc::Shmem>& aResourceData,
+                       const nsTArray<ipc::Shmem>& aSmallShmems,
+                       const nsTArray<ipc::Shmem>& aLargeShmems,
                        wr::ResourceUpdateQueue& aUpdates);
+  bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
+                        wr::ResourceUpdateQueue& aResources);
 
   uint64_t GetLayersId() const;
   void ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands,
                                       wr::ResourceUpdateQueue& aResources);
-  void ProcessWebRenderCommands(const gfx::IntSize &aSize,
-                                InfallibleTArray<WebRenderParentCommand>& commands,
-                                const wr::Epoch& aEpoch,
-                                const wr::LayoutSize& aContentSize,
-                                const wr::ByteBuffer& dl,
-                                const wr::BuiltDisplayListDescriptor& dlDesc,
-                                wr::ResourceUpdateQueue& aResourceUpdates,
-                                const wr::IdNamespace& aIdNamespace);
+
   void ClearResources();
   uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
   bool ShouldParentObserveEpoch();
   mozilla::ipc::IPCResult HandleShutdown();
 
   void AdvanceAnimations();
   void SampleAnimations(nsTArray<wr::WrOpacityProperty>& aOpacityArray,
                         nsTArray<wr::WrTransformProperty>& aTransformArray);
--- a/gfx/layers/wr/WebRenderCanvasLayer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasLayer.cpp
@@ -11,16 +11,17 @@
 #include "GLContext.h"
 #include "GLScreenBuffer.h"
 #include "LayersLogging.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/layers/ScrollingLayersHelper.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClientSharedSurface.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "PersistentBufferProvider.h"
 #include "SharedSurface.h"
 #include "SharedSurfaceGL.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "WebRenderCanvasRenderer.h"
 
 namespace mozilla {
 namespace layers {
@@ -45,32 +46,35 @@ WebRenderCanvasLayer::RenderLayer(wr::Di
   MOZ_ASSERT(canvasRenderer);
   canvasRenderer->UpdateCompositableClient();
 
   Maybe<gfx::Matrix4x4> transform;
   if (canvasRenderer->NeedsYFlip()) {
     transform = Some(GetTransform().PreTranslate(0, mBounds.Height(), 0).PreScale(1, -1, 1));
   }
 
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this, transform);
 
   LayerRect rect(0, 0, mBounds.Width(), mBounds.Height());
   DumpLayerInfo("CanvasLayer", rect);
 
   wr::ImageRendering filter = wr::ToImageRendering(mSamplingFilter);
 
   if (gfxPrefs::LayersDump()) {
     printf_stderr("CanvasLayer %p texture-filter=%s\n",
                   this->GetLayer(),
                   Stringify(filter).c_str());
   }
 
+  // Eww. Re-creating image keys every time is bad. Probably not worth fixing here
+  // since layers-full webrender is going away soon-ish. But don't reproduce what
+  // you see here.
   wr::WrImageKey key = GenerateImageKey();
-  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(canvasRenderer->GetExternalImageId().value(), key));
+  aResources.AddExternalImage(canvasRenderer->GetExternalImageId().value(), key);
   WrManager()->AddImageKeyForDiscard(key);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
   aBuilder.PushImage(r, r, filter, key);
 }
 
 void
 WebRenderCanvasLayer::ClearCachedResources()
--- a/gfx/layers/wr/WebRenderCanvasLayer.h
+++ b/gfx/layers/wr/WebRenderCanvasLayer.h
@@ -28,17 +28,17 @@ public:
   }
 
   CanvasRenderer* CreateCanvasRendererInternal() override;
 
   virtual void ClearCachedResources() override;
 
 protected:
   virtual ~WebRenderCanvasLayer();
-
+  Maybe<wr::ImageKey> mKey;
 public:
   Layer* GetLayer() override { return this; }
   void RenderLayer(wr::DisplayListBuilder& aBuilder,
                    wr::IpcResourceUpdateQueue& aResources,
                    const StackingContextHelper& aSc) override;
 };
 
 } // namespace layers
--- a/gfx/layers/wr/WebRenderColorLayer.cpp
+++ b/gfx/layers/wr/WebRenderColorLayer.cpp
@@ -18,17 +18,17 @@ namespace layers {
 
 using namespace mozilla::gfx;
 
 void
 WebRenderColorLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                  wr::IpcResourceUpdateQueue& aResources,
                                  const StackingContextHelper& aSc)
 {
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
 
   LayerRect rect = Bounds();
   DumpLayerInfo("ColorLayer", rect);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
   aBuilder.PushRect(r, r, wr::ToColorF(mColor));
 }
--- a/gfx/layers/wr/WebRenderContainerLayer.cpp
+++ b/gfx/layers/wr/WebRenderContainerLayer.cpp
@@ -102,17 +102,17 @@ WebRenderContainerLayer::RenderLayer(wr:
     transformForSC = nullptr;
   }
 
   nsTArray<wr::WrFilterOp> filters;
   for (const CSSFilter& filter : this->GetFilterChain()) {
     filters.AppendElement(wr::ToWrFilterOp(filter));
   }
 
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC, filters);
 
   LayerRect rect = Bounds();
   DumpLayerInfo("ContainerLayer", rect);
 
   for (LayerPolygon& child : children) {
     if (child.layer->IsBackfaceHidden()) {
       continue;
@@ -121,17 +121,17 @@ WebRenderContainerLayer::RenderLayer(wr:
   }
 }
 
 void
 WebRenderRefLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                wr::IpcResourceUpdateQueue& aResources,
                                const StackingContextHelper& aSc)
 {
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
 
   ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
   // As with WebRenderTextLayer, because we don't push a stacking context for
   // this layer, WR doesn't know about the transform on this layer. Therefore
   // we need to apply that transform to the bounds before we pass it on to WR.
   // The conversion from ParentLayerPixel to LayerPixel below is a result of
   // changing the reference layer from "this layer" to the "the layer that
   // created aSc".
--- a/gfx/layers/wr/WebRenderDisplayItemLayer.cpp
+++ b/gfx/layers/wr/WebRenderDisplayItemLayer.cpp
@@ -27,25 +27,24 @@ void
 WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                        wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc)
 {
   if (mVisibleRegion.IsEmpty()) {
     return;
   }
 
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
 
   if (mItem) {
     wr::LayoutSize contentSize; // this won't actually be used by anything
     wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
     // We might have recycled this layer. Throw away the old commands.
-    mParentCommands.Clear();
 
-    mItem->CreateWebRenderCommands(builder, aResources, aSc, mParentCommands, WrManager(),
+    mItem->CreateWebRenderCommands(builder, aResources, aSc, WrManager(),
                                    GetDisplayListBuilder());
     builder.Finalize(contentSize, mBuiltDisplayList);
   } else {
     // else we have an empty transaction and just use the
     // old commands.
     WebRenderLayerManager* manager = WrManager();
     MOZ_ASSERT(manager);
 
@@ -53,13 +52,12 @@ WebRenderDisplayItemLayer::RenderLayer(w
     // If this layer or our parent changed, this empty transaction won't work.
     if (manager->IsMutatedLayer(this) || manager->IsMutatedLayer(GetParent())) {
       manager->SetTransactionIncomplete();
       return;
     }
   }
 
   aBuilder.PushBuiltDisplayList(mBuiltDisplayList);
-  WrBridge()->AddWebRenderParentCommands(mParentCommands);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderDisplayItemLayer.h
+++ b/gfx/layers/wr/WebRenderDisplayItemLayer.h
@@ -32,15 +32,14 @@ protected:
 public:
   Layer* GetLayer() override { return this; }
   void RenderLayer(wr::DisplayListBuilder& aBuilder,
                    wr::IpcResourceUpdateQueue& aResources,
                    const StackingContextHelper& aHelper) override;
 
 private:
   wr::BuiltDisplayList mBuiltDisplayList;
-  nsTArray<WebRenderParentCommand> mParentCommands;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // GFX_WEBRENDERDisplayItemLayer_H
--- a/gfx/layers/wr/WebRenderImageLayer.cpp
+++ b/gfx/layers/wr/WebRenderImageLayer.cpp
@@ -5,30 +5,32 @@
 
 #include "WebRenderImageLayer.h"
 
 #include "gfxPrefs.h"
 #include "LayersLogging.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageClient.h"
+#include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/ScrollingLayersHelper.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
 #include "mozilla/layers/TextureWrapperImage.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
 WebRenderImageLayer::WebRenderImageLayer(WebRenderLayerManager* aLayerManager)
   : ImageLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+  , mKey(Nothing())
   , mImageClientContainerType(CompositableType::UNKNOWN)
 {
   MOZ_COUNT_CTOR(WebRenderImageLayer);
 }
 
 WebRenderImageLayer::~WebRenderImageLayer()
 {
   MOZ_COUNT_DTOR(WebRenderImageLayer);
@@ -103,16 +105,53 @@ WebRenderImageLayer::SupportsAsyncUpdate
 {
   if (GetImageClientType() == CompositableType::IMAGE_BRIDGE &&
       mPipelineId.isSome()) {
     return true;
   }
   return false;
 }
 
+Maybe<wr::ImageKey>
+WebRenderImageLayer::UpdateImageKey(ImageClientSingle* aImageClient,
+                                    ImageContainer* aContainer,
+                                    Maybe<wr::ImageKey>& aOldKey,
+                                    wr::ExternalImageId& aExternalImageId,
+                                    wr::IpcResourceUpdateQueue& aResources)
+{
+  MOZ_ASSERT(aImageClient);
+  MOZ_ASSERT(aContainer);
+
+  uint32_t oldCounter = aImageClient->GetLastUpdateGenerationCounter();
+
+  bool ret = aImageClient->UpdateImage(aContainer, /* unused */0);
+  if (!ret || aImageClient->IsEmpty()) {
+    // Delete old key
+    if (aOldKey.isSome()) {
+      WrManager()->AddImageKeyForDiscard(aOldKey.value());
+    }
+    return Nothing();
+  }
+
+  // Reuse old key if generation is not updated.
+  if (oldCounter == aImageClient->GetLastUpdateGenerationCounter() && aOldKey.isSome()) {
+    return aOldKey;
+  }
+
+  // Delete old key, we are generating a new key.
+  // TODO: stop doing this!
+  if (aOldKey.isSome()) {
+    WrManager()->AddImageKeyForDiscard(aOldKey.value());
+  }
+
+  wr::WrImageKey key = GenerateImageKey();
+  aResources.AddExternalImage(aExternalImageId, key);
+  return Some(key);
+}
+
 void
 WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                  wr::IpcResourceUpdateQueue& aResources,
                                  const StackingContextHelper& aSc)
 {
   if (!mContainer) {
      return;
   }
@@ -148,17 +187,17 @@ WebRenderImageLayer::RenderLayer(wr::Dis
 
   if (GetImageClientType() == CompositableType::IMAGE_BRIDGE) {
     MOZ_ASSERT(!mImageClient);
     MOZ_ASSERT(mExternalImageId.isNothing());
 
     // Push IFrame for async image pipeline.
     // XXX Remove this once partial display list update is supported.
 
-    ScrollingLayersHelper scroller(this, aBuilder, aSc);
+    ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
 
     ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
 
     // We don't push a stacking context for this async image pipeline here.
     // Instead, we do it inside the iframe that hosts the image. As a result,
     // a bunch of the calculations normally done as part of that stacking
     // context need to be done manually and pushed over to the parent side,
     // where it will be done when we build the display list for the iframe.
@@ -204,22 +243,23 @@ WebRenderImageLayer::RenderLayer(wr::Dis
   Image* image = autoLock.GetImage();
   if (!image) {
     return;
   }
   gfx::IntSize size = image->GetSize();
   mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
                         mContainer,
                         mKey,
-                        mExternalImageId.ref());
+                        mExternalImageId.ref(),
+                        aResources);
   if (mKey.isNothing()) {
     return;
   }
 
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
 
   LayerRect rect(0, 0, size.width, size.height);
   if (mScaleMode != ScaleMode::SCALE_NONE) {
     NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
                  "No other scalemodes than stretch and none supported yet.");
     rect = LayerRect(0, 0, mScaleToSize.width, mScaleToSize.height);
   }
@@ -233,17 +273,18 @@ WebRenderImageLayer::RenderLayer(wr::Dis
                   Stringify(filter).c_str());
   }
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
   aBuilder.PushImage(r, r, filter, mKey.value());
 }
 
 Maybe<wr::WrImageMask>
 WebRenderImageLayer::RenderMaskLayer(const StackingContextHelper& aSc,
-                                     const gfx::Matrix4x4& aTransform)
+                                     const gfx::Matrix4x4& aTransform,
+                                     wr::IpcResourceUpdateQueue& aResources)
 {
   if (!mContainer) {
      return Nothing();
   }
 
   CompositableType type = GetImageClientType();
   if (type == CompositableType::UNKNOWN) {
     return Nothing();
@@ -273,17 +314,18 @@ WebRenderImageLayer::RenderMaskLayer(con
   if (!image) {
     return Nothing();
   }
 
   MOZ_ASSERT(mImageClient->AsImageClientSingle());
   mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
                         mContainer,
                         mKey,
-                        mExternalImageId.ref());
+                        mExternalImageId.ref(),
+                        aResources);
   if (mKey.isNothing()) {
     return Nothing();
   }
 
   gfx::IntSize size = image->GetSize();
   wr::WrImageMask imageMask;
   imageMask.image = mKey.value();
   Rect maskRect = aTransform.TransformBounds(Rect(0, 0, size.width, size.height));
--- a/gfx/layers/wr/WebRenderImageLayer.h
+++ b/gfx/layers/wr/WebRenderImageLayer.h
@@ -30,24 +30,32 @@ protected:
   virtual ~WebRenderImageLayer();
 
 public:
   Layer* GetLayer() override { return this; }
   void RenderLayer(wr::DisplayListBuilder& aBuilder,
                    wr::IpcResourceUpdateQueue& aResources,
                    const StackingContextHelper& aSc) override;
   Maybe<wr::WrImageMask> RenderMaskLayer(const StackingContextHelper& aSc,
-                                         const gfx::Matrix4x4& aTransform) override;
+                                         const gfx::Matrix4x4& aTransform,
+                                         wr::IpcResourceUpdateQueue& aResources) override;
 
 protected:
   CompositableType GetImageClientType();
   void ClearWrResources();
 
   void AddWRVideoImage(size_t aChannelNumber);
 
+  Maybe<wr::ImageKey>
+  UpdateImageKey(ImageClientSingle* aImageClient,
+                 ImageContainer* aContainer,
+                 Maybe<wr::ImageKey>& aOldKey,
+                 wr::ExternalImageId& aExternalImageId,
+                 wr::IpcResourceUpdateQueue& aResources);
+
   wr::MaybeExternalImageId mExternalImageId;
   Maybe<wr::ImageKey> mKey;
   RefPtr<ImageClient> mImageClient;
   CompositableType mImageClientContainerType;
   Maybe<wr::PipelineId> mPipelineId;
 };
 
 } // namespace layers
--- a/gfx/layers/wr/WebRenderLayer.cpp
+++ b/gfx/layers/wr/WebRenderLayer.cpp
@@ -36,22 +36,23 @@ WebRenderLayer::GenerateImageKey()
 {
   wr::WrImageKey key;
   key.mNamespace = WrBridge()->GetNamespace();
   key.mHandle = WrBridge()->GetNextResourceId();
   return key;
 }
 
 Maybe<wr::WrImageMask>
-WebRenderLayer::BuildWrMaskLayer(const StackingContextHelper& aRelativeTo)
+WebRenderLayer::BuildWrMaskLayer(const StackingContextHelper& aRelativeTo,
+                                 wr::IpcResourceUpdateQueue& aResources)
 {
   if (GetLayer()->GetMaskLayer()) {
     WebRenderLayer* maskLayer = ToWebRenderLayer(GetLayer()->GetMaskLayer());
     gfx::Matrix4x4 transform = maskLayer->GetLayer()->GetTransform();
-    return maskLayer->RenderMaskLayer(aRelativeTo, transform);
+    return maskLayer->RenderMaskLayer(aRelativeTo, transform, aResources);
   }
 
   return Nothing();
 }
 
 LayerRect
 WebRenderLayer::Bounds()
 {
@@ -76,51 +77,16 @@ WebRenderLayer::BoundsForStackingContext
   if (!transform.IsIdentity()) {
     // WR will only apply the 'translate' of the transform, so we need to do the scale/rotation manually.
     bounds.MoveTo(transform.TransformPoint(bounds.TopLeft()));
   }
 
   return bounds;
 }
 
-Maybe<wr::ImageKey>
-WebRenderLayer::UpdateImageKey(ImageClientSingle* aImageClient,
-                               ImageContainer* aContainer,
-                               Maybe<wr::ImageKey>& aOldKey,
-                               wr::ExternalImageId& aExternalImageId)
-{
-  MOZ_ASSERT(aImageClient);
-  MOZ_ASSERT(aContainer);
-
-  uint32_t oldCounter = aImageClient->GetLastUpdateGenerationCounter();
-
-  bool ret = aImageClient->UpdateImage(aContainer, /* unused */0);
-  if (!ret || aImageClient->IsEmpty()) {
-    // Delete old key
-    if (aOldKey.isSome()) {
-      WrManager()->AddImageKeyForDiscard(aOldKey.value());
-    }
-    return Nothing();
-  }
-
-  // Reuse old key if generation is not updated.
-  if (oldCounter == aImageClient->GetLastUpdateGenerationCounter() && aOldKey.isSome()) {
-    return aOldKey;
-  }
-
-  // Delete old key, we are generating a new key.
-  if (aOldKey.isSome()) {
-    WrManager()->AddImageKeyForDiscard(aOldKey.value());
-  }
-
-  wr::WrImageKey key = GenerateImageKey();
-  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(aExternalImageId, key));
-  return Some(key);
-}
-
 void
 WebRenderLayer::DumpLayerInfo(const char* aLayerType, const LayerRect& aRect)
 {
   if (!gfxPrefs::LayersDump()) {
     return;
   }
 
   Layer* layer = GetLayer();
--- a/gfx/layers/wr/WebRenderLayer.h
+++ b/gfx/layers/wr/WebRenderLayer.h
@@ -6,16 +6,19 @@
 #ifndef GFX_WEBRENDERLAYER_H
 #define GFX_WEBRENDERLAYER_H
 
 #include "Layers.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
+namespace wr {
+class IpcResourceUpdateQueue;
+}
 namespace layers {
 
 class ImageClientSingle;
 class StackingContextHelper;
 class WebRenderBridgeChild;
 class WebRenderLayerManager;
 
 typedef gfx::Matrix4x4Typed<LayerPixel, LayerPixel> BoundsTransformMatrix;
@@ -23,47 +26,44 @@ typedef gfx::Matrix4x4Typed<LayerPixel, 
 class WebRenderLayer
 {
 public:
   virtual Layer* GetLayer() = 0;
   virtual void RenderLayer(wr::DisplayListBuilder& aBuilder,
                            wr::IpcResourceUpdateQueue& aResources,
                            const StackingContextHelper& aSc) = 0;
   virtual Maybe<wr::WrImageMask> RenderMaskLayer(const StackingContextHelper& aSc,
-                                             const gfx::Matrix4x4& aTransform)
+                                                 const gfx::Matrix4x4& aTransform,
+                                                 wr::IpcResourceUpdateQueue& aResources)
   {
     MOZ_ASSERT(false);
     return Nothing();
   }
 
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() { return nullptr; }
   static inline WebRenderLayer*
   ToWebRenderLayer(Layer* aLayer)
   {
     return static_cast<WebRenderLayer*>(aLayer->ImplData());
   }
 
-  Maybe<wr::ImageKey> UpdateImageKey(ImageClientSingle* aImageClient,
-                                     ImageContainer* aContainer,
-                                     Maybe<wr::ImageKey>& aOldKey,
-                                     wr::ExternalImageId& aExternalImageId);
-
   WebRenderLayerManager* WrManager();
   WebRenderBridgeChild* WrBridge();
   wr::WrImageKey GenerateImageKey();
 
   LayerRect Bounds();
   LayerRect BoundsForStackingContext();
 
   // Builds a WrImageMask from the mask layer on this layer, if there is one.
   // The |aRelativeTo| parameter should be a reference to the stacking context
   // that we want this mask to be relative to. This is usually the stacking
   // context of the *parent* layer of |this|, because that is what the mask
   // is relative to in the layer tree.
-  Maybe<wr::WrImageMask> BuildWrMaskLayer(const StackingContextHelper& aRelativeTo);
+  Maybe<wr::WrImageMask> BuildWrMaskLayer(const StackingContextHelper& aRelativeTo,
+                                          wr::IpcResourceUpdateQueue& aResources);
 
 protected:
   BoundsTransformMatrix BoundsTransform();
 
   void DumpLayerInfo(const char* aLayerType, const LayerRect& aRect);
 };
 
 } // namespace layers
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -336,17 +336,17 @@ WebRenderLayerManager::CreateWebRenderCo
       }
     }
 
     { // scope the ScrollingLayersHelper
       ScrollingLayersHelper clip(item, aBuilder, aSc, mClipIdCache, AsyncPanZoomEnabled());
 
       // Note: this call to CreateWebRenderCommands can recurse back into
       // this function if the |item| is a wrapper for a sublist.
-      if (!item->CreateWebRenderCommands(aBuilder, aResources, aSc, mParentCommands, this,
+      if (!item->CreateWebRenderCommands(aBuilder, aResources, aSc, this,
                                          aDisplayListBuilder)) {
         PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
       }
     }
 
     if (apzEnabled && forceNewLayerData) {
       // Pop the thing we pushed before the recursion, so the topmost item on
       // the stack is enclosing display item's ASR (or the stack is empty)
@@ -386,16 +386,17 @@ WebRenderLayerManager::EndTransactionWit
                          aDisplayList,
                          aDisplayListBuilder);
 }
 
 Maybe<wr::ImageKey>
 WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
                                       ImageContainer* aContainer,
                                       mozilla::wr::DisplayListBuilder& aBuilder,
+                                      mozilla::wr::IpcResourceUpdateQueue& aResources,
                                       const StackingContextHelper& aSc,
                                       gfx::IntSize& aSize)
 {
   RefPtr<WebRenderImageData> imageData = CreateOrRecycleWebRenderUserData<WebRenderImageData>(aItem);
   MOZ_ASSERT(imageData);
 
   if (aContainer->IsAsync()) {
     bool snap;
@@ -404,16 +405,19 @@ WebRenderLayerManager::CreateImageKey(ns
     LayerRect rect = ViewAs<LayerPixel>(
       LayoutDeviceRect::FromAppUnits(bounds, appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
     LayerRect scBounds(0, 0, rect.width, rect.Height());
     MaybeIntSize scaleToSize;
     if (!aContainer->GetScaleHint().IsEmpty()) {
       scaleToSize = Some(aContainer->GetScaleHint());
     }
+    // TODO!
+    // We appear to be using the image bridge for a lot (most/all?) of
+    // layers-free image handling and that breaks frame consistency.
     imageData->CreateAsyncImageWebRenderCommands(aBuilder,
                                                  aContainer,
                                                  aSc,
                                                  rect,
                                                  scBounds,
                                                  gfx::Matrix4x4(),
                                                  scaleToSize,
                                                  wr::ImageRendering::Auto,
@@ -423,28 +427,31 @@ WebRenderLayerManager::CreateImageKey(ns
 
   AutoLockImage autoLock(aContainer);
   if (!autoLock.HasImage()) {
     return Nothing();
   }
   mozilla::layers::Image* image = autoLock.GetImage();
   aSize = image->GetSize();
 
-  return imageData->UpdateImageKey(aContainer);
+  return imageData->UpdateImageKey(aContainer, aResources);
 }
 
 bool
 WebRenderLayerManager::PushImage(nsDisplayItem* aItem,
                                  ImageContainer* aContainer,
                                  mozilla::wr::DisplayListBuilder& aBuilder,
+                                 mozilla::wr::IpcResourceUpdateQueue& aResources,
                                  const StackingContextHelper& aSc,
                                  const LayerRect& aRect)
 {
   gfx::IntSize size;
-  Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer, aBuilder, aSc, size);
+  Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer,
+                                          aBuilder, aResources,
+                                          aSc, size);
   if (aContainer->IsAsync()) {
     // Async ImageContainer does not create ImageKey, instead it uses Pipeline.
     MOZ_ASSERT(key.isNothing());
     return true;
   }
   if (!key) {
     return false;
   }
@@ -610,17 +617,17 @@ WebRenderLayerManager::GenerateFallbackD
         if (!helper.UpdateImage()) {
           return nullptr;
         }
       }
 
       // Force update the key in fallback data since we repaint the image in this path.
       // If not force update, fallbackData may reuse the original key because it
       // doesn't know UpdateImageHelper already updated the image container.
-      if (!fallbackData->UpdateImageKey(imageContainer, true)) {
+      if (!fallbackData->UpdateImageKey(imageContainer, aResources, true)) {
         return nullptr;
       }
     }
 
     geometry = aItem->AllocateGeometry(aDisplayListBuilder);
     fallbackData->SetInvalid(false);
   }
 
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -60,21 +60,23 @@ public:
   virtual int32_t GetMaxTextureSize() const override;
 
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
   virtual bool BeginTransaction() override;
   virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
   Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
                                      ImageContainer* aContainer,
                                      mozilla::wr::DisplayListBuilder& aBuilder,
+                                     mozilla::wr::IpcResourceUpdateQueue& aResources,
                                      const StackingContextHelper& aSc,
                                      gfx::IntSize& aSize);
   bool PushImage(nsDisplayItem* aItem,
                  ImageContainer* aContainer,
                  mozilla::wr::DisplayListBuilder& aBuilder,
+                 mozilla::wr::IpcResourceUpdateQueue& aResources,
                  const StackingContextHelper& aSc,
                  const LayerRect& aRect);
 
   already_AddRefed<WebRenderFallbackData>
   GenerateFallbackData(nsDisplayItem* aItem,
                        wr::DisplayListBuilder& aBuilder,
                        wr::IpcResourceUpdateQueue& aResourceUpdates,
                        nsDisplayListBuilder* aDisplayListBuilder,
--- a/gfx/layers/wr/WebRenderPaintedLayer.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayer.cpp
@@ -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 "WebRenderPaintedLayer.h"
 
 #include "LayersLogging.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/layers/ImageClient.h"
+#include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/ScrollingLayersHelper.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/UpdateImageHelper.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "gfxPrefs.h"
 #include "gfxUtils.h"
 
@@ -86,26 +87,28 @@ WebRenderPaintedLayer::UpdateImageClient
     return false;
   }
 
   return true;
 }
 
 void
 WebRenderPaintedLayer::CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
+                                                  wr::IpcResourceUpdateQueue& aResources,
                                                   const StackingContextHelper& aSc)
 {
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
 
   LayerRect rect = Bounds();
   DumpLayerInfo("PaintedLayer", rect);
 
   wr::WrImageKey key = GenerateImageKey();
-  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
+  aResources.AddExternalImage(mExternalImageId.value(), key);
+  // TODO: reuse image keys!
   WrManager()->AddImageKeyForDiscard(key);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
   aBuilder.PushImage(r, r, wr::ImageRendering::Auto, key);
 }
 
 void
 WebRenderPaintedLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
@@ -156,17 +159,17 @@ WebRenderPaintedLayer::RenderLayer(wr::D
     mPaintedRect = visibleBounds;
     SetValidRegion(visibleRegion);
   } else {
     // We have an empty transaction, just reuse the old image we had before.
     MOZ_ASSERT(mExternalImageId);
     MOZ_ASSERT(mImageContainer->HasCurrentImage());
   }
 
-  CreateWebRenderDisplayList(aBuilder, aSc);
+  CreateWebRenderDisplayList(aBuilder, aResources, aSc);
 }
 
 void
 WebRenderPaintedLayer::ClearCachedResources()
 {
   ClearWrResources();
   if (mImageClient) {
     mImageClient->FlushAllImages();
--- a/gfx/layers/wr/WebRenderPaintedLayer.h
+++ b/gfx/layers/wr/WebRenderPaintedLayer.h
@@ -52,16 +52,17 @@ public:
 
   RefPtr<ImageContainer> mImageContainer;
   RefPtr<ImageClient> mImageClient;
 
 private:
   bool SetupExternalImages();
   bool UpdateImageClient();
   void CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
+                                  wr::IpcResourceUpdateQueue& aResources,
                                   const StackingContextHelper& aSc);
   void ClearWrResources();
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // GFX_WEBRENDERPAINTEDLAYER_H
--- a/gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
@@ -81,17 +81,17 @@ WebRenderPaintedLayerBlob::RenderLayer(w
     }
     mImageKey = Some(GenerateImageKey());
 
     wr::ImageDescriptor descriptor(imageSize, 0, dt->GetFormat());
     aResources.AddBlobImage(mImageKey.value(), descriptor, bytes.AsSlice());
     mImageBounds = visibleRegion.GetBounds();
   }
 
-  ScrollingLayersHelper scroller(this, aBuilder, aSc);
+  ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
   LayerRect rect = Bounds();
   DumpLayerInfo("PaintedLayer", rect);
 
   aBuilder.PushImage(sc.ToRelativeLayoutRect(LayerRect(mImageBounds)),
                      sc.ToRelativeLayoutRect(rect),
                      wr::ImageRendering::Auto, mImageKey.value());
 }
--- a/gfx/layers/wr/WebRenderTextLayer.cpp
+++ b/gfx/layers/wr/WebRenderTextLayer.cpp
@@ -22,17 +22,17 @@ void
 WebRenderTextLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                 wr::IpcResourceUpdateQueue& aResources,
                                 const StackingContextHelper& aSc)
 {
     if (mBounds.IsEmpty()) {
         return;
     }
 
-    ScrollingLayersHelper scroller(this, aBuilder, aSc);
+    ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
 
     LayerRect rect = LayerRect::FromUnknownRect(
         // I am not 100% sure this is correct, but it probably is. Because:
         // the bounds are in layer space, and when gecko composites layers it
         // applies the transform to the layer before compositing. However with
         // WebRender compositing, we don't pass the transform on this layer to
         // WR, so WR has no way of knowing about the transformed bounds unless
         // we apply it here. The glyphs that we push to WR should already be
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebRenderUserData.h"
 
 #include "mozilla/layers/ImageClient.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/layers/WebRenderMessages.h"
+#include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "nsDisplayListInvalidation.h"
 #include "WebRenderCanvasRenderer.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderUserData::WebRenderUserData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem,
                                      WebRenderUserDataRefTable* aTable)
@@ -64,17 +65,19 @@ WebRenderImageData::~WebRenderImageData(
   }
 
   if (mPipelineId) {
     WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref());
   }
 }
 
 Maybe<wr::ImageKey>
-WebRenderImageData::UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate)
+WebRenderImageData::UpdateImageKey(ImageContainer* aContainer,
+                                   wr::IpcResourceUpdateQueue& aResources,
+                                   bool aForceUpdate)
 {
   CreateImageClientIfNeeded();
   CreateExternalImageIfNeeded();
 
   if (mContainer != aContainer) {
     mContainer = aContainer;
   }
 
@@ -99,22 +102,23 @@ WebRenderImageData::UpdateImageKey(Image
   }
 
   // Reuse old key if generation is not updated.
   if (!aForceUpdate && oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) {
     return mKey;
   }
 
   // Delete old key, we are generating a new key.
+  // TODO(nical): noooo... we need to reuse image keys.
   if (mKey) {
     mWRManager->AddImageKeyForDiscard(mKey.value());
   }
 
   wr::WrImageKey key = WrBridge()->GetNextImageKey();
-  mWRManager->WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
+  aResources.AddExternalImage(mExternalImageId.value(), key);
   mKey = Some(key);
 
   return mKey;
 }
 
 already_AddRefed<ImageClient>
 WebRenderImageData::GetImageClient()
 {
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -8,16 +8,20 @@
 
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/layers/AnimationInfo.h"
 
 class nsDisplayItemGeometry;
 
 namespace mozilla {
+namespace wr {
+class IpcResourceUpdateQueue;
+}
+
 namespace layers {
 class CanvasLayer;
 class ImageClient;
 class ImageContainer;
 class WebRenderBridgeChild;
 class WebRenderCanvasData;
 class WebRenderCanvasRendererAsync;
 class WebRenderImageData;
@@ -74,17 +78,19 @@ public:
 
   virtual WebRenderImageData* AsImageData() override { return this; }
   virtual UserDataType GetType() override { return UserDataType::eImage; }
   static UserDataType Type() { return UserDataType::eImage; }
   Maybe<wr::ImageKey> GetKey() { return mKey; }
   void SetKey(const wr::ImageKey& aKey) { mKey = Some(aKey); }
   already_AddRefed<ImageClient> GetImageClient();
 
-  Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate = false);
+  Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer,
+                                     wr::IpcResourceUpdateQueue& aResources,
+                                     bool aForceUpdate = false);
 
   void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          ImageContainer* aContainer,
                                          const StackingContextHelper& aSc,
                                          const LayerRect& aBounds,
                                          const LayerRect& aSCBounds,
                                          const gfx::Matrix4x4& aSCTransform,
                                          const gfx::MaybeIntSize& aScaleToSize,
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -694,37 +694,41 @@ gfxDWriteFontEntry::IsCJKFont()
 {
     if (mIsCJK != UNINITIALIZED_VALUE) {
         return mIsCJK;
     }
 
     mIsCJK = false;
 
     const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
-    AutoTArray<uint8_t, 128> buffer;
-    if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
+    hb_blob_t* blob = GetFontTable(kOS2Tag);
+    if (!blob) {
         return mIsCJK;
     }
+    // |blob| is an owning reference, but is not RAII-managed, so it must be
+    // explicitly freed using |hb_blob_destroy| before we return. (Beware of
+    // adding any early-return codepaths!)
 
+    uint32_t len;
+    const OS2Table* os2 =
+        reinterpret_cast<const OS2Table*>(hb_blob_get_data(blob, &len));
     // ulCodePageRange bit definitions for the CJK codepages,
     // from http://www.microsoft.com/typography/otspec/os2.htm#cpr
     const uint32_t CJK_CODEPAGE_BITS =
         (1 << 17) | // codepage 932 - JIS/Japan
         (1 << 18) | // codepage 936 - Chinese (simplified)
         (1 << 19) | // codepage 949 - Korean Wansung
         (1 << 20) | // codepage 950 - Chinese (traditional)
         (1 << 21);  // codepage 1361 - Korean Johab
-
-    if (buffer.Length() >= offsetof(OS2Table, sxHeight)) {
-        const OS2Table* os2 =
-            reinterpret_cast<const OS2Table*>(buffer.Elements());
+    if (len >= offsetof(OS2Table, sxHeight)) {
         if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
             mIsCJK = true;
         }
     }
+    hb_blob_destroy(blob);
 
     return mIsCJK;
 }
 
 void
 gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                            FontListSizes* aSizes) const
 {
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -20,16 +20,39 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsRefPtrHashtable.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
+#if defined(MOZ_CRASHREPORTER)
+
+#include "nsExceptionHandler.h"
+#include "nsPrintfCString.h"
+
+#define ENSURE_HR_SUCCEEDED(hr) \
+  if (FAILED(hr)) { \
+    nsPrintfCString location("ENSURE_HR_SUCCEEDED \"%s\": %u", __FILE__, __LINE__); \
+    nsPrintfCString hrAsStr("0x%08X", hr); \
+    CrashReporter::AnnotateCrashReport(location, hrAsStr); \
+    MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr)); \
+    return hr; \
+  }
+
+#else
+
+#define ENSURE_HR_SUCCEEDED(hr) \
+  if (FAILED(hr)) { \
+    return hr; \
+  }
+
+#endif // defined(MOZ_CRASHREPORTER)
+
 namespace mozilla {
 namespace mscom {
 namespace detail {
 
 class LiveSet final
 {
 public:
   LiveSet()
@@ -407,60 +430,56 @@ Interceptor::GetInitialInterceptorForIID
   MOZ_ASSERT(!IsProxy(aTarget.get()));
 
   if (aTargetIid == IID_IUnknown) {
     // We must lock ourselves so that nothing can race with us once we have been
     // published to the live set.
     AutoLock lock(*this);
 
     HRESULT hr = PublishTarget(aLiveSetLock, nullptr, aTargetIid, Move(aTarget));
-    if (FAILED(hr)) {
-      return hr;
-    }
+    ENSURE_HR_SUCCEEDED(hr);
 
-    return QueryInterface(aTargetIid, aOutInterceptor);
+    hr = QueryInterface(aTargetIid, aOutInterceptor);
+    ENSURE_HR_SUCCEEDED(hr);
+    return hr;
   }
 
   // Raise the refcount for stabilization purposes during aggregation
   RefPtr<IUnknown> kungFuDeathGrip(static_cast<IUnknown*>(
         static_cast<WeakReferenceSupport*>(this)));
 
   RefPtr<IUnknown> unkInterceptor;
   HRESULT hr = CreateInterceptor(aTargetIid, kungFuDeathGrip,
                                  getter_AddRefs(unkInterceptor));
-  if (FAILED(hr)) {
-    return hr;
-  }
+  ENSURE_HR_SUCCEEDED(hr);
 
   RefPtr<ICallInterceptor> interceptor;
   hr = unkInterceptor->QueryInterface(IID_ICallInterceptor,
                                       getter_AddRefs(interceptor));
-  if (FAILED(hr)) {
-    return hr;
-  }
+  ENSURE_HR_SUCCEEDED(hr);
 
   hr = interceptor->RegisterSink(mEventSink);
-  if (FAILED(hr)) {
-    return hr;
-  }
+  ENSURE_HR_SUCCEEDED(hr);
 
   // We must lock ourselves so that nothing can race with us once we have been
   // published to the live set.
   AutoLock lock(*this);
 
   hr = PublishTarget(aLiveSetLock, unkInterceptor, aTargetIid, Move(aTarget));
-  if (FAILED(hr)) {
+  ENSURE_HR_SUCCEEDED(hr);
+
+  if (mEventSink->MarshalAs(aTargetIid) == aTargetIid) {
+    hr = unkInterceptor->QueryInterface(aTargetIid, aOutInterceptor);
+    ENSURE_HR_SUCCEEDED(hr);
     return hr;
   }
 
-  if (mEventSink->MarshalAs(aTargetIid) == aTargetIid) {
-    return unkInterceptor->QueryInterface(aTargetIid, aOutInterceptor);
-  }
-
-  return GetInterceptorForIID(aTargetIid, aOutInterceptor);
+  hr = GetInterceptorForIID(aTargetIid, aOutInterceptor);
+  ENSURE_HR_SUCCEEDED(hr);
+  return hr;
 }
 
 /**
  * This method contains the core guts of the handling of QueryInterface calls
  * that are delegated to us from the ICallInterceptor.
  *
  * @param aIid ID of the desired interface
  * @param aOutInterceptor The resulting emulated vtable that corresponds to
@@ -500,66 +519,63 @@ Interceptor::GetInterceptorForIID(REFIID
   // (1a) A COM interceptor already exists for this interface, so all we need
   // to do is run a QI on it.
   if (unkInterceptor) {
     // Technically we didn't actually execute a QI on the target interface, but
     // for logging purposes we would like to record the fact that this interface
     // was requested.
     InterceptorLog::QI(S_OK, mTarget.get(), aIid, interfaceForQILog);
 
-    return unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
+    HRESULT hr = unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
+    ENSURE_HR_SUCCEEDED(hr);
+    return hr;
   }
 
   // (2) Obtain a new target interface.
 
   // (2a) First, make sure that the target interface is available
   // NB: We *MUST* query the correct interface! ICallEvents::Invoke casts its
   // pvReceiver argument directly to the required interface! DO NOT assume
   // that COM will use QI or upcast/downcast!
   HRESULT hr;
 
   STAUniquePtr<IUnknown> targetInterface;
   IUnknown* rawTargetInterface = nullptr;
   hr = QueryInterfaceTarget(interceptorIid, (void**)&rawTargetInterface);
   targetInterface.reset(rawTargetInterface);
   InterceptorLog::QI(hr, mTarget.get(), aIid, targetInterface.get());
   MOZ_ASSERT(SUCCEEDED(hr) || hr == E_NOINTERFACE);
-  if (FAILED(hr)) {
+  if (hr == E_NOINTERFACE) {
     return hr;
   }
+  ENSURE_HR_SUCCEEDED(hr);
 
   // We *really* shouldn't be adding interceptors to proxies
   MOZ_ASSERT(aIid != IID_IMarshal);
 
   // (3) Create a new COM interceptor to that interface that delegates its
   // IUnknown to |this|.
 
   // Raise the refcount for stabilization purposes during aggregation
   RefPtr<IUnknown> kungFuDeathGrip(static_cast<IUnknown*>(
         static_cast<WeakReferenceSupport*>(this)));
 
   hr = CreateInterceptor(interceptorIid, kungFuDeathGrip,
                          getter_AddRefs(unkInterceptor));
-  if (FAILED(hr)) {
-    return hr;
-  }
+  ENSURE_HR_SUCCEEDED(hr);
 
   // (4) Obtain the interceptor's ICallInterceptor interface and register our
   // event sink.
   RefPtr<ICallInterceptor> interceptor;
   hr = unkInterceptor->QueryInterface(IID_ICallInterceptor,
                                       (void**)getter_AddRefs(interceptor));
-  if (FAILED(hr)) {
-    return hr;
-  }
+  ENSURE_HR_SUCCEEDED(hr);
 
   hr = interceptor->RegisterSink(mEventSink);
-  if (FAILED(hr)) {
-    return hr;
-  }
+  ENSURE_HR_SUCCEEDED(hr);
 
   // (5) Now that we have this new COM interceptor, insert it into the map.
 
   { // Scope for lock
     MutexAutoLock lock(mMutex);
     // We might have raced with another thread, so first check that we don't
     // already have an entry for this
     MapEntry* entry = Lookup(interceptorIid);
@@ -571,17 +587,19 @@ Interceptor::GetInterceptorForIID(REFIID
       // the map and its refcounting might not be thread-safe.
       IUnknown* rawTargetInterface = targetInterface.release();
       mInterceptorMap.AppendElement(MapEntry(interceptorIid,
                                              unkInterceptor,
                                              rawTargetInterface));
     }
   }
 
-  return unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
+  hr = unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
+  ENSURE_HR_SUCCEEDED(hr);
+  return hr;
 }
 
 HRESULT
 Interceptor::QueryInterfaceTarget(REFIID aIid, void** aOutput)
 {
   // NB: This QI needs to run on the main thread because the target object
   // is probably Gecko code that is not thread-safe. Note that this main
   // thread invocation is *synchronous*.
@@ -633,26 +651,22 @@ Interceptor::ThreadSafeQueryInterface(RE
       if (XRE_IsContentProcess()) {
         hr = FastMarshaler::Create(static_cast<IWeakReferenceSource*>(this),
                                    getter_AddRefs(mStdMarshalUnk));
       } else {
         hr = ::CoGetStdMarshalEx(static_cast<IWeakReferenceSource*>(this),
                                  SMEXF_SERVER, getter_AddRefs(mStdMarshalUnk));
       }
 
-      if (FAILED(hr)) {
-        return hr;
-      }
+      ENSURE_HR_SUCCEEDED(hr);
     }
 
     if (!mStdMarshal) {
       hr = mStdMarshalUnk->QueryInterface(IID_IMarshal, (void**)&mStdMarshal);
-      if (FAILED(hr)) {
-        return hr;
-      }
+      ENSURE_HR_SUCCEEDED(hr);
 
       // mStdMarshal is weak, so drop its refcount
       mStdMarshal->Release();
     }
 
     RefPtr<IMarshal> marshal(this);
     marshal.forget(aOutInterface);
     return S_OK;
@@ -663,19 +677,18 @@ Interceptor::ThreadSafeQueryInterface(RE
     intcpt.forget(aOutInterface);
     return S_OK;
   }
 
   if (aIid == IID_IDispatch) {
     STAUniquePtr<IDispatch> disp;
     IDispatch* rawDisp = nullptr;
     HRESULT hr = QueryInterfaceTarget(aIid, (void**)&rawDisp);
-    if (FAILED(hr)) {
-      return hr;
-    }
+    ENSURE_HR_SUCCEEDED(hr);
+
     disp.reset(rawDisp);
     return DispatchForwarder::Create(this, disp, aOutInterface);
   }
 
   return GetInterceptorForIID(aIid, (void**)aOutInterface);
 }
 
 ULONG
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -683,17 +683,17 @@ struct ZoneStats
 
     ~ZoneStats() {
         // |allStrings| is usually deleted and set to nullptr before this
         // destructor runs. But there are failure cases due to OOMs that may
         // prevent that, so it doesn't hurt to try again here.
         js_delete(allStrings);
     }
 
-    bool initStrings(JSRuntime* rt);
+    bool initStrings();
 
     void addSizes(const ZoneStats& other) {
         MOZ_ASSERT(isTotals);
         FOR_EACH_SIZE(ADD_OTHER_SIZE)
         unusedGCThings.addSizes(other.unusedGCThings);
         stringInfo.add(other.stringInfo);
         shapeInfo.add(other.shapeInfo);
     }
@@ -803,17 +803,17 @@ struct CompartmentStats
 
     ~CompartmentStats() {
         // |allClasses| is usually deleted and set to nullptr before this
         // destructor runs. But there are failure cases due to OOMs that may
         // prevent that, so it doesn't hurt to try again here.
         js_delete(allClasses);
     }
 
-    bool initClasses(JSRuntime* rt);
+    bool initClasses();
 
     void addSizes(const CompartmentStats& other) {
         MOZ_ASSERT(isTotals);
         FOR_EACH_SIZE(ADD_OTHER_SIZE)
         classInfo.add(other.classInfo);
     }
 
     size_t sizeOfLiveGCThings() const {
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -241,17 +241,17 @@ function getDuplicateVariantRE() {
     //               / (DIGIT 3alphanum)
     var variant = "(?:" + alphanum + "{5,8}|(?:" + DIGIT + alphanum + "{3}))";
 
     // Match a langtag that contains a duplicate variant.
     var duplicateVariant =
         // Match everything in a langtag prior to any variants, and maybe some
         // of the variants as well (which makes this pattern inefficient but
         // not wrong, for our purposes);
-        "(?:" + alphanum + "{2,8}-)+" +
+        "^(?:" + alphanum + "{2,8}-)+" +
         // a variant, parenthesised so that we can refer back to it later;
         "(" + variant + ")-" +
         // zero or more subtags at least two characters long (thus stopping
         // before extension and privateuse components);
         "(?:" + alphanum + "{2,8}-)*" +
         // and the same variant again
         "\\1" +
         // ...but not followed by any characters that would turn it into a
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -630,17 +630,17 @@ MapObject::set(JSContext* cx, HandleObje
     }
 
     return true;
 }
 
 MapObject*
 MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
 {
-    auto map = cx->make_unique<ValueMap>(cx->runtime(),
+    auto map = cx->make_unique<ValueMap>(cx->zone(),
                                          cx->compartment()->randomHashCodeScrambler());
     if (!map || !map->init()) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     MapObject* mapObj = NewObjectWithClassProto<MapObject>(cx,  proto);
     if (!mapObj)
@@ -1313,17 +1313,17 @@ SetObject::add(JSContext* cx, HandleObje
         return false;
     }
     return true;
 }
 
 SetObject*
 SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
 {
-    auto set = cx->make_unique<ValueSet>(cx->runtime(),
+    auto set = cx->make_unique<ValueSet>(cx->zone(),
                                          cx->compartment()->randomHashCodeScrambler());
     if (!set || !set->init()) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     SetObject* obj = NewObjectWithClassProto<SetObject>(cx, proto);
     if (!obj)
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -76,21 +76,21 @@ template <class Key, class Value, class 
 class OrderedHashMap;
 
 template <class T, class OrderedHashPolicy, class AllocPolicy>
 class OrderedHashSet;
 
 typedef OrderedHashMap<HashableValue,
                        HeapPtr<Value>,
                        HashableValue::Hasher,
-                       RuntimeAllocPolicy> ValueMap;
+                       ZoneAllocPolicy> ValueMap;
 
 typedef OrderedHashSet<HashableValue,
                        HashableValue::Hasher,
-                       RuntimeAllocPolicy> ValueSet;
+                       ZoneAllocPolicy> ValueSet;
 
 template <typename ObjectT>
 class OrderedHashTableRef;
 
 struct UnbarrieredHashPolicy;
 
 class MapObject : public NativeObject {
   public:
@@ -125,17 +125,17 @@ class MapObject : public NativeObject {
     // Set call for public JSAPI exposure. Does not actually return map object
     // as stated in spec, expects caller to return a value. for instance, with
     // webidl maplike/setlike, should return interface object.
     static MOZ_MUST_USE bool set(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val);
     static MOZ_MUST_USE bool clear(JSContext *cx, HandleObject obj);
     static MOZ_MUST_USE bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj,
                                       MutableHandleValue iter);
 
-    using UnbarrieredTable = OrderedHashMap<Value, Value, UnbarrieredHashPolicy, RuntimeAllocPolicy>;
+    using UnbarrieredTable = OrderedHashMap<Value, Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
     friend class OrderedHashTableRef<MapObject>;
 
     static void sweepAfterMinorGC(FreeOp* fop, MapObject* mapobj);
 
   private:
     static const ClassSpec classSpec_;
     static const ClassOps classOps_;
 
@@ -229,17 +229,17 @@ class SetObject : public NativeObject {
     static SetObject* create(JSContext *cx, HandleObject proto = nullptr);
     static uint32_t size(JSContext *cx, HandleObject obj);
     static MOZ_MUST_USE bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
     static MOZ_MUST_USE bool clear(JSContext *cx, HandleObject obj);
     static MOZ_MUST_USE bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj,
                                       MutableHandleValue iter);
     static MOZ_MUST_USE bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval);
 
-    using UnbarrieredTable = OrderedHashSet<Value, UnbarrieredHashPolicy, RuntimeAllocPolicy>;
+    using UnbarrieredTable = OrderedHashSet<Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
     friend class OrderedHashTableRef<SetObject>;
 
     static void sweepAfterMinorGC(FreeOp* fop, SetObject* setobj);
 
   private:
     static const ClassSpec classSpec_;
     static const ClassOps classOps_;
 
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -6,17 +6,16 @@
 
 #ifndef builtin_ModuleObject_h
 #define builtin_ModuleObject_h
 
 #include "jsapi.h"
 #include "jsatom.h"
 
 #include "builtin/SelfHostingDefines.h"
-#include "gc/Zone.h"
 #include "js/GCVector.h"
 #include "js/Id.h"
 #include "vm/NativeObject.h"
 #include "vm/ProxyObject.h"
 
 namespace js {
 
 class ModuleEnvironmentObject;
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -3051,17 +3051,17 @@ BlockOnPromise(JSContext* cx, HandleValu
     if (promiseObj && promiseObj->is<PromiseObject>() && IsNativeFunction(thenVal, Promise_then)) {
         // |promise| is an unwrapped Promise, and |then| is the original
         // |Promise.prototype.then|, inline it here.
         // 25.4.5.3., step 3.
         RootedObject PromiseCtor(cx);
         if (!GetBuiltinConstructor(cx, JSProto_Promise, &PromiseCtor))
             return false;
 
-        RootedObject C(cx, SpeciesConstructor(cx, PromiseCtor, JSProto_Promise, IsPromiseSpecies));
+        RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
         if (!C)
             return false;
 
         RootedObject resultPromise(cx, blockedPromise_);
         RootedObject resolveFun(cx);
         RootedObject rejectFun(cx);
 
         // By default, the blocked promise is added as an extra entry to the
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -9785,18 +9785,16 @@ BytecodeEmitter::emitIncOrDec(ParseNode*
         return emitPropIncDec(pn);
       case PNK_ELEM:
         return emitElemIncDec(pn);
       case PNK_CALL:
         return emitCallIncDec(pn);
       default:
         return emitNameIncDec(pn);
     }
-
-    return true;
 }
 
 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
 // the comment on emitSwitch.
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn)
 {
     /*
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1657,16 +1657,28 @@ ObjectDenseElementsMayBeMarkable(NativeO
         for (unsigned i = 0; i < nobj->getDenseInitializedLength(); i++)
             MOZ_ASSERT(!elements[i].isGCThing());
     }
 #endif
 
     return mayBeMarkable;
 }
 
+static inline void
+CheckForCompartmentMismatch(JSObject* obj, JSObject* obj2)
+{
+#ifdef DEBUG
+    if (MOZ_UNLIKELY(obj->compartment() != obj2->compartment())) {
+        fprintf(stderr, "Compartment mismatch in pointer from %s object slot to %s object\n",
+                obj->getClass()->name, obj2->getClass()->name);
+        MOZ_CRASH("Compartment mismatch");
+    }
+#endif
+}
+
 inline void
 GCMarker::processMarkStackTop(SliceBudget& budget)
 {
     /*
      * The function uses explicit goto and implements the scanning of the
      * object directly. It allows to eliminate the tail recursion and
      * significantly improve the marking performance, see bug 641025.
      */
@@ -1727,17 +1739,17 @@ GCMarker::processMarkStackTop(SliceBudge
             return;
         }
 
         const Value& v = *vp++;
         if (v.isString()) {
             traverseEdge(obj, v.toString());
         } else if (v.isObject()) {
             JSObject* obj2 = &v.toObject();
-            MOZ_ASSERT(obj->compartment() == obj2->compartment());
+            CheckForCompartmentMismatch(obj, obj2);
             if (mark(obj2)) {
                 // Save the rest of this value array for later and start scanning obj2's children.
                 pushValueArray(obj, vp, end);
                 obj = obj2;
                 goto scan_obj;
             }
         } else if (v.isSymbol()) {
             traverseEdge(obj, v.toSymbol());
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -453,16 +453,17 @@ class HeapCheckTracerBase : public JS::C
 {
   public:
     explicit HeapCheckTracerBase(JSRuntime* rt, WeakMapTraceKind weakTraceKind);
     bool init();
     bool traceHeap(AutoLockForExclusiveAccess& lock);
     virtual void checkCell(Cell* cell) = 0;
 
   protected:
+    void dumpCellInfo(Cell* cell);
     void dumpCellPath();
 
     Cell* parentCell() {
         return parentIndex == -1 ? nullptr : stack[parentIndex].thing.asCell();
     }
 
     size_t failures;
 
@@ -551,24 +552,35 @@ HeapCheckTracerBase::traceHeap(AutoLockF
             TraceChildren(this, item.thing);
         }
     }
 
     return !oom;
 }
 
 void
+HeapCheckTracerBase::dumpCellInfo(Cell* cell)
+{
+    auto kind = cell->getTraceKind();
+    fprintf(stderr, "%s", GCTraceKindToAscii(kind));
+    if (kind == JS::TraceKind::Object)
+        fprintf(stderr, " %s", static_cast<JSObject*>(cell)->getClass()->name);
+    fprintf(stderr, " %p", cell);
+}
+
+void
 HeapCheckTracerBase::dumpCellPath()
 {
     const char* name = contextName();
     for (int index = parentIndex; index != -1; index = stack[index].parentIndex) {
         const WorkItem& parent = stack[index];
         Cell* cell = parent.thing.asCell();
-        fprintf(stderr, "  from %s %p %s edge\n",
-                GCTraceKindToAscii(cell->getTraceKind()), cell, name);
+        fprintf(stderr, "  from ");
+        dumpCellInfo(cell);
+        fprintf(stderr, " %s edge\n", name);
         name = parent.name;
     }
     fprintf(stderr, "  from root %s\n", name);
 }
 
 #endif // defined(JSGC_HASH_TABLE_CHECKS) || defined(DEBUG)
 
 #ifdef JSGC_HASH_TABLE_CHECKS
@@ -643,26 +655,24 @@ CheckGrayMarkingTracer::CheckGrayMarking
     // Weak gray->black edges are allowed.
     setTraceWeakEdges(false);
 }
 
 void
 CheckGrayMarkingTracer::checkCell(Cell* cell)
 {
     Cell* parent = parentCell();
-    if (!cell->isTenured() || !parent || !parent->isTenured())
+    if (!parent)
         return;
 
-    TenuredCell* tenuredCell = &cell->asTenured();
-    TenuredCell* tenuredParent = &parent->asTenured();
-    if (tenuredParent->isMarkedBlack() && tenuredCell->isMarkedGray())
-    {
+    if (parent->isMarkedBlack() && cell->isMarkedGray()) {
         failures++;
-        fprintf(stderr, "Found black to gray edge to %s %p\n",
-                GCTraceKindToAscii(cell->getTraceKind()), cell);
+        fprintf(stderr, "Found black to gray edge to ");
+        dumpCellInfo(cell);
+        fprintf(stderr, "\n");
         dumpCellPath();
     }
 }
 
 bool
 CheckGrayMarkingTracer::check(AutoLockForExclusiveAccess& lock)
 {
     if (!traceHeap(lock))
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -99,18 +99,16 @@ Zone::init(bool isSystemArg)
            markedAtoms().init() &&
            atomCache().init() &&
            regExps.init();
 }
 
 void
 Zone::setNeedsIncrementalBarrier(bool needs)
 {
-    MOZ_ASSERT_IF(needs && isAtomsZone(),
-                  !runtimeFromActiveCooperatingThread()->hasHelperThreadZones());
     MOZ_ASSERT_IF(needs, canCollect());
     needsIncrementalBarrier_ = needs;
 }
 
 void
 Zone::beginSweepTypes(FreeOp* fop, bool releaseTypes)
 {
     AutoClearTypeInferenceStateOnOOM oom(this);
@@ -293,25 +291,24 @@ Zone::hasMarkedCompartments()
             return true;
     }
     return false;
 }
 
 bool
 Zone::canCollect()
 {
+    // The atoms zone cannot be collected while off-thread parsing is taking
+    // place.
+    if (isAtomsZone())
+        return !runtimeFromAnyThread()->hasHelperThreadZones();
+
     // Zones that will be or are currently used by other threads cannot be
     // collected.
-    if (!isAtomsZone() && group()->createdForHelperThread())
-        return false;
-
-    JSRuntime* rt = runtimeFromAnyThread();
-    if (isAtomsZone() && rt->hasHelperThreadZones())
-        return false;
-    return true;
+    return !group()->createdForHelperThread();
 }
 
 void
 Zone::notifyObservingDebuggers()
 {
     for (CompartmentsInZoneIter comps(this); !comps.done(); comps.next()) {
         JSRuntime* rt = runtimeFromAnyThread();
         RootedGlobalObject global(TlsContext.get(), comps->unsafeUnbarrieredMaybeGlobal());
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -247,17 +247,17 @@ struct Zone : public JS::shadow::Zone,
     void changeGCState(GCState prev, GCState next) {
         MOZ_ASSERT(CurrentThreadIsHeapBusy());
         MOZ_ASSERT(gcState() == prev);
         MOZ_ASSERT_IF(next != NoGC, canCollect());
         gcState_ = next;
     }
 
     bool isCollecting() const {
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
         return isCollectingFromAnyThread();
     }
 
     bool isCollectingFromAnyThread() const {
         if (CurrentThreadIsHeapCollecting())
             return gcState_ != NoGC;
         else
             return needsIncrementalBarrier();
@@ -430,17 +430,17 @@ struct Zone : public JS::shadow::Zone,
 
     JS::WeakCache<TypeDescrObjectSet>& typeDescrObjects() { return typeDescrObjects_.ref(); }
 
     bool addTypeDescrObject(JSContext* cx, HandleObject obj);
 
     bool triggerGCForTooMuchMalloc() {
         JSRuntime* rt = runtimeFromAnyThread();
 
-        if (CurrentThreadCanAccessRuntime(rt)) {
+        if (js::CurrentThreadCanAccessRuntime(rt)) {
             return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
                                         gcMallocCounter.bytes(), gcMallocCounter.maxBytes());
         }
         return false;
     }
 
     void resetGCMallocBytes() { gcMallocCounter.reset(); }
     void setGCMaxMallocBytes(size_t value) { gcMallocCounter.setMax(value); }
@@ -615,17 +615,17 @@ struct Zone : public JS::shadow::Zone,
         return uniqueIds().has(cell);
     }
 
     // Transfer an id from another cell. This must only be called on behalf of a
     // moving GC. This method is infallible.
     void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src) {
         MOZ_ASSERT(src != tgt);
         MOZ_ASSERT(!IsInsideNursery(tgt));
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
         MOZ_ASSERT(!uniqueIds().has(tgt));
         uniqueIds().rekeyIfMoved(src, tgt);
     }
 
     // Remove any unique id associated with this Cell.
     void removeUniqueId(js::gc::Cell* cell) {
         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
@@ -654,16 +654,38 @@ struct Zone : public JS::shadow::Zone,
     }
     void setKeepShapeTables(bool b) {
         keepShapeTables_ = b;
     }
 
     // Delete an empty compartment after its contents have been merged.
     void deleteEmptyCompartment(JSCompartment* comp);
 
+    /*
+     * This variation of calloc will call the large-allocation-failure callback
+     * on OOM and retry the allocation.
+     */
+    template <typename T>
+    T* pod_callocCanGC(size_t numElems) {
+        T* p = pod_calloc<T>(numElems);
+        if (MOZ_LIKELY(!!p))
+            return p;
+        size_t bytes;
+        if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
+            reportAllocationOverflow();
+            return nullptr;
+        }
+        JSRuntime* rt = runtimeFromActiveCooperatingThread();
+        p = static_cast<T*>(rt->onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
+        if (!p)
+            return nullptr;
+        updateMallocCounter(bytes);
+        return p;
+    }
+
   private:
     js::ZoneGroupData<js::jit::JitZone*> jitZone_;
 
     js::ActiveThreadData<bool> gcScheduled_;
     js::ZoneGroupData<bool> gcPreserveCode_;
     js::ZoneGroupData<bool> keepShapeTables_;
 
     // Allow zones to be linked into a list
@@ -689,27 +711,27 @@ class ZoneGroupsIter
     ZoneGroup** it;
     ZoneGroup** end;
 
   public:
     explicit ZoneGroupsIter(JSRuntime* rt) : iterMarker(&rt->gc) {
         it = rt->gc.groups().begin();
         end = rt->gc.groups().end();
 
-        if (!done() && (*it)->createdForHelperThread())
+        if (!done() && (*it)->usedByHelperThread())
             next();
     }
 
     bool done() const { return it == end; }
 
     void next() {
         MOZ_ASSERT(!done());
         do {
             it++;
-        } while (!done() && (*it)->createdForHelperThread());
+        } while (!done() && (*it)->usedByHelperThread());
     }
 
     ZoneGroup* get() const {
         MOZ_ASSERT(!done());
         return *it;
     }
 
     operator ZoneGroup*() const { return get(); }
@@ -887,71 +909,57 @@ class CompartmentsIterT
     }
 
     operator JSCompartment*() const { return get(); }
     JSCompartment* operator->() const { return get(); }
 };
 
 typedef CompartmentsIterT<ZonesIter> CompartmentsIter;
 
-/*
- * Allocation policy that uses Zone::pod_malloc and friends, so that memory
- * pressure is accounted for on the zone. This is suitable for memory associated
- * with GC things allocated in the zone.
- *
- * Since it doesn't hold a JSContext (those may not live long enough), it can't
- * report out-of-memory conditions itself; the caller must check for OOM and
- * take the appropriate action.
- *
- * FIXME bug 647103 - replace these *AllocPolicy names.
- */
-class ZoneAllocPolicy
+template <typename T>
+inline T*
+ZoneAllocPolicy::maybe_pod_malloc(size_t numElems)
 {
-    Zone* const zone;
-
-  public:
-    MOZ_IMPLICIT ZoneAllocPolicy(Zone* zone) : zone(zone) {}
+    return zone->maybe_pod_malloc<T>(numElems);
+}
 
-    template <typename T>
-    T* maybe_pod_malloc(size_t numElems) {
-        return zone->maybe_pod_malloc<T>(numElems);
-    }
+template <typename T>
+inline T*
+ZoneAllocPolicy::maybe_pod_calloc(size_t numElems)
+{
+    return zone->maybe_pod_calloc<T>(numElems);
+}
 
-    template <typename T>
-    T* maybe_pod_calloc(size_t numElems) {
-        return zone->maybe_pod_calloc<T>(numElems);
-    }
+template <typename T>
+inline T*
+ZoneAllocPolicy::maybe_pod_realloc(T* p, size_t oldSize, size_t newSize)
+{
+    return zone->maybe_pod_realloc<T>(p, oldSize, newSize);
+}
 
-    template <typename T>
-    T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
-        return zone->maybe_pod_realloc<T>(p, oldSize, newSize);
-    }
-
-    template <typename T>
-    T* pod_malloc(size_t numElems) {
-        return zone->pod_malloc<T>(numElems);
-    }
+template <typename T>
+inline T*
+ZoneAllocPolicy::pod_malloc(size_t numElems)
+{
+    return zone->pod_malloc<T>(numElems);
+}
 
-    template <typename T>
-    T* pod_calloc(size_t numElems) {
-        return zone->pod_calloc<T>(numElems);
-    }
+template <typename T>
+inline T*
+ZoneAllocPolicy::pod_calloc(size_t numElems)
+{
+    return zone->pod_calloc<T>(numElems);
+}
 
-    template <typename T>
-    T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
-        return zone->pod_realloc<T>(p, oldSize, newSize);
-    }
-
-    void free_(void* p) { js_free(p); }
-    void reportAllocOverflow() const {}
-
-    MOZ_MUST_USE bool checkSimulatedOOM() const {
-        return !js::oom::ShouldFailWithOOM();
-    }
-};
+template <typename T>
+inline T*
+ZoneAllocPolicy::pod_realloc(T* p, size_t oldSize, size_t newSize)
+{
+    return zone->pod_realloc<T>(p, oldSize, newSize);
+}
 
 /*
  * Provides a delete policy that can be used for objects which have their
  * lifetime managed by the GC so they can be safely destroyed outside of GC.
  *
  * This is necessary for example when initializing such an object may fail after
  * the initial allocation. The partially-initialized object must be destroyed,
  * but it may not be safe to do so at the current time as the store buffer may
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1401141.js
@@ -0,0 +1,13 @@
+if (!('gczeal' in this))
+    quit();
+if (helperThreadCount() == 0)
+    quit();
+
+gczeal(15,1);
+setGCCallback({
+  action: "majorGC",
+});
+gcslice(3);
+var lfGlobal = newGlobal();
+lfGlobal.offThreadCompileScript("");
+
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -24,18 +24,16 @@
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsInRange;
 
 uint32_t
 jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
 {
-    AutoUnsafeCallWithABI unsafe;
-
     JSContext* cx = TlsContext.get();
     MOZ_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_EXITFP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_EXITFP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
                "Fake exitfp pointer should be within the first page.");
 
@@ -101,18 +99,16 @@ jit::Bailout(BailoutStack* sp, BaselineB
 
     return retval;
 }
 
 uint32_t
 jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
                          BaselineBailoutInfo** bailoutInfo)
 {
-    AutoUnsafeCallWithABI unsafe;
-
     sp->checkInvariants();
 
     JSContext* cx = TlsContext.get();
 
     // We don't have an exit frame.
     cx->activation()->asJit()->setExitFP(FAKE_EXITFP_FOR_BAILOUT);
 
     JitActivationIterator jitActivations(cx);
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -535,20 +535,18 @@ BaselineInspector::hasSeenDoubleResult(j
 
     const ICEntry& entry = icEntryFromPC(pc);
     ICStub* stub = entry.fallbackStub();
 
     MOZ_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
 
     if (stub->isUnaryArith_Fallback())
         return stub->toUnaryArith_Fallback()->sawDoubleResult();
-    else
-        return stub->toBinaryArith_Fallback()->sawDoubleResult();
 
-    return false;
+    return stub->toBinaryArith_Fallback()->sawDoubleResult();
 }
 
 JSObject*
 BaselineInspector::getTemplateObject(jsbytecode* pc)
 {
     if (!hasBaselineScript())
         return nullptr;
 
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -1675,17 +1675,17 @@ static bool
 CanAttachDenseElementHole(JSObject* obj, bool ownProp)
 {
     // Make sure the objects on the prototype don't have any indexed properties
     // or that such properties can't appear without a shape change.
     // Otherwise returning undefined for holes would obviously be incorrect,
     // because we would have to lookup a property on the prototype instead.
     do {
         // The first two checks are also relevant to the receiver object.
-        if (obj->isIndexed())
+        if (obj->isNative() && obj->as<NativeObject>().isIndexed())
             return false;
 
         if (ClassCanHaveExtraProperties(obj->getClass()))
             return false;
 
         // Don't need to check prototype for OwnProperty checks
         if (ownProp)
             return true;
@@ -3144,17 +3144,17 @@ SetPropIRGenerator::tryAttachSetDenseEle
 
 static bool
 CanAttachAddElement(JSObject* obj, bool isInit)
 {
     // Make sure the objects on the prototype don't have any indexed properties
     // or that such properties can't appear without a shape change.
     do {
         // The first two checks are also relevant to the receiver object.
-        if (obj->isIndexed())
+        if (obj->isNative() && obj->as<NativeObject>().isIndexed())
             return false;
 
         const Class* clasp = obj->getClass();
         if ((clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) &&
             (clasp->getAddProperty() ||
              clasp->getResolve() ||
              clasp->getOpsLookupProperty() ||
              clasp->getOpsSetProperty()))
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7907,38 +7907,38 @@ JitCompartment::generateStringConcatStub
 #ifdef MOZ_VTUNE
     vtune::MarkStub(code, "StringConcatStub");
 #endif
 
     return code;
 }
 
 JitCode*
-JitRuntime::generateMallocStub(JSContext* cx)
+JitZone::generateMallocStub(JSContext* cx)
 {
     const Register regReturn = CallTempReg0;
     const Register regNBytes = CallTempReg0;
 
     MacroAssembler masm(cx);
 
     AllocatableRegisterSet regs(RegisterSet::Volatile());
 #ifdef JS_USE_LINK_REGISTER
     masm.pushReturnAddress();
 #endif
     regs.takeUnchecked(regNBytes);
     LiveRegisterSet save(regs.asLiveSet());
     masm.PushRegsInMask(save);
 
     const Register regTemp = regs.takeAnyGeneral();
-    const Register regRuntime = regTemp;
+    const Register regZone = regTemp;
     MOZ_ASSERT(regTemp != regNBytes);
 
     masm.setupUnalignedABICall(regTemp);
-    masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
-    masm.passABIArg(regRuntime);
+    masm.movePtr(ImmPtr(cx->zone()), regZone);
+    masm.passABIArg(regZone);
     masm.passABIArg(regNBytes);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MallocWrapper));
     masm.storeCallWordResult(regReturn);
 
     masm.PopRegsInMask(save);
     masm.ret();
 
     Linker linker(masm);
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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/Ion.h"
 
+#include "jit/JitCompartment.h"
+
 #include "jscompartmentinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
 JSRuntime*
 CompileRuntime::runtime()
 {
@@ -136,16 +138,22 @@ CompileZone::get(Zone* zone)
 }
 
 CompileRuntime*
 CompileZone::runtime()
 {
     return CompileRuntime::get(zone()->runtimeFromAnyThread());
 }
 
+JitCode*
+CompileZone::mallocStub()
+{
+    return zone()->jitZone()->mallocStub();
+}
+
 bool
 CompileZone::isAtomsZone()
 {
     return zone()->isAtomsZone();
 }
 
 #ifdef DEBUG
 const void*
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -63,16 +63,18 @@ class CompileZone
     Zone* zone();
 
   public:
     static CompileZone* get(Zone* zone);
 
     CompileRuntime* runtime();
     bool isAtomsZone();
 
+    JitCode* mallocStub();
+
 #ifdef DEBUG
     const void* addressOfIonBailAfter();
 #endif
 
     const void* addressOfJSContext();
     const void* addressOfNeedsIncrementalBarrier();
     const void* addressOfFreeList(gc::AllocKind allocKind);
     const void* addressOfNurseryPosition();
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -315,21 +315,16 @@ JitRuntime::initialize(JSContext* cx, Au
     if (!shapePreBarrier_)
         return false;
 
     JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for ObjectGroup");
     objectGroupPreBarrier_ = generatePreBarrier(cx, MIRType::ObjectGroup);
     if (!objectGroupPreBarrier_)
         return false;
 
-    JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
-    mallocStub_ = generateMallocStub(cx);
-    if (!mallocStub_)
-        return false;
-
     JitSpew(JitSpew_Codegen, "# Emitting free stub");
     freeStub_ = generateFreeStub(cx);
     if (!freeStub_)
         return false;
 
     JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
     for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
         JitSpew(JitSpew_Codegen, "# VM function wrapper");
@@ -433,17 +428,17 @@ JitCompartment::JitCompartment()
 JitCompartment::~JitCompartment()
 {
     js_delete(stubCodes_);
 }
 
 bool
 JitCompartment::initialize(JSContext* cx)
 {
-    stubCodes_ = cx->new_<ICStubCodeMap>(cx->runtime());
+    stubCodes_ = cx->new_<ICStubCodeMap>(cx->zone());
     if (!stubCodes_)
         return false;
 
     if (!stubCodes_->init()) {
         ReportOutOfMemory(cx);
         return false;
     }
 
@@ -465,16 +460,23 @@ JitCompartment::ensureIonStubsExist(JSCo
 bool
 JitZone::init(JSContext* cx)
 {
     if (!baselineCacheIRStubCodes_.init()) {
         ReportOutOfMemory(cx);
         return false;
     }
 
+    JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
+    mallocStub_ = generateMallocStub(cx);
+    if (!mallocStub_) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+
     return true;
 }
 
 void
 jit::FreeIonBuilder(IonBuilder* builder)
 {
     // The builder is allocated into its LifoAlloc, so destroying that will
     // destroy the builder and all other data accumulated during compilation,
--- a/js/src/jit/IonControlFlow.cpp
+++ b/js/src/jit/IonControlFlow.cpp
@@ -250,18 +250,16 @@ ControlFlowGenerator::traverseBytecode()
             }
             if (!current)
                 return true;
         }
 
         JSOp op = JSOp(*pc);
         pc += CodeSpec[op].length;
     }
-
-    return true;
 }
 
 ControlFlowGenerator::ControlStatus
 ControlFlowGenerator::snoopControlFlow(JSOp op)
 {
     switch (op) {
       case JSOP_POP:
       case JSOP_NOP: {
--- a/js/src/jit/JSJitFrameIter.cpp
+++ b/js/src/jit/JSJitFrameIter.cpp
@@ -20,16 +20,18 @@ JSJitFrameIter::JSJitFrameIter(const Jit
     frameSize_(0),
     cachedSafepointIndex_(nullptr),
     activation_(activation)
 {
     if (activation_->bailoutData()) {
         current_ = activation_->bailoutData()->fp();
         frameSize_ = activation_->bailoutData()->topFrameSize();
         type_ = JitFrame_Bailout;
+    } else {
+        MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
     }
 }
 
 JSJitFrameIter::JSJitFrameIter(JSContext* cx)
   : JSJitFrameIter(cx->activation()->asJit())
 {
 }
 
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -124,18 +124,17 @@ class JitRuntime
 
     // Thunk that calls the GC pre barrier.
     ExclusiveAccessLockWriteOnceData<JitCode*> valuePreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> stringPreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> objectPreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> shapePreBarrier_;
     ExclusiveAccessLockWriteOnceData<JitCode*> objectGroupPreBarrier_;
 
-    // Thunk to call malloc/free.
-    ExclusiveAccessLockWriteOnceData<JitCode*> mallocStub_;
+    // Thunk to call free.
     ExclusiveAccessLockWriteOnceData<JitCode*> freeStub_;
 
     // Thunk called to finish compilation of an IonScript.
     ExclusiveAccessLockWriteOnceData<JitCode*> lazyLinkStub_;
 
     // Thunk used by the debugger for breakpoint and step mode.
     ExclusiveAccessLockWriteOnceData<JitCode*> debugTrapHandler_;
 
@@ -160,17 +159,16 @@ class JitRuntime
     JitCode* generateExceptionTailStub(JSContext* cx, void* handler);
     JitCode* generateBailoutTailStub(JSContext* cx);
     JitCode* generateEnterJIT(JSContext* cx, EnterJitType type);
     JitCode* generateArgumentsRectifier(JSContext* cx, void** returnAddrOut);
     JitCode* generateBailoutTable(JSContext* cx, uint32_t frameClass);
     JitCode* generateBailoutHandler(JSContext* cx);
     JitCode* generateInvalidator(JSContext* cx);
     JitCode* generatePreBarrier(JSContext* cx, MIRType type);
-    JitCode* generateMallocStub(JSContext* cx);
     JitCode* generateFreeStub(JSContext* cx);
     JitCode* generateDebugTrapHandler(JSContext* cx);
     JitCode* generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
     JitCode* generateVMWrapper(JSContext* cx, const VMFunction& f);
 
     bool generateTLEventVM(JSContext* cx, MacroAssembler& masm, const VMFunction& f, bool enter);
 
     inline bool generateTLEnterVM(JSContext* cx, MacroAssembler& masm, const VMFunction& f) {
@@ -281,20 +279,16 @@ class JitRuntime
           case MIRType::String: return stringPreBarrier_;
           case MIRType::Object: return objectPreBarrier_;
           case MIRType::Shape: return shapePreBarrier_;
           case MIRType::ObjectGroup: return objectGroupPreBarrier_;
           default: MOZ_CRASH();
         }
     }
 
-    JitCode* mallocStub() const {
-        return mallocStub_;
-    }
-
     JitCode* freeStub() const {
         return freeStub_;
     }
 
     JitCode* lazyLinkStub() const {
         return lazyLinkStub_;
     }
 
@@ -415,16 +409,19 @@ class JitZone
     // Map CacheIRStubKey to shared JitCode objects.
     using BaselineCacheIRStubCodeMap = GCHashMap<CacheIRStubKey,
                                                  ReadBarrieredJitCode,
                                                  CacheIRStubKey,
                                                  SystemAllocPolicy,
                                                  IcStubCodeMapGCPolicy<CacheIRStubKey>>;
     BaselineCacheIRStubCodeMap baselineCacheIRStubCodes_;
 
+    // Thunk to call malloc.
+    WriteOnceData<JitCode*> mallocStub_;
+
   public:
     MOZ_MUST_USE bool init(JSContext* cx);
     void sweep(FreeOp* fop);
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* jitZone,
                                 size_t* baselineStubsOptimized,
                                 size_t* cachedCFG) const;
@@ -468,16 +465,23 @@ class JitZone
             return false;
         IonCacheIRStubInfoSet::AddPtr p = ionCacheIRStubInfoSet_.lookupForAdd(lookup);
         MOZ_ASSERT(!p);
         return ionCacheIRStubInfoSet_.add(p, Move(key));
     }
     void purgeIonCacheIRStubInfo() {
         ionCacheIRStubInfoSet_.finish();
     }
+
+    JitCode* mallocStub() const {
+        return mallocStub_;
+    }
+
+  private:
+    JitCode* generateMallocStub(JSContext* cx);
 };
 
 enum class BailoutReturnStub {
     GetProp,
     GetPropSuper,
     SetProp,
     Call,
     New,
@@ -487,17 +491,17 @@ enum class BailoutReturnStub {
 class JitCompartment
 {
     friend class JitActivation;
 
     // Map ICStub keys to ICStub shared code objects.
     using ICStubCodeMap = GCHashMap<uint32_t,
                                     ReadBarrieredJitCode,
                                     DefaultHasher<uint32_t>,
-                                    RuntimeAllocPolicy,
+                                    ZoneAllocPolicy,
                                     IcStubCodeMapGCPolicy<uint32_t>>;
     ICStubCodeMap* stubCodes_;
 
     // Keep track of offset into various baseline stubs' code at return
     // point from called script.
     struct BailoutReturnStubInfo
     {
         void* addr;
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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/LIR.h"
 
+#include "mozilla/ScopeExit.h"
+
 #include <ctype.h>
 
 #include "jsprf.h"
 
 #include "jit/JitSpewer.h"
 #include "jit/MIR.h"
 #include "jit/MIRGenerator.h"
 
@@ -230,20 +232,28 @@ LRecoverInfo::appendOperands(Node* ins)
     return true;
 }
 
 bool
 LRecoverInfo::appendDefinition(MDefinition* def)
 {
     MOZ_ASSERT(def->isRecoveredOnBailout());
     def->setInWorklist();
+    auto clearWorklistFlagOnFailure = mozilla::MakeScopeExit([&] {
+        def->setNotInWorklist();
+    });
 
     if (!appendOperands(def))
         return false;
-    return instructions_.append(def);
+
+    if (!instructions_.append(def))
+        return false;
+
+    clearWorklistFlagOnFailure.release();
+    return true;
 }
 
 bool
 LRecoverInfo::appendResumePoint(MResumePoint* rp)
 {
     // Stores should be recovered first.
     for (auto iter(rp->storesBegin()), end(rp->storesEnd()); iter != end; ++iter) {
         if (!appendDefinition(iter->operand))
@@ -257,31 +267,33 @@ LRecoverInfo::appendResumePoint(MResumeP
         return false;
 
     return instructions_.append(rp);
 }
 
 bool
 LRecoverInfo::init(MResumePoint* rp)
 {
+    // Before exiting this function, remove temporary flags from all definitions
+    // added in the vector.
+    auto clearWorklistFlags = mozilla::MakeScopeExit([&] {
+        for (MNode** it = begin(); it != end(); it++) {
+            if (!(*it)->isDefinition())
+                continue;
+            (*it)->toDefinition()->setNotInWorklist();
+        }
+    });
+
     // Sort operations in the order in which we need to restore the stack. This
     // implies that outer frames, as well as operations needed to recover the
     // current frame, are located before the current frame. The inner-most
     // resume point should be the last element in the list.
     if (!appendResumePoint(rp))
         return false;
 
-    // Remove temporary flags from all definitions.
-    for (MNode** it = begin(); it != end(); it++) {
-        if (!(*it)->isDefinition())
-            continue;
-
-        (*it)->toDefinition()->setNotInWorklist();
-    }
-
     MOZ_ASSERT(mir() == rp);
     return true;
 }
 
 LSnapshot::LSnapshot(LRecoverInfo* recoverInfo, BailoutKind kind)
   : numSlots_(TotalOperandCount(recoverInfo) * BOX_PIECES),
     slots_(nullptr),
     recoverInfo_(recoverInfo),
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -847,17 +847,17 @@ MacroAssembler::callMallocStub(size_t nb
     const Register regNBytes = CallTempReg0;
 
     MOZ_ASSERT(nbytes > 0);
     MOZ_ASSERT(nbytes <= INT32_MAX);
 
     if (regNBytes != result)
         push(regNBytes);
     move32(Imm32(nbytes), regNBytes);
-    call(GetJitContext()->runtime->jitRuntime()->mallocStub());
+    call(GetJitContext()->compartment->zone()->mallocStub());
     if (regNBytes != result) {
         movePtr(regNBytes, result);
         pop(regNBytes);
     }
     branchTest32(Assembler::Zero, result, result, fail);
 }
 
 void
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -537,20 +537,20 @@ InterruptCheck(JSContext* cx)
         JitRuntime::AutoPreventBackedgePatching apbp(rt);
         cx->zone()->group()->jitZoneGroup->patchIonBackedges(cx, JitZoneGroup::BackedgeLoopHeader);
     }
 
     return CheckForInterrupt(cx);
 }
 
 void*
-MallocWrapper(JSRuntime* rt, size_t nbytes)
+MallocWrapper(JS::Zone* zone, size_t nbytes)
 {
     AutoUnsafeCallWithABI unsafe;
-    return rt->pod_malloc<uint8_t>(nbytes);
+    return zone->pod_malloc<uint8_t>(nbytes);
 }
 
 JSObject*
 NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group)
 {
     JSObject* obj = CallObject::create(cx, shape, group);
     if (!obj)
         return nullptr;
@@ -1232,17 +1232,16 @@ LeaveWith(JSContext* cx, BaselineFrame* 
     frame->popOffEnvironmentChain<WithEnvironmentObject>();
     return true;
 }
 
 bool
 InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
                         uint32_t numStackValues)
 {
-    AutoUnsafeCallWithABI unsafe;
     return frame->initForOsr(interpFrame, numStackValues);
 }
 
 JSObject*
 CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
                       HandleObject owner, int32_t offset)
 {
     MOZ_ASSERT(descr->is<TypeDescr>());
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -674,17 +674,17 @@ JSString* StringFromCodePoint(JSContext*
 
 MOZ_MUST_USE bool
 SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
             bool strict, jsbytecode* pc);
 
 MOZ_MUST_USE bool
 InterruptCheck(JSContext* cx);
 
-void* MallocWrapper(JSRuntime* rt, size_t nbytes);
+void* MallocWrapper(JS::Zone* zone, size_t nbytes);
 JSObject* NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group);
 JSObject* NewSingletonCallObject(JSContext* cx, HandleShape shape);
 JSObject* NewStringObject(JSContext* cx, HandleString str);
 
 bool OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out);
 bool OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out);
 
 MOZ_MUST_USE bool
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -292,17 +292,18 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         masm.push(framePtr); // BaselineFrame
         masm.push(r0); // jitcode
 
         masm.setupUnalignedABICall(scratch);
         masm.passABIArg(r11); // BaselineFrame
         masm.passABIArg(OsrFrameReg); // InterpreterFrame
         masm.passABIArg(numStackValues);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
         Register jitcode = regs.takeAny();
         masm.pop(jitcode);
         masm.pop(framePtr);
 
         MOZ_ASSERT(jitcode != ReturnReg);
 
         Label error;
@@ -429,17 +430,18 @@ JitRuntime::generateInvalidator(JSContex
     masm.mov(sp, r1);
     const int sizeOfBailoutInfo = sizeof(void*)*2;
     masm.reserveStack(sizeOfBailoutInfo);
     masm.mov(sp, r2);
     masm.setupAlignedABICall();
     masm.passABIArg(r0);
     masm.passABIArg(r1);
     masm.passABIArg(r2);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(0)), r2);
     {
         ScratchRegisterScope scratch(masm);
         masm.ma_ldr(Address(sp, sizeOfBailoutInfo), r1, scratch);
     }
     // Remove the return address, the IonScript, the register state
     // (InvaliationBailoutStack) and the space that was allocated for the return
@@ -671,17 +673,18 @@ GenerateBailoutThunk(JSContext* cx, Macr
     // Decrement sp by another 4, so we keep alignment. Not Anymore! Pushing
     // both the snapshotoffset as well as the: masm.as_sub(sp, sp, Imm8(4));
 
     // Set the old (4-byte aligned) value of the sp as the first argument.
     masm.passABIArg(r0);
     masm.passABIArg(r1);
 
     // Sp % 8 == 0
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(0)), r2);
     {
         ScratchRegisterScope scratch(masm);
         masm.ma_add(sp, Imm32(sizeOfBailoutInfo), sp, scratch);
     }
 
     // Common size of a bailout frame.
     uint32_t bailoutFrameSize = 0
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -194,17 +194,18 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         masm.push(BaselineFrameReg, reg_code);
 
         // Initialize the frame, including filling in the slots.
         masm.setupUnalignedABICall(r19);
         masm.passABIArg(BaselineFrameReg); // BaselineFrame.
         masm.passABIArg(reg_osrFrame); // InterpreterFrame.
         masm.passABIArg(reg_osrNStack);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
         masm.pop(r19, BaselineFrameReg);
         MOZ_ASSERT(r19 != ReturnReg);
 
         masm.addToStackPtr(Imm32(ExitFrameLayout::SizeWithFooter()));
         masm.addPtr(Imm32(BaselineFrame::Size()), BaselineFrameReg);
 
         Label error;
@@ -297,17 +298,18 @@ JitRuntime::generateInvalidator(JSContex
     masm.Sub(x2, masm.GetStackPointer64(), Operand(sizeof(size_t) + sizeof(void*)));
     masm.moveToStackPtr(r2);
 
     masm.setupUnalignedABICall(r10);
     masm.passABIArg(r0);
     masm.passABIArg(r1);
     masm.passABIArg(r2);
 
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.pop(r2, r1);
 
     masm.Add(masm.GetStackPointer64(), masm.GetStackPointer64(), x1);
     masm.Add(masm.GetStackPointer64(), masm.GetStackPointer64(),
              Operand(sizeof(InvalidationBailoutStack)));
     masm.syncStackPtr();
 
@@ -494,17 +496,18 @@ GenerateBailoutThunk(JSContext* cx, Macr
     // Make space for the BaselineBailoutInfo* outparam.
     const int sizeOfBailoutInfo = sizeof(void*) * 2;
     masm.reserveStack(sizeOfBailoutInfo);
     masm.moveStackPtrTo(r1);
 
     masm.setupUnalignedABICall(r2);
     masm.passABIArg(r0);
     masm.passABIArg(r1);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.Ldr(x2, MemOperand(masm.GetStackPointer64(), 0));
     masm.addToStackPtr(Imm32(sizeOfBailoutInfo));
 
     static const uint32_t BailoutDataSize = sizeof(void*) * Registers::Total +
                                             sizeof(double) * FloatRegisters::TotalPhys;
 
     if (frameClass == NO_FRAME_SIZE_CLASS_ID) {
--- a/js/src/jit/mips32/Trampoline-mips32.cpp
+++ b/js/src/jit/mips32/Trampoline-mips32.cpp
@@ -260,17 +260,18 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.reserveStack(2 * sizeof(uintptr_t));
         masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame
         masm.storePtr(reg_code, Address(StackPointer, 0)); // jitcode
 
         masm.setupUnalignedABICall(scratch);
         masm.passABIArg(BaselineFrameReg); // BaselineFrame
         masm.passABIArg(OsrFrameReg); // InterpreterFrame
         masm.passABIArg(numStackValues);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
         regs.add(OsrFrameReg);
         regs.take(JSReturnOperand);
         Register jitcode = regs.takeAny();
         masm.loadPtr(Address(StackPointer, 0), jitcode);
         masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), framePtr);
         masm.freeStack(2 * sizeof(uintptr_t));
 
@@ -386,17 +387,18 @@ JitRuntime::generateInvalidator(JSContex
     masm.ma_addu(a1, StackPointer, Imm32(sizeof(uintptr_t)));
     // Pass pointer to BailoutInfo
     masm.movePtr(StackPointer, a2);
 
     masm.setupAlignedABICall();
     masm.passABIArg(a0);
     masm.passABIArg(a1);
     masm.passABIArg(a2);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.loadPtr(Address(StackPointer, 0), a2);
     masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), a1);
     // Remove the return address, the IonScript, the register state
     // (InvaliationBailoutStack) and the space that was allocated for the
     // return value.
     masm.addPtr(Imm32(sizeof(InvalidationBailoutStack) + 2 * sizeof(uintptr_t)), StackPointer);
     // remove the space that this frame was using before the bailout
@@ -635,17 +637,18 @@ GenerateBailoutThunk(JSContext* cx, Macr
     // Put pointer to BailoutInfo
     masm.subPtr(Imm32(bailoutInfoOutParamSize), StackPointer);
     masm.storePtr(ImmPtr(nullptr), Address(StackPointer, 0));
     masm.movePtr(StackPointer, a1);
 
     masm.setupAlignedABICall();
     masm.passABIArg(a0);
     masm.passABIArg(a1);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     // Get BailoutInfo pointer
     masm.loadPtr(Address(StackPointer, 0), a2);
 
     // Remove both the bailout frame and the topmost Ion frame's stack.
     if (frameClass == NO_FRAME_SIZE_CLASS_ID) {
         // Load frameSize from stack
         masm.loadPtr(Address(StackPointer,
--- a/js/src/jit/mips64/Trampoline-mips64.cpp
+++ b/js/src/jit/mips64/Trampoline-mips64.cpp
@@ -277,17 +277,18 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.reserveStack(2 * sizeof(uintptr_t));
         masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame
         masm.storePtr(reg_code, Address(StackPointer, 0)); // jitcode
 
         masm.setupUnalignedABICall(scratch);
         masm.passABIArg(BaselineFrameReg); // BaselineFrame
         masm.passABIArg(OsrFrameReg); // InterpreterFrame
         masm.passABIArg(numStackValues);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
         regs.add(OsrFrameReg);
         Register jitcode = regs.takeAny();
         masm.loadPtr(Address(StackPointer, 0), jitcode);
         masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), framePtr);
         masm.freeStack(2 * sizeof(uintptr_t));
 
         Label error;
@@ -384,17 +385,18 @@ JitRuntime::generateInvalidator(JSContex
     masm.ma_daddu(a1, StackPointer, Imm32(sizeof(uintptr_t)));
     // Pass pointer to BailoutInfo
     masm.movePtr(StackPointer, a2);
 
     masm.setupAlignedABICall();
     masm.passABIArg(a0);
     masm.passABIArg(a1);
     masm.passABIArg(a2);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.loadPtr(Address(StackPointer, 0), a2);
     masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), a1);
     // Remove the return address, the IonScript, the register state
     // (InvaliationBailoutStack) and the space that was allocated for the
     // return value.
     masm.addPtr(Imm32(sizeof(InvalidationBailoutStack) + 2 * sizeof(uintptr_t)), StackPointer);
     // remove the space that this frame was using before the bailout
@@ -628,17 +630,18 @@ GenerateBailoutThunk(JSContext* cx, Macr
     // Put pointer to BailoutInfo
     static const uint32_t sizeOfBailoutInfo = sizeof(uintptr_t) * 2;
     masm.subPtr(Imm32(sizeOfBailoutInfo), StackPointer);
     masm.movePtr(StackPointer, a1);
 
     masm.setupAlignedABICall();
     masm.passABIArg(a0);
     masm.passABIArg(a1);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     // Get BailoutInfo pointer
     masm.loadPtr(Address(StackPointer, 0), a2);
 
     // Stack is:
     //     [frame]
     //     snapshotOffset
     //     frameSize
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -706,17 +706,17 @@ CodeGeneratorShared::createNativeToBytec
         }
 
         // Otherwise, we must have reached the top without finding any siblings.
         MOZ_ASSERT(tree->isOutermostCaller());
         break;
     }
 
     // Allocate array for list.
-    JSScript** data = cx->runtime()->pod_malloc<JSScript*>(scriptList.length());
+    JSScript** data = cx->zone()->pod_malloc<JSScript*>(scriptList.length());
     if (!data)
         return false;
 
     for (uint32_t i = 0; i < scriptList.length(); i++)
         data[i] = scriptList[i];
 
     // Success.
     nativeToBytecodeScriptListLength_ = scriptList.length();
@@ -753,17 +753,17 @@ CodeGeneratorShared::generateCompactNati
         js_free(nativeToBytecodeScriptList_);
         return false;
     }
 
     MOZ_ASSERT(tableOffset > 0);
     MOZ_ASSERT(numRegions > 0);
 
     // Writer is done, copy it to sized buffer.
-    uint8_t* data = cx->runtime()->pod_malloc<uint8_t>(writer.length());
+    uint8_t* data = cx->zone()->pod_malloc<uint8_t>(writer.length());
     if (!data) {
         js_free(nativeToBytecodeScriptList_);
         return false;
     }
 
     memcpy(data, writer.buffer(), writer.length());
     nativeToBytecodeMap_ = data;
     nativeToBytecodeMapSize_ = writer.length();
@@ -909,17 +909,17 @@ CodeGeneratorShared::generateCompactTrac
 
     MOZ_ASSERT(regionTableOffset > 0);
     MOZ_ASSERT(typesTableOffset > 0);
     MOZ_ASSERT(attemptsTableOffset > 0);
     MOZ_ASSERT(typesTableOffset > regionTableOffset);
     MOZ_ASSERT(attemptsTableOffset > typesTableOffset);
 
     // Copy over the table out of the writer's buffer.
-    uint8_t* data = cx->runtime()->pod_malloc<uint8_t>(writer.length());
+    uint8_t* data = cx->zone()->pod_malloc<uint8_t>(writer.length());
     if (!data)
         return false;
 
     memcpy(data, writer.buffer(), writer.length());
     trackedOptimizationsMap_ = data;
     trackedOptimizationsMapSize_ = writer.length();
     trackedOptimizationsRegionTableOffset_ = regionTableOffset;
     trackedOptimizationsTypesTableOffset_ = typesTableOffset;
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -237,17 +237,18 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         masm.push(framePtr);
         masm.push(reg_code);
 
         masm.setupUnalignedABICall(scratch);
         masm.passABIArg(framePtr); // BaselineFrame
         masm.passABIArg(OsrFrameReg); // InterpreterFrame
         masm.passABIArg(numStackValues);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
         masm.pop(reg_code);
         masm.pop(framePtr);
 
         MOZ_ASSERT(reg_code != ReturnReg);
 
         Label error;
         masm.addPtr(Imm32(ExitFrameLayout::SizeWithFooter()), rsp);
@@ -371,17 +372,18 @@ JitRuntime::generateInvalidator(JSContex
     // Make space for InvalidationBailout's bailoutInfo outparam.
     masm.reserveStack(sizeof(void*));
     masm.movq(rsp, r9);
 
     masm.setupUnalignedABICall(rdx);
     masm.passABIArg(rax);
     masm.passABIArg(rbx);
     masm.passABIArg(r9);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.pop(r9); // Get the bailoutInfo outparam.
     masm.pop(rbx); // Get the frameSize outparam.
 
     // Pop the machine state and the dead frame.
     masm.lea(Operand(rsp, rbx, TimesOne, sizeof(InvalidationBailoutStack)), rsp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
@@ -600,17 +602,18 @@ GenerateBailoutThunk(JSContext* cx, Macr
     // Make space for Bailout's bailoutInfo outparam.
     masm.reserveStack(sizeof(void*));
     masm.movq(rsp, r9);
 
     // Call the bailout function.
     masm.setupUnalignedABICall(rax);
     masm.passABIArg(r8);
     masm.passABIArg(r9);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.pop(r9); // Get the bailoutInfo outparam.
 
     // Stack is:
     //     [frame]
     //     snapshotOffset
     //     frameSize
     //     [bailoutFrame]
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -230,17 +230,18 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         masm.push(framePtr);
         masm.push(jitcode);
 
         masm.setupUnalignedABICall(scratch);
         masm.passABIArg(framePtr); // BaselineFrame
         masm.passABIArg(OsrFrameReg); // InterpreterFrame
         masm.passABIArg(numStackValues);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
         masm.pop(jitcode);
         masm.pop(framePtr);
 
         MOZ_ASSERT(jitcode != ReturnReg);
 
         Label error;
         masm.addPtr(Imm32(ExitFrameLayout::SizeWithFooter()), esp);
@@ -363,17 +364,18 @@ JitRuntime::generateInvalidator(JSContex
     // Make space for InvalidationBailout's bailoutInfo outparam.
     masm.reserveStack(sizeof(void*));
     masm.movl(esp, ecx);
 
     masm.setupUnalignedABICall(edx);
     masm.passABIArg(eax);
     masm.passABIArg(ebx);
     masm.passABIArg(ecx);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.pop(ecx); // Get bailoutInfo outparam.
     masm.pop(ebx); // Get the frameSize outparam.
 
     // Pop the machine state and the dead frame.
     masm.lea(Operand(esp, ebx, TimesOne, sizeof(InvalidationBailoutStack)), esp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in ecx.
@@ -598,17 +600,18 @@ GenerateBailoutThunk(JSContext* cx, Macr
     // Make space for Bailout's baioutInfo outparam.
     masm.reserveStack(sizeof(void*));
     masm.movl(esp, ebx);
 
     // Call the bailout function. This will correct the size of the bailout.
     masm.setupUnalignedABICall(ecx);
     masm.passABIArg(eax);
     masm.passABIArg(ebx);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.pop(ecx); // Get bailoutInfo outparam.
 
     // Common size of stuff we've pushed.
     static const uint32_t BailoutDataSize = 0
         + sizeof(void*) // frameClass
         + sizeof(RegisterDump);
 
--- a/js/src/jsalloc.h
+++ b/js/src/jsalloc.h
@@ -14,16 +14,20 @@
 #ifndef jsalloc_h
 #define jsalloc_h
 
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
 extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx);
 
+namespace JS {
+struct Zone;
+} // namespace JS
+
 namespace js {
 
 enum class AllocFunction {
     Malloc,
     Calloc,
     Realloc
 };
 /* Policy for using system memory functions and doing no error reporting. */
@@ -130,11 +134,45 @@ class TempAllocPolicy
             ReportOutOfMemory(cx_);
             return false;
         }
 
         return true;
     }
 };
 
+/*
+ * Allocation policy that uses Zone::pod_malloc and friends, so that memory
+ * pressure is accounted for on the zone. This is suitable for memory associated
+ * with GC things allocated in the zone.
+ *
+ * Since it doesn't hold a JSContext (those may not live long enough), it can't
+ * report out-of-memory conditions itself; the caller must check for OOM and
+ * take the appropriate action.
+ *
+ * FIXME bug 647103 - replace these *AllocPolicy names.
+ */
+class ZoneAllocPolicy
+{
+    JS::Zone* const zone;
+
+  public:
+    MOZ_IMPLICIT ZoneAllocPolicy(JS::Zone* z) : zone(z) {}
+
+    // These methods are defined in gc/Zone.h.
+    template <typename T> inline T* maybe_pod_malloc(size_t numElems);
+    template <typename T> inline T* maybe_pod_calloc(size_t numElems);
+    template <typename T> inline T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize);
+    template <typename T> inline T* pod_malloc(size_t numElems);
+    template <typename T> inline T* pod_calloc(size_t numElems);
+    template <typename T> inline T* pod_realloc(T* p, size_t oldSize, size_t newSize);
+
+    void free_(void* p) { js_free(p); }
+    void reportAllocOverflow() const {}
+
+    MOZ_MUST_USE bool checkSimulatedOOM() const {
+        return !js::oom::ShouldFailWithOOM();
+    }
+};
+
 } /* namespace js */
 
 #endif /* jsalloc_h */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1329,17 +1329,17 @@ JS::detail::ComputeThis(JSContext* cx, V
     return thisv;
 }
 
 JS_PUBLIC_API(void*)
 JS_malloc(JSContext* cx, size_t nbytes)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    return static_cast<void*>(cx->runtime()->pod_malloc<uint8_t>(nbytes));
+    return static_cast<void*>(cx->zone()->pod_malloc<uint8_t>(nbytes));
 }
 
 JS_PUBLIC_API(void*)
 JS_realloc(JSContext* cx, void* p, size_t oldBytes, size_t newBytes)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     return static_cast<void*>(cx->zone()->pod_realloc<uint8_t>(static_cast<uint8_t*>(p), oldBytes,
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -526,17 +526,18 @@ SetArrayElement(JSContext* cx, HandleObj
  * Otherwise call result.succeed() or result.fail() to indicate whether the
  * deletion attempt succeeded (that is, whether the call to [[Delete]] returned
  * true or false).  (Deletes generally fail only when the property is
  * non-configurable, but proxies may implement different semantics.)
  */
 static bool
 DeleteArrayElement(JSContext* cx, HandleObject obj, uint64_t index, ObjectOpResult& result)
 {
-    if (obj->is<ArrayObject>() && !obj->isIndexed() &&
+    if (obj->is<ArrayObject>() &&
+        !obj->as<NativeObject>().isIndexed() &&
         !obj->as<NativeObject>().denseElementsAreFrozen())
     {
         ArrayObject* aobj = &obj->as<ArrayObject>();
         if (index <= UINT32_MAX) {
             uint32_t idx = uint32_t(index);
             if (idx < aobj->getDenseInitializedLength()) {
                 if (!aobj->maybeCopyElementsForWrite(cx))
                     return false;
@@ -574,17 +575,18 @@ DeletePropertyOrThrow(JSContext* cx, Han
         return success.reportError(cx, obj, id);
     }
     return true;
 }
 
 static bool
 DeletePropertiesOrThrow(JSContext* cx, HandleObject obj, uint64_t len, uint64_t finalLength)
 {
-    if (obj->is<ArrayObject>() && !obj->isIndexed() &&
+    if (obj->is<ArrayObject>() &&
+        !obj->as<NativeObject>().isIndexed() &&
         !obj->as<NativeObject>().denseElementsAreFrozen())
     {
         if (len <= UINT32_MAX) {
             // Skip forward to the initialized elements of this array.
             len = Min(uint32_t(len), obj->as<ArrayObject>().getDenseInitializedLength());
         }
     }
 
@@ -983,20 +985,26 @@ array_addProperty(JSContext* cx, HandleO
         arr->setLength(cx, index + 1);
     }
     return true;
 }
 
 static inline bool
 ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj)
 {
-    return (!obj->isNative() && !obj->is<UnboxedArrayObject>()) ||
-           obj->isIndexed() ||
-           obj->is<TypedArrayObject>() ||
-           ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
+    if (!obj->isNative())
+        return !obj->is<UnboxedArrayObject>();
+
+    if (obj->as<NativeObject>().isIndexed())
+        return true;
+
+    if (obj->is<TypedArrayObject>())
+        return true;
+
+    return ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
                              obj->getClass(), INT_TO_JSID(0), obj);
 }
 
 /*
  * Whether obj may have indexed properties anywhere besides its dense
  * elements. This includes other indexed properties in its shape hierarchy, and
  * indexed properties or elements along its prototype chain.
  */
@@ -3133,27 +3141,27 @@ GetIndexedPropertiesInRange(JSContext* c
         for (uint32_t i = begin; i < initLen && i < end; i++) {
             if (nativeObj->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE))
                 continue;
             if (!indexes.append(i))
                 return false;
         }
 
         // Append typed array elements.
-        if (pobj->is<TypedArrayObject>()) {
-            uint32_t len = pobj->as<TypedArrayObject>().length();
+        if (nativeObj->is<TypedArrayObject>()) {
+            uint32_t len = nativeObj->as<TypedArrayObject>().length();
             for (uint32_t i = begin; i < len && i < end; i++) {
                 if (!indexes.append(i))
                     return false;
             }
         }
 
         // Append sparse elements.
-        if (pobj->isIndexed()) {
-            Shape::Range<NoGC> r(pobj->as<NativeObject>().lastProperty());
+        if (nativeObj->isIndexed()) {
+            Shape::Range<NoGC> r(nativeObj->lastProperty());
             for (; !r.empty(); r.popFront()) {
                 Shape& shape = r.front();
                 jsid id = shape.propid();
                 uint32_t i;
                 if (!IdIsIndex(id, &i))
                     continue;
 
                 if (!(begin <= i && i < end))
@@ -3273,17 +3281,17 @@ ArraySliceOrdinary(JSContext* cx, Handle
             if (!op(cx, obj, uint32_t(begin), uint32_t(end), &adder))
                 return false;
 
             rval.setObject(*narr);
             return true;
         }
     }
 
-    if (obj->isNative() && obj->isIndexed() && count > 1000) {
+    if (obj->isNative() && obj->as<NativeObject>().isIndexed() && count > 1000) {
         if (!SliceSparse(cx, obj, begin, end, narr))
             return false;
     } else {
         if (!CopyArrayElements(cx, obj, begin, count, narr))
             return false;
     }
 
     rval.setObject(*narr);
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -76,33 +76,33 @@ struct CommonNameInfo
 {
     const char* str;
     size_t length;
 };
 
 bool
 JSRuntime::initializeAtoms(JSContext* cx)
 {
-    atoms_ = cx->new_<AtomSet>();
+    atoms_ = js_new<AtomSet>();
     if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
         return false;
 
     // |permanentAtoms| hasn't been created yet.
     MOZ_ASSERT(!permanentAtoms);
 
     if (parentRuntime) {
         staticStrings = parentRuntime->staticStrings;
         commonNames = parentRuntime->commonNames;
         emptyString = parentRuntime->emptyString;
         permanentAtoms = parentRuntime->permanentAtoms;
         wellKnownSymbols = parentRuntime->wellKnownSymbols;
         return true;
     }
 
-    staticStrings = cx->new_<StaticStrings>();
+    staticStrings = js_new<StaticStrings>();
     if (!staticStrings || !staticStrings->init(cx))
         return false;
 
     static const CommonNameInfo cachedNames[] = {
 #define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
         FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
 #undef COMMON_NAME_INFO
 #define COMMON_NAME_INFO(name, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
@@ -111,33 +111,33 @@ JSRuntime::initializeAtoms(JSContext* cx
 #define COMMON_NAME_INFO(name) { #name, sizeof(#name) - 1 },
         JS_FOR_EACH_WELL_KNOWN_SYMBOL(COMMON_NAME_INFO)
 #undef COMMON_NAME_INFO
 #define COMMON_NAME_INFO(name) { "Symbol." #name, sizeof("Symbol." #name) - 1 },
         JS_FOR_EACH_WELL_KNOWN_SYMBOL(COMMON_NAME_INFO)
 #undef COMMON_NAME_INFO
     };
 
-    commonNames = cx->new_<JSAtomState>();
+    commonNames = js_new<JSAtomState>();
     if (!commonNames)
         return false;
 
     ImmutablePropertyNamePtr* names = reinterpret_cast<ImmutablePropertyNamePtr*>(commonNames.ref());
     for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
         JSAtom* atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, PinAtom);
         if (!atom)
             return false;
         names->init(atom->asPropertyName());
     }
     MOZ_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1));
 
     emptyString = commonNames->empty;
 
     // Create the well-known symbols.
-    wellKnownSymbols = cx->new_<WellKnownSymbols>();
+    wellKnownSymbols = js_new<WellKnownSymbols>();
     if (!wellKnownSymbols)
         return false;
 
     ImmutablePropertyNamePtr* descriptions = commonNames->wellKnownSymbolDescriptions();
     ImmutableSymbolPtr* symbols = reinterpret_cast<ImmutableSymbolPtr*>(wellKnownSymbols.ref());
     for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
         JS::Symbol* symbol = JS::Symbol::new_(cx, JS::SymbolCode(i), descriptions[i]);
         if (!symbol) {
@@ -237,19 +237,19 @@ bool
 JSRuntime::transformToPermanentAtoms(JSContext* cx)
 {
     MOZ_ASSERT(!parentRuntime);
 
     // All static strings were created as permanent atoms, now move the contents
     // of the atoms table into permanentAtoms and mark each as permanent.
 
     MOZ_ASSERT(!permanentAtoms);
-    permanentAtoms = cx->new_<FrozenAtomSet>(atoms_);   // takes ownership of atoms_
+    permanentAtoms = js_new<FrozenAtomSet>(atoms_);   // takes ownership of atoms_
 
-    atoms_ = cx->new_<AtomSet>();
+    atoms_ = js_new<AtomSet>();
     if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
         return false;
 
     for (FrozenAtomSet::Range r(permanentAtoms->all()); !r.empty(); r.popFront()) {
         AtomStateEntry entry = r.front();
         JSAtom* atom = entry.asPtr(cx);
         atom->morphIntoPermanentAtom();
     }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1145,17 +1145,17 @@ class MOZ_STACK_CLASS ReportExceptionClo
 JS_FRIEND_API(bool)
 js::UseInternalJobQueues(JSContext* cx)
 {
     // Internal job queue handling must be set up very early. Self-hosting
     // initialization is as good a marker for that as any.
     MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
                        "js::UseInternalJobQueues must be called early during runtime startup.");
     MOZ_ASSERT(!cx->jobQueue);
-    auto* queue = cx->new_<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
+    auto* queue = js_new<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
     if (!queue)
         return false;
 
     cx->jobQueue = queue;
     cx->runtime()->offThreadPromiseState.ref().initInternalDispatchQueue();
 
     JS::SetEnqueuePromiseJobCallback(cx, InternalEnqueuePromiseJobCallback);
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -138,17 +138,16 @@ struct JSContext : public JS::RootingCon
         }
         return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, this);
     }
 
     /* Clear the pending exception (if any) due to OOM. */
     void recoverFromOutOfMemory();
 
     inline void updateMallocCounter(size_t nbytes) {
-        // Note: this is racy.
         runtime()->updateMallocCounter(zone(), nbytes);
     }
 
     void reportAllocationOverflow() {
         js::ReportAllocationOverflow(this);
     }
 
     // Accessors for immutable runtime data.
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -93,16 +93,17 @@ JSCompartment::JSCompartment(Zone* zone,
     debugEnvs(nullptr),
     enumerators(nullptr),
     compartmentStats_(nullptr),
     scheduledForDestruction(false),
     maybeAlive(true),
     jitCompartment_(nullptr),
     mappedArgumentsTemplate_(nullptr),
     unmappedArgumentsTemplate_(nullptr),
+    iterResultTemplate_(nullptr),
     lcovOutput()
 {
     PodArrayZero(sawDeprecatedLanguageExtension);
     runtime_->numCompartments++;
     MOZ_ASSERT_IF(creationOptions_.mergeable(),
                   creationOptions_.invisibleToDebugger());
 }
 
@@ -707,17 +708,17 @@ JSCompartment::traceOutgoingCrossCompart
         if (e.front().key().is<JSObject*>()) {
             Value v = e.front().value().unbarrieredGet();
             ProxyObject* wrapper = &v.toObject().as<ProxyObject>();
 
             /*
              * We have a cross-compartment wrapper. Its private pointer may
              * point into the compartment being collected, so we should mark it.
              */
-            TraceEdge(trc, wrapper->slotOfPrivate(), "cross-compartment wrapper");
+            ProxyObject::traceEdgeToTarget(trc, wrapper);
         }
     }
 }
 
 /* static */ void
 JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc)
 {
     gcstats::AutoPhase ap(trc->runtime()->gc.stats(), gcstats::PhaseKind::MARK_CCWS);
@@ -988,16 +989,19 @@ CrossCompartmentKey::needsSweep()
 void
 JSCompartment::sweepTemplateObjects()
 {
     if (mappedArgumentsTemplate_ && IsAboutToBeFinalized(&mappedArgumentsTemplate_))
         mappedArgumentsTemplate_.set(nullptr);
 
     if (unmappedArgumentsTemplate_ && IsAboutToBeFinalized(&unmappedArgumentsTemplate_))
         unmappedArgumentsTemplate_.set(nullptr);
+
+    if (iterResultTemplate_ && IsAboutToBeFinalized(&iterResultTemplate_))
+        iterResultTemplate_.set(nullptr);
 }
 
 /* static */ void
 JSCompartment::fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc)
 {
     MOZ_ASSERT(trc->runtime()->gc.isHeapCompacting());
 
     for (CompartmentsIter comp(trc->runtime(), SkipAtoms); !comp.done(); comp.next()) {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -657,17 +657,17 @@ struct JSCompartment
     JS::Zone* zone() { return zone_; }
     const JS::Zone* zone() const { return zone_; }
 
     const JS::CompartmentCreationOptions& creationOptions() const { return creationOptions_; }
     JS::CompartmentBehaviors& behaviors() { return behaviors_; }
     const JS::CompartmentBehaviors& behaviors() const { return behaviors_; }
 
     JSRuntime* runtimeFromActiveCooperatingThread() const {
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
         return runtime_;
     }
 
     // Note: Unrestricted access to the zone's runtime from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     JSRuntime* runtimeFromAnyThread() const {
         return runtime_;
     }
@@ -1193,27 +1193,32 @@ struct JSCompartment
     bool scheduledForDestruction;
     bool maybeAlive;
 
   private:
     js::jit::JitCompartment* jitCompartment_;
 
     js::ReadBarriered<js::ArgumentsObject*> mappedArgumentsTemplate_;
     js::ReadBarriered<js::ArgumentsObject*> unmappedArgumentsTemplate_;
+    js::ReadBarriered<js::NativeObject*> iterResultTemplate_;
 
   public:
     bool ensureJitCompartmentExists(JSContext* cx);
     js::jit::JitCompartment* jitCompartment() {
         return jitCompartment_;
     }
 
     js::ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped);
 
     js::ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const;
 
+    static const size_t IterResultObjectValueSlot = 0;
+    static const size_t IterResultObjectDoneSlot = 1;
+    js::NativeObject* getOrCreateIterResultTemplateObject(JSContext* cx);
+
   private:
     // Used for collecting telemetry on SpiderMonkey's deprecated language extensions.
     bool sawDeprecatedLanguageExtension[size_t(js::DeprecatedLanguageExtension::Count)];
 
     void reportTelemetry();
 
   public:
     void addTelemetry(const char* filename, js::DeprecatedLanguageExtension e);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4026,17 +4026,17 @@ RelazifyFunctions(Zone* zone, AllocKind 
             fun->maybeRelazify(rt);
     }
 }
 
 static bool
 ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason)
 {
     // If we are repeating a GC because we noticed dead compartments haven't
-    // been collected, then only collect zones contianing those compartments.
+    // been collected, then only collect zones containing those compartments.
     if (reason == JS::gcreason::COMPARTMENT_REVIVED) {
         for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
             if (comp->scheduledForDestruction)
                 return true;
         }
 
         return false;
     }
@@ -4058,17 +4058,17 @@ ShouldCollectZone(Zone* zone, JS::gcreas
     // active thread.
     //
     // Otherwise, we always schedule a GC in the atoms zone so that atoms which
     // the other collected zones are using are marked, and we can update the
     // set of atoms in use by the other collected zones at the end of the GC.
     if (zone->isAtomsZone())
         return TlsContext.get()->canCollectAtoms();
 
-    return true;
+    return zone->canCollect();
 }
 
 bool
 GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut,
                                      AutoLockForExclusiveAccess& lock)
 {
 #ifdef DEBUG
     /* Assert that zone state is as we expect */
@@ -6701,31 +6701,29 @@ AutoGCSlice::AutoGCSlice(JSRuntime* rt)
          * Clear needsIncrementalBarrier early so we don't do any write
          * barriers during GC. We don't need to update the Ion barriers (which
          * is expensive) because Ion code doesn't run during GC. If need be,
          * we'll update the Ion barriers in ~AutoGCSlice.
          */
         if (zone->isGCMarking()) {
             MOZ_ASSERT(zone->needsIncrementalBarrier());
             zone->setNeedsIncrementalBarrier(false);
-        } else {
-            MOZ_ASSERT(!zone->needsIncrementalBarrier());
-        }
+        }
+        MOZ_ASSERT(!zone->needsIncrementalBarrier());
     }
 }
 
 AutoGCSlice::~AutoGCSlice()
 {
     /* We can't use GCZonesIter if this is the end of the last slice. */
     for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
+        MOZ_ASSERT(!zone->needsIncrementalBarrier());
         if (zone->isGCMarking()) {
             zone->setNeedsIncrementalBarrier(true);
             zone->arenas.purge();
-        } else {
-            zone->setNeedsIncrementalBarrier(false);
         }
     }
 }
 
 void
 GCRuntime::pushZealSelectedObjects()
 {
 #ifdef JS_GC_ZEAL
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -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/. */
 
 /* JavaScript iterators. */
 
 #include "jsiter.h"
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Unused.h"
 
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
@@ -41,16 +42,17 @@
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using JS::ForOfIterator;
 
 using mozilla::ArrayLength;
+using mozilla::DebugOnly;
 using mozilla::Maybe;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::PodZero;
 
 typedef Rooted<PropertyIteratorObject*> RootedPropertyIteratorObject;
 
 static const gc::AllocKind ITERATOR_FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
@@ -977,35 +979,88 @@ js::LookupInIteratorCache(JSContext* cx,
 
 // ES 2017 draft 7.4.7.
 JSObject*
 js::CreateIterResultObject(JSContext* cx, HandleValue value, bool done)
 {
     // Step 1 (implicit).
 
     // Step 2.
-    RootedObject resultObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
-    if (!resultObj)
+    RootedObject templateObject(cx, cx->compartment()->getOrCreateIterResultTemplateObject(cx));
+    if (!templateObject)
         return nullptr;
 
+    NativeObject* resultObj;
+    JS_TRY_VAR_OR_RETURN_NULL(cx, resultObj, NativeObject::createWithTemplate(cx, gc::DefaultHeap,
+                                                                              templateObject));
+
     // Step 3.
-    if (!DefineDataProperty(cx, resultObj, cx->names().value, value))
-        return nullptr;
+    resultObj->setSlot(JSCompartment::IterResultObjectValueSlot, value);
 
     // Step 4.
-    if (!DefineDataProperty(cx, resultObj, cx->names().done,
-                            done ? TrueHandleValue : FalseHandleValue))
-    {
-        return nullptr;
-    }
+    resultObj->setSlot(JSCompartment::IterResultObjectDoneSlot,
+                       done ? TrueHandleValue : FalseHandleValue);
 
     // Step 5.
     return resultObj;
 }
 
+NativeObject*
+JSCompartment::getOrCreateIterResultTemplateObject(JSContext* cx)
+{
+    if (iterResultTemplate_)
+        return iterResultTemplate_;
+
+    // Create template plain object
+    RootedNativeObject templateObject(cx, NewBuiltinClassInstance<PlainObject>(cx, TenuredObject));
+    if (!templateObject)
+        return iterResultTemplate_; // = nullptr
+
+    // Create a new group for the template.
+    Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
+    RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(),
+                                                                  proto));
+    if (!group)
+        return iterResultTemplate_; // = nullptr
+    templateObject->setGroup(group);
+
+    // Set dummy `value` property
+    if (!NativeDefineDataProperty(cx, templateObject, cx->names().value, UndefinedHandleValue,
+                                  JSPROP_ENUMERATE))
+    {
+        return iterResultTemplate_; // = nullptr
+    }
+
+    // Set dummy `done` property
+    if (!NativeDefineDataProperty(cx, templateObject, cx->names().done, TrueHandleValue,
+                                  JSPROP_ENUMERATE))
+    {
+        return iterResultTemplate_; // = nullptr
+    }
+
+    // Update `value` property typeset, since it can be any value.
+    HeapTypeSet* types = group->maybeGetProperty(NameToId(cx->names().value));
+    MOZ_ASSERT(types);
+    {
+        AutoEnterAnalysis enter(cx);
+        types->makeUnknown(cx);
+    }
+
+    // Make sure that the properties are in the right slots.
+    DebugOnly<Shape*> shape = templateObject->lastProperty();
+    MOZ_ASSERT(shape->previous()->slot() == JSCompartment::IterResultObjectValueSlot &&
+               shape->previous()->propidRef() == NameToId(cx->names().value));
+    MOZ_ASSERT(shape->slot() == JSCompartment::IterResultObjectDoneSlot &&
+               shape->propidRef() == NameToId(cx->names().done));
+
+    iterResultTemplate_.set(templateObject);
+
+    return iterResultTemplate_;
+}
+
 bool
 js::ThrowStopIteration(JSContext* cx)
 {
     MOZ_ASSERT(!JS_IsExceptionPending(cx));
 
     // StopIteration isn't a constructor, but it's stored in GlobalObject
     // as one, out of laziness. Hence the GetBuiltinConstructor call here.
     RootedObject ctor(cx);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1156,17 +1156,17 @@ js::CloneObject(JSContext* cx, HandleObj
     return clone;
 }
 
 static bool
 GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values)
 {
     MOZ_ASSERT(!obj->isSingleton());
     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
-    MOZ_ASSERT(!obj->isIndexed());
+    MOZ_ASSERT_IF(obj->isNative(), !obj->as<NativeObject>().isIndexed());
 
     size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
     if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
         return false;
 
     size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
     for (size_t i = 0; i < initlen; i++)
         values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i));
@@ -2971,17 +2971,17 @@ js::WatchGuts(JSContext* cx, JS::HandleO
         if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
             return false;
 
         MarkTypePropertyNonData(cx, obj, id);
     }
 
     WatchpointMap* wpmap = cx->compartment()->watchpointMap;
     if (!wpmap) {
-        wpmap = cx->runtime()->new_<WatchpointMap>();
+        wpmap = cx->zone()->new_<WatchpointMap>();
         if (!wpmap || !wpmap->init()) {
             ReportOutOfMemory(cx);
             js_delete(wpmap);
             return false;
         }
         cx->compartment()->watchpointMap = wpmap;
     }
 
@@ -3581,36 +3581,39 @@ JSObject::dump(js::GenericPrinter& out) 
     } else {
         const ObjectGroup* group = obj->group();
         out.printf("group %p\n", (const void*)group);
     }
 
     out.put("flags:");
     if (obj->isDelegate()) out.put(" delegate");
     if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) out.put(" not_extensible");
-    if (obj->isIndexed()) out.put(" indexed");
     if (obj->maybeHasInterestingSymbolProperty()) out.put(" maybe_has_interesting_symbol");
     if (obj->isBoundFunction()) out.put(" bound_function");
     if (obj->isQualifiedVarObj()) out.put(" varobj");
     if (obj->isUnqualifiedVarObj()) out.put(" unqualified_varobj");
     if (obj->watched()) out.put(" watched");
     if (obj->isIteratedSingleton()) out.put(" iterated_singleton");
     if (obj->isNewGroupUnknown()) out.put(" new_type_unknown");
     if (obj->hasUncacheableProto()) out.put(" has_uncacheable_proto");
-    if (obj->hadElementsAccess()) out.put(" had_elements_access");
-    if (obj->wasNewScriptCleared()) out.put(" new_script_cleared");
     if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable())
         out.put(" immutable_prototype");
 
     if (obj->isNative()) {
         const NativeObject* nobj = &obj->as<NativeObject>();
         if (nobj->inDictionaryMode())
             out.put(" inDictionaryMode");
         if (nobj->hasShapeTable())
             out.put(" hasShapeTable");
+        if (nobj->hadElementsAccess())
+            out.put(" had_elements_access");
+        if (nobj->isIndexed())
+            out.put(" indexed");
+        if (nobj->wasNewScriptCleared())
+            out.put(" new_script_cleared");
     }
     out.putChar('\n');
 
     if (obj->isNative()) {
         const NativeObject* nobj = &obj->as<NativeObject>();
         uint32_t slots = nobj->getDenseInitializedLength();
         if (slots) {
             out.put("elements\n");
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -231,31 +231,16 @@ class JSObject : public js::gc::Cell
     static bool setUncacheableProto(JSContext* cx, JS::HandleObject obj) {
         MOZ_ASSERT(obj->hasStaticPrototype(),
                    "uncacheability as a concept is only applicable to static "
                    "(not dynamically-computed) prototypes");
         return setFlags(cx, obj, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
     }
 
     /*
-     * Whether SETLELEM was used to access this object. See also the comment near
-     * PropertyTree::MAX_HEIGHT.
-     */
-    inline bool hadElementsAccess() const;
-    static bool setHadElementsAccess(JSContext* cx, JS::HandleObject obj) {
-        return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS);
-    }
-
-    /*
-     * Whether there may be indexed properties on this object, excluding any in
-     * the object's elements.
-     */
-    inline bool isIndexed() const;
-
-    /*
      * Whether there may be "interesting symbol" properties on this object. An
      * interesting symbol is a symbol for which symbol->isInterestingSymbol()
      * returns true.
      */
     MOZ_ALWAYS_INLINE bool maybeHasInterestingSymbolProperty() const;
 
     /*
      * If this object was instantiated with `new Ctor`, return the constructor's
@@ -408,22 +393,16 @@ class JSObject : public js::gc::Cell
 
     /*
      * Mark an object as requiring its default 'new' type to have unknown
      * properties.
      */
     inline bool isNewGroupUnknown() const;
     static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
 
-    // Mark an object as having its 'new' script information cleared.
-    inline bool wasNewScriptCleared() const;
-    static bool setNewScriptCleared(JSContext* cx, JS::HandleObject obj) {
-        return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED);
-    }
-
     /* Set a new prototype for an object with a singleton type. */
     static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp,
                                 js::Handle<js::TaggedProto> proto);
 
     /*
      * For bootstrapping, whether to splice a prototype for Function.prototype
      * or the global object.
      */
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -463,43 +463,31 @@ JSObject::isDelegate() const
 }
 
 inline bool
 JSObject::hasUncacheableProto() const
 {
     return hasAllFlags(js::BaseShape::UNCACHEABLE_PROTO);
 }
 
-inline bool
-JSObject::hadElementsAccess() const
-{
-    return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
-}
-
-inline bool
-JSObject::isIndexed() const
-{
-    return hasAllFlags(js::BaseShape::INDEXED);
-}
-
 MOZ_ALWAYS_INLINE bool
 JSObject::maybeHasInterestingSymbolProperty() const
 {
     const js::NativeObject* nobj;
     if (isNative()) {
         nobj = &as<js::NativeObject>();
     } else if (is<js::UnboxedPlainObject>()) {
         nobj = as<js::UnboxedPlainObject>().maybeExpando();
         if (!nobj)
             return false;
     } else {
         return true;
     }
 
-    return nobj->hasAllFlags(js::BaseShape::HAS_INTERESTING_SYMBOL);
+    return nobj->hasInterestingSymbol();
 }
 
 inline bool
 JSObject::staticPrototypeIsImmutable() const
 {
     MOZ_ASSERT(hasStaticPrototype());
     return hasAllFlags(js::BaseShape::IMMUTABLE_PROTOTYPE);
 }
@@ -511,22 +499,16 @@ JSObject::isIteratedSingleton() const
 }
 
 inline bool
 JSObject::isNewGroupUnknown() const
 {
     return hasAllFlags(js::BaseShape::NEW_GROUP_UNKNOWN);
 }
 
-inline bool
-JSObject::wasNewScriptCleared() const
-{
-    return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
-}
-
 namespace js {
 
 static MOZ_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value& v)
 {
     return v.isObject() && v.toObject().is<JSFunction>();
 }
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -500,17 +500,17 @@ JA(JSContext* cx, HandleObject obj, Stri
                 RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
                 if (i <= JSID_INT_MAX) {
                     MOZ_ASSERT(nativeObj->containsDenseElement(i) != nativeObj->isIndexed(),
                                "the array must either be small enough to remain "
                                "fully dense (and otherwise un-indexed), *or* "
                                "all its initially-dense elements were sparsified "
                                "and the object is indexed");
                 } else {
-                    MOZ_ASSERT(obj->isIndexed());
+                    MOZ_ASSERT(nativeObj->isIndexed());
                 }
             }
 #endif
             if (!GetElement(cx, obj, i, &outputValue))
                 return false;
             if (!PreprocessValue(cx, obj, i, &outputValue, scx))
                 return false;
             if (IsFilteredValue(outputValue)) {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3907,17 +3907,17 @@ JSScript::getOrCreateBreakpointSite(JSCo
 {
     if (!ensureHasDebugScript(cx))
         return nullptr;
 
     DebugScript* debug = debugScript();
     BreakpointSite*& site = debug->breakpoints[pcToOffset(pc)];
 
     if (!site) {
-        site = cx->runtime()->new_<JSBreakpointSite>(this, pc);
+        site = cx->zone()->new_<JSBreakpointSite>(this, pc);
         if (!site) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
         debug->numSites++;
     }
 
     return site;
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -115,30 +115,30 @@ static T extractUnbarriered(const WriteB
 template <typename T>
 static T* extractUnbarriered(T* v)
 {
     return v;
 }
 
 template <class Key, class Value,
           class HashPolicy = DefaultHasher<Key> >
-class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>,
+class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
                 public WeakMapBase
 {
   public:
-    typedef HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy> Base;
+    typedef HashMap<Key, Value, HashPolicy, ZoneAllocPolicy> Base;
     typedef typename Base::Enum Enum;
     typedef typename Base::Lookup Lookup;
     typedef typename Base::Entry Entry;
     typedef typename Base::Range Range;
     typedef typename Base::Ptr Ptr;
     typedef typename Base::AddPtr AddPtr;
 
     explicit WeakMap(JSContext* cx, JSObject* memOf = nullptr)
-        : Base(cx->runtime()), WeakMapBase(memOf, cx->compartment()->zone()) { }
+        : Base(cx->zone()), WeakMapBase(memOf, cx->zone()) { }
 
     bool init(uint32_t len = 16) {
         if (!Base::init(len))
             return false;
         zone()->gcWeakMapList().insertFront(this);
         marked = JS::IsIncrementalGCInProgress(TlsContext.get());
         return true;
     }
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -673,16 +673,22 @@ static bool
 proxy_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
 {
     if (!Proxy::delete_(cx, obj, id, result))
         return false;
     return SuppressDeletedProperty(cx, obj, id); // XXX is this necessary?
 }
 
 /* static */ void
+ProxyObject::traceEdgeToTarget(JSTracer* trc, ProxyObject* obj)
+{
+    TraceCrossCompartmentEdge(trc, obj, obj->slotOfPrivate(), "proxy target");
+}
+
+/* static */ void
 ProxyObject::trace(JSTracer* trc, JSObject* obj)
 {
     ProxyObject* proxy = &obj->as<ProxyObject>();
 
     TraceEdge(trc, &proxy->shape_, "ProxyObject_shape");
 
 #ifdef DEBUG
     if (TlsContext.get()->isStrictProxyCheckingEnabled() && proxy->is<WrapperObject>()) {
@@ -697,17 +703,18 @@ ProxyObject::trace(JSTracer* trc, JSObje
             MOZ_ASSERT(p);
             MOZ_ASSERT(*p->value().unsafeGet() == ObjectValue(*proxy));
         }
     }
 #endif
 
     // Note: If you add new slots here, make sure to change
     // nuke() to cope.
-    TraceCrossCompartmentEdge(trc, obj, proxy->slotOfPrivate(), "private");
+
+    traceEdgeToTarget(trc, proxy);
 
     size_t nreserved = proxy->numReservedSlots();
     for (size_t i = 0; i < nreserved; i++) {
         /*
          * The GC can use the second reserved slot to link the cross compartment
          * wrappers into a linked list, in which case we don't want to trace it.
          */
         if (proxy->is<CrossCompartmentWrapperObject>() &&
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/duplicate-variants.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+
+// RFC 5646 section 2.1
+// variant       = 5*8alphanum         ; registered variants
+//               / (DIGIT 3alphanum)
+
+// Duplicate variants are forbidden.
+assertEqArray(Intl.getCanonicalLocales("de-1996"), ["de-1996"]);
+assertThrowsInstanceOf(() => Intl.getCanonicalLocales("de-1996-1996"), RangeError);
+
+// Multiple different variants are allowed.
+assertEqArray(Intl.getCanonicalLocales("sl-rozaj-biske-1994"), ["sl-rozaj-biske-1994"]);
+
+// Variants can have the same prefix.
+assertEqArray(Intl.getCanonicalLocales("zh-Latn-pinyin-pinyin2"), ["zh-Latn-pinyin-pinyin2"]);
+
+// Values in extension sequences are not counted as variants.
+assertEqArray(Intl.getCanonicalLocales("en-u-kf-false-kn-false"), ["en-u-kf-false-kn-false"]);
+
+// Also test duplicates in Unicode extension keywords and attributes.
+// From https://tools.ietf.org/html/rfc6067#section-2.1
+//
+//    An 'attribute' is a subtag with a length of three to eight
+//    characters following the singleton and preceding any 'keyword'
+//    sequences.  No attributes were defined at the time of this
+//    document's publication.
+//
+//    A 'keyword' is a sequence of subtags consisting of a 'key' subtag,
+//    followed by zero or more 'type' subtags (so a 'key' might appear
+//    alone and not be accompanied by a 'type' subtag).  A 'key' MUST
+//    NOT appear more than once in a language tag's extension string.
+//
+//    ...
+//
+//    Only the first occurrence of an attribute or key conveys meaning in a
+//    language tag.  When interpreting tags containing the Unicode locale
+//    extension, duplicate attributes or keywords are ignored in the
+//    following way: ignore any attribute that has already appeared in the
+//    tag and ignore any keyword whose key has already occurred in the tag.
+assertEqArray(Intl.getCanonicalLocales("en-u-kn-false-kn-false"), ["en-u-kn-false-kn-false"]);
+assertEqArray(Intl.getCanonicalLocales("en-u-attr1-attr2-attr2"), ["en-u-attr1-attr2-attr2"]);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -299,17 +299,17 @@ ArrayBufferObject::class_constructor(JSC
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
 static ArrayBufferObject::BufferContents
 AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
 {
-    uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes);
+    uint8_t* p = cx->zone()->pod_callocCanGC<uint8_t>(nbytes);
     if (!p)
         ReportOutOfMemory(cx);
 
     return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
 }
 
 static void
 NoteViewBufferWasDetached(ArrayBufferViewObject* view,
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -663,29 +663,29 @@ WasmBreakpointSite::destroyIfEmpty(FreeO
     if (isEmpty())
         debug->destroyBreakpointSite(fop, offset);
 }
 
 /*** Debugger hook dispatch **********************************************************************/
 
 Debugger::Debugger(JSContext* cx, NativeObject* dbg)
   : object(dbg),
-    debuggees(cx->runtime()),
+    debuggees(cx->zone()),
     uncaughtExceptionHook(nullptr),
     enabled(true),
     allowUnobservedAsmJS(false),
     allowWasmBinarySource(false),
     collectCoverageInfo(false),
-    observedGCs(cx->runtime()),
+    observedGCs(cx->zone()),
     allocationsLog(cx),
     trackingAllocationSites(false),
     allocationSamplingProbability(1.0),
     maxAllocationsLogLength(DEFAULT_MAX_LOG_LENGTH),
     allocationsLogOverflowed(false),
-    frames(cx->runtime()),
+    frames(cx->zone()),
     scripts(cx),
     sources(cx),
     objects(cx),
     environments(cx),
     wasmInstanceScripts(cx),
     wasmInstanceSources(cx),
 #ifdef NIGHTLY_BUILD
     traceLoggerLastDrainedSize(0),
@@ -4241,22 +4241,22 @@ static inline DebuggerSourceReferent Get
 class MOZ_STACK_CLASS Debugger::ScriptQuery
 {
   public:
     /* Construct a ScriptQuery to use matching scripts for |dbg|. */
     ScriptQuery(JSContext* cx, Debugger* dbg):
         cx(cx),
         debugger(dbg),
         iterMarker(&cx->runtime()->gc),
-        compartments(cx->runtime()),
+        compartments(cx->zone()),
         url(cx),
         displayURLString(cx),
         hasSource(false),
         source(cx, AsVariant(static_cast<ScriptSourceObject*>(nullptr))),
-        innermostForCompartment(cx->runtime()),
+        innermostForCompartment(cx->zone()),
         vector(cx, ScriptVector(cx)),
         wasmInstanceVector(cx, WasmInstanceObjectVector(cx))
     {}
 
     /*
      * Initialize this ScriptQuery. Raise an error and return false if we
      * haven't enough memory.
      */
@@ -4496,17 +4496,17 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
     JSContext* cx;
 
     /* The debugger for which we conduct queries. */
     Debugger* debugger;
 
     /* Require the set of compartments to stay fixed while the ScriptQuery is alive. */
     gc::AutoEnterIteration iterMarker;
 
-    typedef HashSet<JSCompartment*, DefaultHasher<JSCompartment*>, RuntimeAllocPolicy>
+    typedef HashSet<JSCompartment*, DefaultHasher<JSCompartment*>, ZoneAllocPolicy>
         CompartmentSet;
 
     /* A script must be in one of these compartments to match the query. */
     CompartmentSet compartments;
 
     /* If this is a string, matching scripts have urls equal to it. */
     RootedValue url;
 
@@ -4529,17 +4529,17 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
     bool hasLine;
 
     /* The line matching scripts must cover. */
     unsigned int line;
 
     /* True if the query has an 'innermost' property whose value is true. */
     bool innermost;
 
-    typedef HashMap<JSCompartment*, JSScript*, DefaultHasher<JSCompartment*>, RuntimeAllocPolicy>
+    typedef HashMap<JSCompartment*, JSScript*, DefaultHasher<JSCompartment*>, ZoneAllocPolicy>
         CompartmentToScriptMap;
 
     /*
      * For 'innermost' queries, a map from compartments to the innermost script
      * we've seen so far in that compartment. (Template instantiation code size
      * explosion ho!)
      */
     CompartmentToScriptMap innermostForCompartment;
@@ -6522,34 +6522,34 @@ struct DebuggerScriptSetBreakpointMatche
         if (!dbg_->ensureExecutionObservabilityOfScript(cx_, script))
             return false;
 
         jsbytecode* pc = script->offsetToPC(offset_);
         BreakpointSite* site = script->getOrCreateBreakpointSite(cx_, pc);
         if (!site)
             return false;
         site->inc(cx_->runtime()->defaultFreeOp());
-        if (cx_->runtime()->new_<Breakpoint>(dbg_, site, handler_))
+        if (cx_->zone()->new_<Breakpoint>(dbg_, site, handler_))
             return true;
         site->dec(cx_->runtime()->defaultFreeOp());
         site->destroyIfEmpty(cx_->runtime()->defaultFreeOp());
         return false;
     }
 
     ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
         wasm::Instance& instance = wasmInstance->instance();
         if (!instance.debug().hasBreakpointTrapAtOffset(offset_)) {
             JS_ReportErrorNumberASCII(cx_, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_OFFSET);
             return false;
         }
         WasmBreakpointSite* site = instance.debug().getOrCreateBreakpointSite(cx_, offset_);
         if (!site)
             return false;
         site->inc(cx_->runtime()->defaultFreeOp());
-        if (cx_->runtime()->new_<WasmBreakpoint>(dbg_, site, handler_, instance.object()))
+        if (cx_->zone()->new_<WasmBreakpoint>(dbg_, site, handler_, instance.object()))
             return true;
         site->dec(cx_->runtime()->defaultFreeOp());
         site->destroyIfEmpty(cx_->runtime()->defaultFreeOp());
         return false;
     }
 };
 
 static bool
@@ -11646,17 +11646,17 @@ Debugger::isDebuggerCrossCompartmentEdge
 /*** JS::dbg::GarbageCollectionEvent **************************************************************/
 
 namespace JS {
 namespace dbg {
 
 /* static */ GarbageCollectionEvent::Ptr
 GarbageCollectionEvent::Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t gcNumber)
 {
-    auto data = rt->make_unique<GarbageCollectionEvent>(gcNumber);
+    auto data = MakeUnique<GarbageCollectionEvent>(gcNumber);
     if (!data)
         return nullptr;
 
     data->nonincrementalReason = stats.nonincrementalReason();
 
     for (auto& slice : stats.slices()) {
         if (!data->reason) {
             // There is only one GC reason for the whole cycle, but for legacy
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -43,17 +43,17 @@ namespace js {
 class Breakpoint;
 class DebuggerMemory;
 class ScriptedOnStepHandler;
 class ScriptedOnPopHandler;
 class WasmInstanceObject;
 
 typedef HashSet<ReadBarrieredGlobalObject,
                 MovableCellHasher<ReadBarrieredGlobalObject>,
-                RuntimeAllocPolicy> WeakGlobalObjectSet;
+                ZoneAllocPolicy> WeakGlobalObjectSet;
 
 /*
  * A weakmap from GC thing keys to JSObject values that supports the keys being
  * in different compartments to the values. All values must be in the same
  * compartment.
  *
  * The purpose of this is to allow the garbage collector to easily find edges
  * from debuggee object compartments to debugger compartments when calculating
@@ -80,27 +80,27 @@ class DebuggerWeakMap : private WeakMap<
 {
   private:
     typedef HeapPtr<UnbarrieredKey> Key;
     typedef HeapPtr<JSObject*> Value;
 
     typedef HashMap<JS::Zone*,
                     uintptr_t,
                     DefaultHasher<JS::Zone*>,
-                    RuntimeAllocPolicy> CountMap;
+                    ZoneAllocPolicy> CountMap;
 
     CountMap zoneCounts;
     JSCompartment* compartment;
 
   public:
     typedef WeakMap<Key, Value, MovableCellHasher<Key>> Base;
 
     explicit DebuggerWeakMap(JSContext* cx)
         : Base(cx),
-          zoneCounts(cx->runtime()),
+          zoneCounts(cx->zone()),
           compartment(cx->compartment())
     { }
 
   public:
     /* Expose those parts of HashMap public interface that are used by Debugger methods. */
 
     typedef typename Base::Entry Entry;
     typedef typename Base::Ptr Ptr;
@@ -399,17 +399,17 @@ class Debugger : private mozilla::Linked
     // List of all js::Breakpoints in this debugger.
     using BreakpointList =
         mozilla::DoublyLinkedList<js::Breakpoint,
                                   DebuggerLinkAccess<js::Breakpoint>>;
     BreakpointList breakpoints;
 
     // The set of GC numbers for which one or more of this Debugger's observed
     // debuggees participated in.
-    using GCNumberSet = HashSet<uint64_t, DefaultHasher<uint64_t>, RuntimeAllocPolicy>;
+    using GCNumberSet = HashSet<uint64_t, DefaultHasher<uint64_t>, ZoneAllocPolicy>;
     GCNumberSet observedGCs;
 
     using AllocationsLog = js::TraceableFifo<AllocationsLogEntry>;
 
     AllocationsLog allocationsLog;
     bool trackingAllocationSites;
     double allocationSamplingProbability;
     size_t maxAllocationsLogLength;
@@ -476,17 +476,17 @@ class Debugger : private mozilla::Linked
      * We don't trace the keys of this map (the frames are on the stack and
      * thus necessarily live), but we do trace the values. It's like a WeakMap
      * that way, but since stack frames are not gc-things, the implementation
      * has to be different.
      */
     typedef HashMap<AbstractFramePtr,
                     HeapPtr<DebuggerFrame*>,
                     DefaultHasher<AbstractFramePtr>,
-                    RuntimeAllocPolicy> FrameMap;
+                    ZoneAllocPolicy> FrameMap;
     FrameMap frames;
 
     /* An ephemeral map from JSScript* to Debugger.Script instances. */
     typedef DebuggerWeakMap<JSScript*> ScriptWeakMap;
     ScriptWeakMap scripts;
 
     /* The map from debuggee source script objects to their Debugger.Source instances. */
     typedef DebuggerWeakMap<JSObject*, true> SourceWeakMap;
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -2417,18 +2417,18 @@ DebugEnvironmentProxy::isOptimizedOut() 
     return false;
 }
 
 /*****************************************************************************/
 
 DebugEnvironments::DebugEnvironments(JSContext* cx, Zone* zone)
  : zone_(zone),
    proxiedEnvs(cx),
-   missingEnvs(cx->runtime()),
-   liveEnvs(cx->runtime())
+   missingEnvs(cx->zone()),
+   liveEnvs(cx->zone())
 {}
 
 DebugEnvironments::~DebugEnvironments()
 {
     MOZ_ASSERT_IF(missingEnvs.initialized(), missingEnvs.empty());
 }
 
 bool
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -944,31 +944,31 @@ class DebugEnvironments
 
     /*
      * The map from live frames which have optimized-away environments to the
      * corresponding debug environments.
      */
     typedef HashMap<MissingEnvironmentKey,
                     ReadBarrieredDebugEnvironmentProxy,
                     MissingEnvironmentKey,
-                    RuntimeAllocPolicy> MissingEnvironmentMap;
+                    ZoneAllocPolicy> MissingEnvironmentMap;
     MissingEnvironmentMap missingEnvs;
 
     /*
      * The map from environment objects of live frames to the live frame. This
      * map updated lazily whenever the debugger needs the information. In
      * between two lazy updates, liveEnvs becomes incomplete (but not invalid,
      * onPop* removes environments as they are popped). Thus, two consecutive
      * debugger lazy updates of liveEnvs need only fill in the new
      * environments.
      */
     typedef GCHashMap<ReadBarriered<JSObject*>,
                       LiveEnvironmentVal,
                       MovableCellHasher<ReadBarriered<JSObject*>>,
-                      RuntimeAllocPolicy> LiveEnvironmentMap;
+                      ZoneAllocPolicy> LiveEnvironmentMap;
     LiveEnvironmentMap liveEnvs;
 
   public:
     DebugEnvironments(JSContext* cx, Zone* zone);
     ~DebugEnvironments();
 
     Zone* zone() const { return zone_; }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1625,20 +1625,20 @@ SetObjectElementOperation(JSContext* cx,
 
     // Set the HadElementsAccess flag on the object if needed. This flag is
     // used to do more eager dictionary-mode conversion for objects that are
     // used as hashmaps. Set this flag only for objects with many properties,
     // to avoid unnecessary Shape changes.
     if (obj->isNative() &&
         JSID_IS_ATOM(id) &&
         !obj->as<NativeObject>().inDictionaryMode() &&
-        !obj->hadElementsAccess() &&
+        !obj->as<NativeObject>().hadElementsAccess() &&
         obj->as<NativeObject>().slotSpan() > PropertyTree::MAX_HEIGHT_WITH_ELEMENTS_ACCESS / 3)
     {
-        if (!JSObject::setHadElementsAccess(cx, obj))
+        if (!NativeObject::setHadElementsAccess(cx, obj.as<NativeObject>()))
             return false;
     }
 
     ObjectOpResult result;
     return SetProperty(cx, obj, id, value, receiver, result) &&
            result.checkStrictErrorOrWarning(cx, obj, id, strict);
 }
 
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -311,17 +311,17 @@ static void
 StatsZoneCallback(JSRuntime* rt, void* data, Zone* zone)
 {
     // Append a new CompartmentStats to the vector.
     RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->zoneStatsVector.growBy(1));
     ZoneStats& zStats = rtStats->zoneStatsVector.back();
-    if (!zStats.initStrings(rt))
+    if (!zStats.initStrings())
         MOZ_CRASH("oom");
     rtStats->initExtraZoneStats(zone, &zStats);
     rtStats->currZoneStats = &zStats;
 
     zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
                                  &zStats.typePool,
                                  &zStats.regexpZone,
                                  &zStats.jitZone,
@@ -336,17 +336,17 @@ static void
 StatsCompartmentCallback(JSContext* cx, void* data, JSCompartment* compartment)
 {
     // Append a new CompartmentStats to the vector.
     RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
     CompartmentStats& cStats = rtStats->compartmentStatsVector.back();
-    if (!cStats.initClasses(cx->runtime()))
+    if (!cStats.initClasses())
         MOZ_CRASH("oom");
     rtStats->initExtraCompartmentStats(compartment, &cStats);
 
     compartment->setCompartmentStats(&cStats);
 
     // Measure the compartment object itself, and things hanging off it.
     compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
                                         &cStats.typeInferenceAllocationSiteTables,
@@ -615,33 +615,33 @@ StatsCellCallback(JSRuntime* rt, void* d
         MOZ_CRASH("invalid traceKind in StatsCellCallback");
     }
 
     // Yes, this is a subtraction:  see StatsArenaCallback() for details.
     zStats->unusedGCThings.addToKind(traceKind, -thingSize);
 }
 
 bool
-ZoneStats::initStrings(JSRuntime* rt)
+ZoneStats::initStrings()
 {
     isTotals = false;
-    allStrings = rt->new_<StringsHashMap>();
+    allStrings = js_new<StringsHashMap>();
     if (!allStrings || !allStrings->init()) {
         js_delete(allStrings);
         allStrings = nullptr;
         return false;
     }
     return true;
 }
 
 bool
-CompartmentStats::initClasses(JSRuntime* rt)
+CompartmentStats::initClasses()
 {
     isTotals = false;
-    allClasses = rt->new_<ClassesHashMap>();
+    allClasses = js_new<ClassesHashMap>();
     if (!allClasses || !allClasses->init()) {
         js_delete(allClasses);
         allClasses = nullptr;
         return false;
     }
     return true;
 }
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -495,16 +495,30 @@ NativeObject::create(JSContext* cx, js::
     else
         nobj = SetNewObjectMetadata(cx, nobj);
 
     js::gc::TraceCreateObject(nobj);
 
     return nobj;
 }
 
+/* static */ inline JS::Result<NativeObject*, JS::OOM&>
+NativeObject::createWithTemplate(JSContext* cx, js::gc::InitialHeap heap,
+                                 HandleObject templateObject)
+{
+    RootedObjectGroup group(cx, templateObject->group());
+    RootedShape shape(cx, templateObject->as<NativeObject>().lastProperty());
+
+    gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+    MOZ_ASSERT(CanBeFinalizedInBackground(kind, shape->getObjectClass()));
+    kind = gc::GetBackgroundAllocKind(kind);
+
+    return create(cx, kind, heap, shape, group);
+}
+
 MOZ_ALWAYS_INLINE uint32_t
 NativeObject::numDynamicSlots() const
 {
     return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
 }
 
 /* static */ MOZ_ALWAYS_INLINE uint32_t
 NativeObject::dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class* clasp)
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -538,16 +538,19 @@ class NativeObject : public ShapedObject
     }
 
     inline bool isInWholeCellBuffer() const;
 
     static inline JS::Result<NativeObject*, JS::OOM&>
     create(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
            js::HandleShape shape, js::HandleObjectGroup group);
 
+    static inline JS::Result<NativeObject*, JS::OOM&>
+    createWithTemplate(JSContext* cx, js::gc::InitialHeap heap, HandleObject templateObject);
+
   protected:
 #ifdef DEBUG
     void checkShapeConsistency();
 #else
     void checkShapeConsistency() { }
 #endif
 
     static Shape*
@@ -713,16 +716,63 @@ class NativeObject : public ShapedObject
 
     /* Index into the dynamic slots array to use for a dynamic slot. */
     size_t dynamicSlotIndex(size_t slot) {
         MOZ_ASSERT(slot >= numFixedSlots());
         return slot - numFixedSlots();
     }
 
     /*
+     * The methods below shadow methods on JSObject and are more efficient for
+     * known-native objects.
+     */
+    bool hasAllFlags(js::BaseShape::Flag flags) const {
+        MOZ_ASSERT(flags);
+        return shape_->hasAllObjectFlags(flags);
+    }
+    bool watched() const {
+        return hasAllFlags(js::BaseShape::WATCHED);
+    }
+    bool nonProxyIsExtensible() const {
+        return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);
+    }
+
+    /*
+     * Whether there may be indexed properties on this object, excluding any in
+     * the object's elements.
+     */
+    bool isIndexed() const {
+        return hasAllFlags(js::BaseShape::INDEXED);
+    }
+
+    static bool setHadElementsAccess(JSContext* cx, HandleNativeObject obj) {
+        return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS);
+    }
+
+    /*
+     * Whether SETLELEM was used to access this object. See also the comment near
+     * PropertyTree::MAX_HEIGHT.
+     */
+    bool hadElementsAccess() const {
+        return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
+    }
+
+    // Mark an object as having its 'new' script information cleared.
+    bool wasNewScriptCleared() const {
+        return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
+    }
+    static bool setNewScriptCleared(JSContext* cx, HandleNativeObject obj) {
+        return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED);
+    }
+
+    bool hasInterestingSymbol() const {
+        return hasAllFlags(js::BaseShape::HAS_INTERESTING_SYMBOL);
+    }
+
+    /*
      * Grow or shrink slots immediately before changing the slot span.
      * The number of allocated slots is not stored explicitly, and changes to
      * the slots must track changes in the slot span.
      */
     bool growSlots(JSContext* cx, uint32_t oldCount, uint32_t newCount);
     void shrinkSlots(JSContext* cx, uint32_t oldCount, uint32_t newCount);
 
     /*
--- a/js/src/vm/ObjectGroup-inl.h
+++ b/js/src/vm/ObjectGroup-inl.h
@@ -11,16 +11,17 @@
 
 namespace js {
 
 inline bool
 ObjectGroup::needsSweep()
 {
     // Note: this can be called off thread during compacting GCs, in which case
     // nothing will be running on the active thread.
+    MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
     return generation() != zoneFromAnyThread()->types.generation;
 }
 
 inline void
 ObjectGroup::maybeSweep(AutoClearTypeInferenceStateOnOOM* oom)
 {
     if (needsSweep())
         sweep(oom);
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -315,17 +315,17 @@ JSObject::makeLazyGroup(JSContext* cx, H
 
     // Find flags which need to be specified immediately on the object.
     // Don't track whether singletons are packed.
     ObjectGroupFlags initialFlags = OBJECT_FLAG_SINGLETON | OBJECT_FLAG_NON_PACKED;
 
     if (obj->isIteratedSingleton())
         initialFlags |= OBJECT_FLAG_ITERATED;
 
-    if (obj->isIndexed())
+    if (obj->isNative() && obj->as<NativeObject>().isIndexed())
         initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
 
     if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
         initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
 
     Rooted<TaggedProto> proto(cx, obj->taggedProto());
     ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, obj->getClass(), proto,
                                                            initialFlags);
@@ -492,17 +492,17 @@ ObjectGroup::defaultNewGroup(JSContext* 
                 associated = fun->nonLazyScript()->functionNonDelazifying();
             else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin())
                 associated = fun->lazyScript()->functionNonDelazifying();
             else
                 associated = nullptr;
 
             // If we have previously cleared the 'new' script information for this
             // function, don't try to construct another one.
-            if (associated && associated->wasNewScriptCleared())
+            if (associated && associated->as<JSFunction>().wasNewScriptCleared())
                 associated = nullptr;
 
         } else {
             associated = nullptr;
         }
 
         if (!associated)
             clasp = &PlainObject::class_;
--- a/js/src/vm/Probes-inl.h
+++ b/js/src/vm/Probes-inl.h
@@ -6,18 +6,16 @@
 
 #ifndef vm_Probes_inl_h
 #define vm_Probes_inl_h
 
 #include "vm/Probes.h"
 
 #include "jscntxt.h"
 
-#include "gc/Zone.h"
-
 namespace js {
 
 /*
  * Many probe handlers are implemented inline for minimal performance impact,
  * especially important when no backends are enabled.
  */
 
 inline bool
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -109,23 +109,31 @@ ProxyObject::allocKindForTenure() const
     MOZ_ASSERT(usingInlineValueArray());
     Value priv = const_cast<ProxyObject*>(this)->private_();
     return GetProxyGCObjectKind(getClass(), data.handler, priv);
 }
 
 void
 ProxyObject::setCrossCompartmentPrivate(const Value& priv)
 {
-    *slotOfPrivate() = priv;
+    setPrivate(priv);
 }
 
 void
 ProxyObject::setSameCompartmentPrivate(const Value& priv)
 {
     MOZ_ASSERT(IsObjectValueInCompartment(priv, compartment()));
+    setPrivate(priv);
+}
+
+inline void
+ProxyObject::setPrivate(const Value& priv)
+{
+    MOZ_ASSERT_IF(IsMarkedBlack(this) && priv.isGCThing(),
+                  !JS::GCThingIsMarkedGray(JS::GCCellPtr(priv)));
     *slotOfPrivate() = priv;
 }
 
 void
 ProxyObject::nuke()
 {
     // Select a dead proxy handler based on the properties of this wrapper.
     // Do this before clearing the target.
--- a/js/src/vm/ProxyObject.h
+++ b/js/src/vm/ProxyObject.h
@@ -57,20 +57,16 @@ class ProxyObject : public ShapedObject
 
     const Value& private_() {
         return GetProxyPrivate(this);
     }
 
     void setCrossCompartmentPrivate(const Value& priv);
     void setSameCompartmentPrivate(const Value& priv);
 
-    GCPtrValue* slotOfPrivate() {
-        return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values()->privateSlot);
-    }
-
     JSObject* target() const {
         return const_cast<ProxyObject*>(this)->private_().toObjectOrNull();
     }
 
     const BaseProxyHandler* handler() const {
         return GetProxyHandler(const_cast<ProxyObject*>(this));
     }
 
@@ -98,16 +94,22 @@ class ProxyObject : public ShapedObject
 
     gc::AllocKind allocKindForTenure() const;
 
   private:
     GCPtrValue* reservedSlotPtr(size_t n) {
         return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->reservedSlots->slots[n]);
     }
 
+    GCPtrValue* slotOfPrivate() {
+        return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values()->privateSlot);
+    }
+
+    void setPrivate(const Value& priv);
+
     static bool isValidProxyClass(const Class* clasp) {
         // Since we can take classes from the outside, make sure that they
         // are "sane". They have to quack enough like proxies for us to belive
         // they should be treated as such.
 
         // Proxy classes are not allowed to have call or construct hooks directly. Their
         // callability is instead decided by handler()->isCallable().
         return clasp->isProxy() &&
@@ -117,16 +119,18 @@ class ProxyObject : public ShapedObject
 
   public:
     static unsigned grayLinkReservedSlot(JSObject* obj);
 
     void renew(const BaseProxyHandler* handler, const Value& priv);
 
     static void trace(JSTracer* trc, JSObject* obj);
 
+    static void traceEdgeToTarget(JSTracer* trc, ProxyObject* obj);
+
     void nuke();
 
     // There is no class_ member to force specialization of JSObject::is<T>().
     // The implementation in JSObject is incorrect for proxies since it doesn't
     // take account of the handler type.
     static const Class proxyClass;
 };
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -1314,17 +1314,17 @@ RegExpZone::get(JSContext* cx, HandleAto
 
 size_t
 RegExpZone::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return set_.sizeOfExcludingThis(mallocSizeOf);
 }
 
 RegExpZone::RegExpZone(Zone* zone)
-  : set_(zone, zone->runtimeFromActiveCooperatingThread())
+  : set_(zone, zone)
 {}
 
 /* Functions */
 
 JSObject*
 js::CloneRegExpObject(JSContext* cx, Handle<RegExpObject*> regex)
 {
     // Unlike RegExpAlloc, all clones must use |regex|'s group.
--- a/js/src/vm/RegExpShared.h
+++ b/js/src/vm/RegExpShared.h
@@ -255,17 +255,17 @@ class RegExpZone
             return l.atom == r.atom && l.flag == r.flag;
         }
     };
 
     /*
      * The set of all RegExpShareds in the zone. On every GC, every RegExpShared
      * that was not marked is deleted and removed from the set.
      */
-    using Set = JS::WeakCache<JS::GCHashSet<ReadBarriered<RegExpShared*>, Key, RuntimeAllocPolicy>>;
+    using Set = JS::WeakCache<JS::GCHashSet<ReadBarriered<RegExpShared*>, Key, ZoneAllocPolicy>>;
     Set set_;
 
   public:
     explicit RegExpZone(Zone* zone);
 
     ~RegExpZone() {
         MOZ_ASSERT_IF(set_.initialized(), set_.empty());
     }
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -213,22 +213,22 @@ JSRuntime::init(JSContext* cx, uint32_t 
 
     defaultFreeOp_ = js_new<js::FreeOp>(this);
     if (!defaultFreeOp_)
         return false;
 
     if (!gc.init(maxbytes, maxNurseryBytes))
         return false;
 
-    ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this, nullptr));
+    ScopedJSDeletePtr<Zone> atomsZone(js_new<Zone>(this, nullptr));
     if (!atomsZone || !atomsZone->init(true))
         return false;
 
     JS::CompartmentOptions options;
-    ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
+    ScopedJSDeletePtr<JSCompartment> atomsCompartment(js_new<JSCompartment>(atomsZone.get(), options));
     if (!atomsCompartment || !atomsCompartment->init(nullptr))
         return false;
 
     gc.atomsZone = atomsZone.get();
     if (!atomsZone->compartments().append(atomsCompartment.get()))
         return false;
 
     atomsCompartment->setIsSystem(true);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -43,17 +43,16 @@
 #include "js/UniquePtr.h"
 #include "js/Vector.h"
 #include "threading/Thread.h"
 #include "vm/Caches.h"
 #include "vm/CodeCoverage.h"
 #include "vm/CommonPropertyNames.h"
 #include "vm/DateTime.h"
 #include "vm/GeckoProfiler.h"
-#include "vm/MallocProvider.h"
 #include "vm/Scope.h"
 #include "vm/SharedImmutableStringsCache.h"
 #include "vm/Stack.h"
 #include "vm/Stopwatch.h"
 #include "vm/Symbol.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)
@@ -976,16 +975,18 @@ struct JSRuntime : public js::MallocProv
      */
     JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
                                        void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
 
     /*  onOutOfMemory but can call OnLargeAllocationFailure. */
     JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
                                             void* reallocPtr = nullptr);
 
+    static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
+
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* runtime);
 
   private:
     // Settings for how helper threads can be used.
     mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
     mozilla::Atomic<bool> parallelParsingEnabled_;
 
     js::ActiveThreadData<bool> autoWritableJitCodeActive_;
@@ -1012,48 +1013,16 @@ struct JSRuntime : public js::MallocProv
         autoWritableJitCodeActive_ = b;
     }
 
     /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
     js::ActiveThreadData<JS::OutOfMemoryCallback> oomCallback;
     js::ActiveThreadData<void*> oomCallbackData;
 
     /*
-     * These variations of malloc/calloc/realloc will call the
-     * large-allocation-failure callback on OOM and retry the allocation.
-     */
-    static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
-
-    template <typename T>
-    T* pod_callocCanGC(size_t numElems) {
-        T* p = pod_calloc<T>(numElems);
-        if (MOZ_LIKELY(!!p))
-            return p;
-        size_t bytes;
-        if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
-            reportAllocationOverflow();
-            return nullptr;
-        }
-        return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
-    }
-
-    template <typename T>
-    T* pod_reallocCanGC(T* p, size_t oldSize, size_t newSize) {
-        T* p2 = pod_realloc<T>(p, oldSize, newSize);
-        if (MOZ_LIKELY(!!p2))
-            return p2;
-        size_t bytes;
-        if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) {
-            reportAllocationOverflow();
-            return nullptr;
-        }
-        return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p));
-    }
-
-    /*
      * Debugger.Memory functions like takeCensus use this embedding-provided
      * function to assess the size of malloc'd blocks of memory.
      */
     js::ActiveThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
 
     /* Last time at which an animation was played for this runtime. */
     mozilla::Atomic<int64_t> lastAnimationTime;
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -600,16 +600,18 @@ FrameIter::popInterpreterFrame()
         popActivation();
     else
         data_.pc_ = data_.interpFrames_.pc();
 }
 
 void
 FrameIter::settleOnActivation()
 {
+    MOZ_ASSERT(!data_.cx_->inUnsafeCallWithABI);
+
     while (true) {
         if (data_.activations_.done()) {
             data_.state_ = DONE;
             return;
         }
 
         Activation* activation = data_.activations_.activation();
 
--- a/js/src/vm/Stopwatch.cpp
+++ b/js/src/vm/Stopwatch.cpp
@@ -12,20 +12,18 @@
 
 #if defined(XP_WIN)
 #include <processthreadsapi.h>
 #endif // defined(XP_WIN)
 
 #include "jscompartment.h"
 #include "jswin.h"
 
-#include "gc/Zone.h"
 #include "vm/Runtime.h"
 
-
 namespace js {
 
 bool
 PerformanceMonitoring::addRecentGroup(PerformanceGroup* group)
 {
     if (group->isUsedInThisIteration())
         return true;
 
--- a/js/src/vm/TaggedProto.cpp
+++ b/js/src/vm/TaggedProto.cpp
@@ -5,19 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/TaggedProto.h"
 
 #include "jsfun.h"
 #include "jsobj.h"
 
 #include "gc/Barrier.h"
-#include "gc/Zone.h"
-
-#include "vm/Caches-inl.h"
 
 namespace js {
 
 /* static */ void
 InternalBarrierMethods<TaggedProto>::preBarrier(TaggedProto& proto)
 {
     InternalBarrierMethods<JSObject*>::preBarrier(proto.toObjectOrNull());
 }
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1311,20 +1311,18 @@ js::EnsureTrackPropertyTypes(JSContext* 
 {
     id = IdToTypeId(id);
 
     if (obj->isSingleton()) {
         AutoEnterAnalysis enter(cx);
         if (obj->hasLazyGroup()) {
             AutoEnterOOMUnsafeRegion oomUnsafe;
             RootedObject objRoot(cx, obj);
-            if (!JSObject::getGroup(cx, objRoot)) {
+            if (!JSObject::getGroup(cx, objRoot))
                 oomUnsafe.crash("Could not allocate ObjectGroup in EnsureTrackPropertyTypes");
-                return;
-            }
         }
         if (!obj->group()->unknownProperties() && !obj->group()->getProperty(cx, obj, id)) {
             MOZ_ASSERT(obj->group()->unknownProperties());
             return;
         }
     }
 
     MOZ_ASSERT(obj->group()->unknownProperties() || TrackPropertyTypes(obj, id));
@@ -3041,17 +3039,17 @@ ObjectGroup::clearNewScript(JSContext* c
 
     if (!replacement) {
         // Invalidate any Ion code constructing objects of this type.
         setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
 
         // Mark the constructing function as having its 'new' script cleared, so we
         // will not try to construct another one later.
         RootedFunction fun(cx, newScript->function());
-        if (!JSObject::setNewScriptCleared(cx, fun))
+        if (!NativeObject::setNewScriptCleared(cx, fun))
             cx->recoverFromOutOfMemory();
     }
 
     detachNewScript(/* writeBarrier = */ true, replacement);
 
     if (!cx->helperThread()) {
         bool found = newScript->rollbackPartiallyInitializedObjects(cx, this);
 
@@ -4423,16 +4421,18 @@ ObjectGroup::sweep(AutoClearTypeInferenc
     } else {
         MOZ_RELEASE_ASSERT(!propertySet);
     }
 }
 
 /* static */ void
 JSScript::maybeSweepTypes(AutoClearTypeInferenceStateOnOOM* oom)
 {
+    MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
+
     if (!types_ || typesGeneration() == zone()->types.generation)
         return;
 
     setTypesGeneration(zone()->types.generation);
 
     AssertGCStateForSweep(zone());
 
     Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM;
@@ -4606,16 +4606,17 @@ TypeZone::clearAllNewScriptsOnOOM()
             group->maybeClearNewScriptOnOOM();
     }
 }
 
 AutoClearTypeInferenceStateOnOOM::AutoClearTypeInferenceStateOnOOM(Zone* zone)
   : zone(zone), oom(false)
 {
     MOZ_RELEASE_ASSERT(CurrentThreadCanAccessZone(zone));
+    MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
     zone->types.setSweepingTypes(true);
 }
 
 AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM()
 {
     zone->types.setSweepingTypes(false);
 
     if (oom) {
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -695,16 +695,21 @@ class ConstraintTypeSet : public TypeSet
     }
 
     /*
      * Add a type to this set, calling any constraint handlers if this is a new
      * possible type.
      */
     void addType(JSContext* cx, Type type);
 
+    /* Generalize to any type. */
+    void makeUnknown(JSContext* cx) {
+        addType(cx, UnknownType());
+    }
+
     // Trigger a post barrier when writing to this set, if necessary.
     // addType(cx, type) takes care of this automatically.
     void postWriteBarrier(JSContext* cx, Type type);
 
     /* Add a new constraint to this set. */
     bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
 
     inline void sweep(JS::Zone* zone, AutoClearTypeInferenceStateOnOOM& oom);
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -14,16 +14,18 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 
 #include "jsarray.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 
+#include "gc/Zone.h"
+
 #include "jit/AtomicOperations.h"
 
 #include "js/Conversions.h"
 #include "js/Value.h"
 
 #include "vm/NativeObject.h"
 
 namespace js {
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -7,17 +7,16 @@
 #ifndef vm_TypedArrayObject_h
 #define vm_TypedArrayObject_h
 
 #include "mozilla/Attributes.h"
 
 #include "jsobj.h"
 
 #include "gc/Barrier.h"
-#include "gc/Zone.h"
 #include "js/Class.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/SharedArrayObject.h"
 
 #define JS_FOR_EACH_TYPED_ARRAY(macro) \
     macro(int8_t, Int8) \
     macro(uint8_t, Uint8) \
     macro(int16_t, Int16) \
--- a/js/src/vm/WeakMapPtr.cpp
+++ b/js/src/vm/WeakMapPtr.cpp
@@ -59,17 +59,18 @@ JS::WeakMapPtr<K, V>::destroy()
     ptr = nullptr;
 }
 
 template <typename K, typename V>
 bool
 JS::WeakMapPtr<K, V>::init(JSContext* cx)
 {
     MOZ_ASSERT(!initialized());
-    typename details::Utils<K, V>::PtrType map = cx->runtime()->new_<typename details::Utils<K,V>::Type>(cx);
+    typename details::Utils<K, V>::PtrType map =
+        cx->zone()->new_<typename details::Utils<K,V>::Type>(cx);
     if (!map || !map->init())
         return false;
     ptr = map;
     return true;
 }
 
 template <typename K, typename V>
 void
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -4465,18 +4465,16 @@ CheckSharedArrayAtomicAccess(FunctionVal
       case Scalar::Int32:
       case Scalar::Uint8:
       case Scalar::Uint16:
       case Scalar::Uint32:
         return true;
       default:
         return f.failf(viewName, "not an integer array");
     }
-
-    return true;
 }
 
 static bool
 WriteAtomicOperator(FunctionValidator& f, MozOp opcode, Scalar::Type viewType)
 {
     return f.encoder().writeOp(opcode) &&
            f.encoder().writeFixedU8(viewType);
 }
--- a/js/src/wasm/WasmDebug.cpp
+++ b/js/src/wasm/WasmDebug.cpp
@@ -412,17 +412,17 @@ DebugState::getOrCreateBreakpointSite(JS
     WasmBreakpointSite* site;
     if (!breakpointSites_.initialized() && !breakpointSites_.init()) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     WasmBreakpointSiteMap::AddPtr p = breakpointSites_.lookupForAdd(offset);
     if (!p) {
-        site = cx->runtime()->new_<WasmBreakpointSite>(this, offset);
+        site = cx->zone()->new_<WasmBreakpointSite>(this, offset);
         if (!site || !breakpointSites_.add(p, offset, site)) {
             js_delete(site);
             ReportOutOfMemory(cx);
             return nullptr;
         }
     } else {
         site = p->value();
     }
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -87,17 +87,16 @@ public:
     MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
   }
 #endif
 
   virtual bool CreateWebRenderCommands(
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
-    nsTArray<WebRenderParentCommand>& aParentCommands,
     mozilla::layers::WebRenderLayerManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) override;
 
   virtual LayerState GetLayerState(
     nsDisplayListBuilder* aBuilder,
     LayerManager* aManager,
     const ContainerLayerParameters& aParameters) override;
 
@@ -194,17 +193,16 @@ nsDisplayButtonBoxShadowOuter::BuildLaye
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands(
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const StackingContextHelper& aSc,
-  nsTArray<WebRenderParentCommand>& aParentCommands,
   mozilla::layers::WebRenderLayerManager* aManager,
   nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) !=
         LAYER_ACTIVE) {
       return false;
@@ -295,17 +293,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
 private:
   nsButtonFrameRenderer* mBFR;
   Maybe<nsCSSBorderRenderer> mBorderRenderer;
 };
 
@@ -363,17 +360,16 @@ nsDisplayButtonBorder::BuildLayer(nsDisp
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayButtonBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                const StackingContextHelper& aSc,
-                                               nsTArray<WebRenderParentCommand>& aParentCommands,
                                                mozilla::layers::WebRenderLayerManager* aManager,
                                                nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -460,17 +456,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
    virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
                                         const StackingContextHelper& aSc,
-                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                         mozilla::layers::WebRenderLayerManager* aManager,
                                         nsDisplayListBuilder* aDisplayListBuilder) override;
   NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
 private:
   nsButtonFrameRenderer* mBFR;
   Maybe<nsCSSBorderRenderer> mBorderRenderer;
 };
 
@@ -547,17 +542,16 @@ nsDisplayButtonForeground::BuildLayer(ns
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayButtonForeground::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                    mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                    const StackingContextHelper& aSc,
-                                                   nsTArray<WebRenderParentCommand>& aParentCommands,
                                                    mozilla::layers::WebRenderLayerManager* aManager,
                                                    nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -224,17 +224,16 @@ public:
     MOZ_ASSERT(IsTextType());
   }
 
   void
   CreateWebRenderCommands(nsDisplayItem* aItem,
                           wr::DisplayListBuilder& aBuilder,
                           wr::IpcResourceUpdateQueue& aResources,
                           const layers::StackingContextHelper& aSc,
-                          nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                           mozilla::layers::WebRenderLayerManager* aManager,
                           nsDisplayListBuilder* aDisplayListBuilder);
 
   DrawResult
   Paint(gfxContext& aRenderingContext, nsPoint aPt,
         const nsRect& aDirtyRect, uint32_t aFlags,
         bool aDisableSubpixelAA, nsIFrame* aFrame);
 
@@ -274,26 +273,24 @@ public:
   IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags);
 
 private:
   void
   CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                   wr::DisplayListBuilder& aBuilder,
                                   wr::IpcResourceUpdateQueue& aResources,
                                   const layers::StackingContextHelper& aSc,
-                                  nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                   mozilla::layers::WebRenderLayerManager* aManager,
                                   nsDisplayListBuilder* aDisplayListBuilder);
 
   void
   CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                  wr::DisplayListBuilder& aBuilder,
                                  wr::IpcResourceUpdateQueue& aResources,
                                  const layers::StackingContextHelper& aSc,
-                                 nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                  mozilla::layers::WebRenderLayerManager* aManager,
                                  nsDisplayListBuilder* aDisplayListBuilder);
 
   void
   CreateWebRenderCommandsForText(nsDisplayItem* aItem,
                                  wr::DisplayListBuilder& aBuilder,
                                  wr::IpcResourceUpdateQueue& aResources,
                                  const layers::StackingContextHelper& aSc,
@@ -325,28 +322,25 @@ private:
   int32_t mListStyleType;
 };
 
 void
 BulletRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
                                         wr::DisplayListBuilder& aBuilder,
                                         wr::IpcResourceUpdateQueue& aResources,
                                         const layers::StackingContextHelper& aSc,
-                                        nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                         mozilla::layers::WebRenderLayerManager* aManager,
                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (IsImageType()) {
     CreateWebRenderCommandsForImage(aItem, aBuilder, aResources,
-                                    aSc, aParentCommands,
-                                    aManager, aDisplayListBuilder);
+                                    aSc, aManager, aDisplayListBuilder);
   } else if (IsPathType()) {
     CreateWebRenderCommandsForPath(aItem, aBuilder, aResources,
-                                   aSc, aParentCommands,
-                                   aManager, aDisplayListBuilder);
+                                   aSc, aManager, aDisplayListBuilder);
   } else {
     MOZ_ASSERT(IsTextType());
     CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
                                    aManager, aDisplayListBuilder);
   }
 }
 
 DrawResult
@@ -453,17 +447,16 @@ BulletRenderer::IsImageContainerAvailabl
   return mImage->IsImageContainerAvailable(aManager, aFlags);
 }
 
 void
 BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                                 wr::DisplayListBuilder& aBuilder,
                                                 wr::IpcResourceUpdateQueue& aResources,
                                                 const layers::StackingContextHelper& aSc,
-                                                nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                 mozilla::layers::WebRenderLayerManager* aManager,
                                                 nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(IsImageType());
 
   if (!mImage) {
      return;
   }
@@ -474,17 +467,17 @@ BulletRenderer::CreateWebRenderCommandsF
 
   RefPtr<layers::ImageContainer> container =
     mImage->GetImageContainer(aManager, flags);
   if (!container) {
     return;
   }
 
   gfx::IntSize size;
-  Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aSc, size);
+  Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aResources, aSc, size);
   if (key.isNothing()) {
     return;
   }
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel);
   wr::LayoutRect dest = aSc.ToRelativeLayoutRect(destRect);
 
@@ -494,17 +487,16 @@ BulletRenderer::CreateWebRenderCommandsF
                      key.value());
 }
 
 void
 BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                wr::IpcResourceUpdateQueue& aResources,
                                                const layers::StackingContextHelper& aSc,
-                                               nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                mozilla::layers::WebRenderLayerManager* aManager,
                                                nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(IsPathType());
 
   if (!aManager->PushItemAsImage(aItem, aBuilder, aResources, aSc, aDisplayListBuilder)) {
     NS_WARNING("Fail to create WebRender commands for Bullet path.");
   }
@@ -562,17 +554,16 @@ public:
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aParameters) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue&,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) override {
     aOutFrames->AppendElement(mFrame);
   }
@@ -667,31 +658,30 @@ nsDisplayBullet::BuildLayer(nsDisplayLis
 
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayBullet::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                          wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
-                                         nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
   }
 
   if (!mBulletRenderer)
     return false;
 
-  mBulletRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc, aParentCommands,
+  mBulletRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
                                            aManager, aDisplayListBuilder);
   return true;
 }
 
 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
                             gfxContext* aCtx)
 {
   uint32_t flags = imgIContainer::FLAG_NONE;
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -304,17 +304,16 @@ nsDisplayCanvasBackgroundColor::BuildLay
 
   return layer.forget();
 }
 
 bool
 nsDisplayCanvasBackgroundColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                         const StackingContextHelper& aSc,
-                                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                                         WebRenderLayerManager* aManager,
                                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -156,17 +156,16 @@ public:
     aOutFrames->AppendElement(mFrame);
   }
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override
   {
     if (ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowCanvasBackgroundColorLayers) ||
         ForceActiveLayers()) {
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -41,17 +41,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      gfxContext* aCtx) override;
 
   NS_DISPLAY_DECL_NAME("ColumnRule", TYPE_COLUMN_RULE);
 
 private:
@@ -103,17 +102,16 @@ nsDisplayColumnRule::BuildLayer(nsDispla
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayColumnRule::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                              mozilla::wr::IpcResourceUpdateQueue& aResources,
                                              const StackingContextHelper& aSc,
-                                             nsTArray<WebRenderParentCommand>& aParentCommands,
                                              mozilla::layers::WebRenderLayerManager* aManager,
                                              nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     RefPtr<gfxContext> screenRefCtx = gfxContext::CreateOrNull(
       gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
 
     static_cast<nsColumnSetFrame*>(mFrame)->
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -122,17 +122,16 @@ public:
   {
     return static_cast<nsHTMLCanvasFrame*>(mFrame)->
       BuildLayer(aBuilder, aManager, this, aContainerParameters);
   }
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override
   {
     HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(mFrame->GetContent());
     switch(element->GetCurrentContextType()) {
       case CanvasContextType::Canvas2D:
       case CanvasContextType::WebGL1:
       case CanvasContextType::WebGL2:
@@ -150,17 +149,17 @@ public:
           }
         }
 
         data->UpdateCompositableClient();
 
         // Push IFrame for async image pipeline.
         // XXX Remove this once partial display list update is supported.
 
-        /* ScrollingLayersHelper scroller(this, aBuilder, aSc); */
+        /* ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc); */
         nsIntSize canvasSizeInPx = data->GetSize();
         IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx);
         nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx);
 
         nsRect area = mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame();
         nsRect dest =
           nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio,
                                                mFrame->StylePosition());
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1696,17 +1696,16 @@ nsDisplayImage::BuildLayer(nsDisplayList
   ConfigureLayer(layer, aParameters);
   return layer.forget();
 }
 
 bool
 nsDisplayImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
                                         const StackingContextHelper& aSc,
-                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                         WebRenderLayerManager* aManager,
                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (!CanOptimizeToImageLayer(aManager, aDisplayListBuilder)) {
     return false;
   }
 
   uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
@@ -1720,17 +1719,17 @@ nsDisplayImage::CreateWebRenderCommands(
     return false;
   }
 
 
   const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
   const LayoutDeviceRect destRect(
     LayoutDeviceIntRect::FromAppUnits(GetDestRect(), factor));
   const LayerRect dest = ViewAs<LayerPixel>(destRect, PixelCastJustification::WebRenderHasUnitResolution);
-  return aManager->PushImage(this, container, aBuilder, aSc, dest);
+  return aManager->PushImage(this, container, aBuilder, aResources, aSc, dest);
 }
 
 DrawResult
 nsImageFrame::PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
                          const nsRect& aDirtyRect, imgIContainer* aImage,
                          uint32_t aFlags)
 {
   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -457,17 +457,16 @@ public:
                                    bool* aSnap) const override;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
 private:
   nsCOMPtr<imgIContainer> mImage;
   nsCOMPtr<imgIContainer> mPrevImage;
 };
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -1042,17 +1042,16 @@ nsDisplayPlugin::GetOpaqueRegion(nsDispl
 
   return result;
 }
 
 bool
 nsDisplayPlugin::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
-                                         nsTArray<WebRenderParentCommand>& aParentCommands,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
   return static_cast<nsPluginFrame*>(mFrame)->CreateWebRenderCommands(this,
                                                                       aBuilder,
                                                                       aResources,
                                                                       aSc,
                                                                       aManager,
@@ -1441,17 +1440,17 @@ nsPluginFrame::CreateWebRenderCommands(n
 
   RefPtr<LayerManager> lm = aDisplayListBuilder->GetWidgetLayerManager();
   if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) {
     mDidCompositeObserver = MakeUnique<PluginFrameDidCompositeObserver>(mInstanceOwner, lm);
   }
   lm->AddDidCompositeObserver(mDidCompositeObserver.get());
 
   LayerRect dest(r.x, r.y, size.width, size.height);
-  return aManager->PushImage(aItem, container, aBuilder, aSc, dest);
+  return aManager->PushImage(aItem, container, aBuilder, aResources, aSc, dest);
 }
 
 
 already_AddRefed<Layer>
 nsPluginFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
                           LayerManager* aManager,
                           nsDisplayItem* aItem,
                           const ContainerLayerParameters& aContainerParameters)
--- a/layout/generic/nsPluginFrame.h
+++ b/layout/generic/nsPluginFrame.h
@@ -389,14 +389,13 @@ public:
   {
     return static_cast<nsPluginFrame*>(mFrame)->GetLayerState(aBuilder,
                                                               aManager);
   }
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 };
 
 #endif /* nsPluginFrame_h___ */
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4971,17 +4971,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      gfxContext* aCtx) override;
   NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override
   {
@@ -5171,17 +5170,16 @@ nsDisplayText::Paint(nsDisplayListBuilde
                                                     mDisableSubpixelAA);
   RenderToContext(aCtx, nullptr, aBuilder);
 }
 
 bool
 nsDisplayText::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -429,17 +429,16 @@ public:
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("Video", TYPE_VIDEO)
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const mozilla::layers::StackingContextHelper& aSc,
-                                       nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override
   {
     nsRect area = Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
     HTMLVideoElement* element = static_cast<HTMLVideoElement*>(Frame()->GetContent());
 
     nsIntSize videoSizeInPx;
     if (NS_FAILED(element->GetVideoSize(&videoSizeInPx)) || area.IsEmpty()) {
@@ -482,17 +481,17 @@ public:
     VideoInfo::Rotation rotationDeg = element->RotationDegrees();
     IntSize scaleHint(static_cast<int32_t>(destGFXRect.Width()),
                       static_cast<int32_t>(destGFXRect.Height()));
     // scaleHint is set regardless of rotation, so swap w/h if needed.
     SwapScaleWidthHeightForRotation(scaleHint, rotationDeg);
     container->SetScaleHint(scaleHint);
 
     LayerRect rect(destGFXRect.x, destGFXRect.y, destGFXRect.width, destGFXRect.height);
-    return aManager->PushImage(this, container, aBuilder, aSc, rect);
+    return aManager->PushImage(this, container, aBuilder, aResources, aSc, rect);
   }
 
   // It would be great if we could override GetOpaqueRegion to return nonempty here,
   // but it's probably not safe to do so in general. Video frames are
   // updated asynchronously from decoder threads, and it's possible that
   // we might have an opaque video frame when GetOpaqueRegion is called, but
   // when we come to paint, the video frame is transparent or has gone
   // away completely (e.g. because of a decoder error). The problem would
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -380,17 +380,16 @@ nsDisplayRemote::BuildLayer(nsDisplayLis
   }
   return layer.forget();
 }
 
 bool
 nsDisplayRemote::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
-                                         nsTArray<WebRenderParentCommand>& aParentCommands,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(aManager->IsLayersFreeTransaction());
 
   mOffset = mozilla::layout::GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
 
   mozilla::LayoutDeviceRect visible = mozilla::LayoutDeviceRect::FromAppUnits(
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -159,17 +159,16 @@ public:
 
   virtual already_AddRefed<Layer>
   BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
              const ContainerLayerParameters& aContainerParameters) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual bool UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                 mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
 
   uint64_t GetRemoteLayersId() const;
 
   NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1989,18 +1989,18 @@ nsCSSRendering::CanBuildWebRenderDisplay
   }
 
   return false;
 }
 
 DrawResult
 nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
                                                              mozilla::wr::DisplayListBuilder& aBuilder,
+                                                             mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                              const mozilla::layers::StackingContextHelper& aSc,
-                                                             nsTArray<WebRenderParentCommand>& aParentCommands,
                                                              mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                                              mozilla::layers::WebRenderLayerManager* aManager,
                                                              nsDisplayItem* aItem)
 {
   NS_PRECONDITION(aParams.frame,
                   "Frame is expected to be provided to BuildWebRenderDisplayItemsForStyleImageLayer");
 
   nsStyleContext *sc;
@@ -2016,17 +2016,17 @@ nsCSSRendering::BuildWebRenderDisplayIte
 
     nsIContent* content = aParams.frame->GetContent();
     if (!content || content->GetParent()) {
       return DrawResult::SUCCESS;
     }
 
     sc = aParams.frame->StyleContext();
   }
-  return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aSc, aParentCommands,
+  return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aResources, aSc,
                                                             aLayer, aManager, aItem,
                                                             sc, *aParams.frame->StyleBorder());
 }
 
 static bool
 IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
 {
   if (aBorder.GetComputedBorder().Side(aSide) == 0)
@@ -2738,18 +2738,18 @@ nsCSSRendering::PaintStyleImageLayerWith
   }
 
   return result;
 }
 
 DrawResult
 nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
                                                                    mozilla::wr::DisplayListBuilder& aBuilder,
+                                                                   mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                                    const mozilla::layers::StackingContextHelper& aSc,
-                                                                   nsTArray<WebRenderParentCommand>& aParentCommands,
                                                                    mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                                                    mozilla::layers::WebRenderLayerManager* aManager,
                                                                    nsDisplayItem* aItem,
                                                                    nsStyleContext *aBackgroundSC,
                                                                    const nsStyleBorder& aBorder)
 {
   MOZ_ASSERT(!(aParams.paintFlags & PAINTBG_MASK_IMAGE));
 
@@ -2782,17 +2782,17 @@ nsCSSRendering::BuildWebRenderDisplayIte
   DrawResult result = DrawResult::SUCCESS;
   nsBackgroundLayerState state =
     PrepareImageLayer(&aParams.presCtx, aParams.frame,
                       aParams.paintFlags, paintBorderArea,
                       clipState.mBGClipArea, layer, nullptr);
   result &= state.mImageRenderer.PrepareResult();
   if (!state.mFillArea.IsEmpty()) {
     return state.mImageRenderer.BuildWebRenderDisplayItemsForLayer(&aParams.presCtx,
-                                     aBuilder, aSc, aParentCommands,
+                                     aBuilder, aResources, aSc,
                                      aLayer, aManager, aItem,
                                      state.mDestArea, state.mFillArea,
                                      state.mAnchor + paintBorderArea.TopLeft(),
                                      clipState.mDirtyRectInAppUnits,
                                      state.mRepeatSize, aParams.opacity);
   }
 
   return result;
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -497,26 +497,26 @@ struct nsCSSRendering {
 
   static bool CanBuildWebRenderDisplayItemsForStyleImageLayer(LayerManager* aManager,
                                                               nsPresContext& aPresCtx,
                                                               nsIFrame *aFrame,
                                                               const nsStyleBackground* aBackgroundStyle,
                                                               int32_t aLayer);
   static DrawResult BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
                                                                  mozilla::wr::DisplayListBuilder& aBuilder,
+                                                                 mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                                  const mozilla::layers::StackingContextHelper& aSc,
-                                                                 nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
                                                                  mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                                                  mozilla::layers::WebRenderLayerManager* aManager,
                                                                  nsDisplayItem* aItem);
 
   static DrawResult BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
                                                                        mozilla::wr::DisplayListBuilder& aBuilder,
+                                                                       mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                                        const mozilla::layers::StackingContextHelper& aSc,
-                                                                       nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
                                                                        mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                                                        mozilla::layers::WebRenderLayerManager* aManager,
                                                                        nsDisplayItem* aItem,
                                                                        nsStyleContext *mBackgroundSC,
                                                                        const nsStyleBorder& aBorder);
 
   /**
    * Returns the rectangle covered by the given background layer image, taking
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2925,17 +2925,16 @@ nsDisplaySolidColor::WriteDebugInfo(std:
           << (int)NS_GET_B(mColor) << ","
           << (int)NS_GET_A(mColor) << ")";
 }
 
 bool
 nsDisplaySolidColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                              mozilla::wr::IpcResourceUpdateQueue& aResources,
                                              const StackingContextHelper& aSc,
-                                             nsTArray<WebRenderParentCommand>& aParentCommands,
                                              mozilla::layers::WebRenderLayerManager* aManager,
                                              nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -2983,17 +2982,16 @@ nsDisplaySolidColorRegion::WriteDebugInf
           << int(mColor.b * 255) << ","
           << mColor.a << ")";
 }
 
 bool
 nsDisplaySolidColorRegion::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                    mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                    const StackingContextHelper& aSc,
-                                                   nsTArray<WebRenderParentCommand>& aParentCommands,
                                                    mozilla::layers::WebRenderLayerManager* aManager,
                                                    nsDisplayListBuilder* aDisplayListBuilder)
 {
   for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
     nsRect rect = iter.Get();
     LayoutDeviceRect layerRects = LayoutDeviceRect::FromAppUnits(
       rect, mFrame->PresContext()->AppUnitsPerDevPixel());
     wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(layerRects);
@@ -3619,17 +3617,16 @@ nsDisplayBackgroundImage::CanBuildWebRen
                                                                          mBackgroundStyle,
                                                                          mLayer);
 }
 
 bool
 nsDisplayBackgroundImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                   mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                   const StackingContextHelper& aSc,
-                                                  nsTArray<WebRenderParentCommand>& aParentCommands,
                                                   WebRenderLayerManager* aManager,
                                                   nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -3641,17 +3638,17 @@ nsDisplayBackgroundImage::CreateWebRende
   CheckForBorderItem(this, mImageFlags);
   nsCSSRendering::PaintBGParams params =
     nsCSSRendering::PaintBGParams::ForSingleLayer(*StyleFrame()->PresContext(),
                                                   mVisibleRect, mBackgroundRect,
                                                   StyleFrame(), mImageFlags, mLayer,
                                                   CompositionOp::OP_OVER);
   params.bgClipRect = &mBounds;
   DrawResult result =
-    nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(params, aBuilder, aSc, aParentCommands, nullptr, aManager, this);
+    nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(params, aBuilder, aResources, aSc, nullptr, aManager, this);
   nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
 
   return true;
 }
 
 void
 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aRect,
@@ -4244,17 +4241,16 @@ nsDisplayBackgroundColor::BuildLayer(nsD
 
   return layer.forget();
 }
 
 bool
 nsDisplayBackgroundColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                   mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                   const StackingContextHelper& aSc,
-                                                  nsTArray<WebRenderParentCommand>& aParentCommands,
                                                   mozilla::layers::WebRenderLayerManager* aManager,
                                                   nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -4465,17 +4461,16 @@ nsDisplayOutline::BuildLayer(nsDisplayLi
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayOutline::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                           mozilla::wr::IpcResourceUpdateQueue& aResources,
                                           const StackingContextHelper& aSc,
-                                          nsTArray<WebRenderParentCommand>& aParentCommands,
                                           mozilla::layers::WebRenderLayerManager* aManager,
                                           nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -4749,17 +4744,16 @@ nsDisplayCaret::Paint(nsDisplayListBuild
   // need to check for the caret's visibility.
   mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
 }
 
 bool
 nsDisplayCaret::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
                                         const StackingContextHelper& aSc,
-                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                         mozilla::layers::WebRenderLayerManager* aManager,
                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -5015,41 +5009,40 @@ nsDisplayBorder::BuildLayer(nsDisplayLis
     return layer.forget();
   }
 }
 
 bool
 nsDisplayBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
-                                         nsTArray<WebRenderParentCommand>& aParentCommands,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
   }
 
   if (mBorderImageRenderer) {
-    CreateBorderImageWebRenderCommands(aBuilder, aSc, aParentCommands,
+    CreateBorderImageWebRenderCommands(aBuilder, aResources, aSc,
                                        aManager, aDisplayListBuilder);
   } else if (mBorderRenderer) {
     mBorderRenderer->CreateWebRenderCommands(aBuilder, aResources, aSc);
   }
 
   return true;
 };
 
 void
 nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                    mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                     const StackingContextHelper& aSc,
-                                                    nsTArray<WebRenderParentCommand>& aParentCommands,
                                                     mozilla::layers::WebRenderLayerManager* aManager,
                                                     nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(mBorderImageRenderer);
   if (!mBorderImageRenderer->mImageRenderer.IsReady()) {
     return;
   }
 
@@ -5083,17 +5076,17 @@ nsDisplayBorder::CreateBorderImageWebRen
 
       RefPtr<imgIContainer> img = mBorderImageRenderer->mImageRenderer.GetImage();
       RefPtr<layers::ImageContainer> container = img->GetImageContainer(aManager, flags);
       if (!container) {
         return;
       }
 
       gfx::IntSize size;
-      Maybe<wr::ImageKey> key = aManager->CreateImageKey(this, container, aBuilder, aSc, size);
+      Maybe<wr::ImageKey> key = aManager->CreateImageKey(this, container, aBuilder, aResources, aSc, size);
       if (key.isNothing()) {
         return;
       }
 
       aBuilder.PushBorderImage(dest,
                                clip,
                                wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
                                key.value(),
@@ -5383,17 +5376,16 @@ nsDisplayBoxShadowOuter::CanBuildWebRend
 
   return true;
 }
 
 bool
 nsDisplayBoxShadowOuter::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                  mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                  const StackingContextHelper& aSc,
-                                                 nsTArray<WebRenderParentCommand>& aParentCommands,
                                                  mozilla::layers::WebRenderLayerManager* aManager,
                                                  nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -5643,17 +5635,16 @@ nsDisplayBoxShadowInner::CreateInsetBoxS
     }
   }
 }
 
 bool
 nsDisplayBoxShadowInner::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                  mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                  const StackingContextHelper& aSc,
-                                                 nsTArray<WebRenderParentCommand>& aParentCommands,
                                                  mozilla::layers::WebRenderLayerManager* aManager,
                                                  nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
@@ -5909,17 +5900,16 @@ nsDisplayWrapList::SetReferenceFrame(con
   mReferenceFrame = aFrame;
   mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
 }
 
 bool
 nsDisplayWrapList::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                            mozilla::wr::IpcResourceUpdateQueue& aResources,
                                            const StackingContextHelper& aSc,
-                                           nsTArray<WebRenderParentCommand>& aParentCommands,
                                            mozilla::layers::WebRenderLayerManager* aManager,
                                            nsDisplayListBuilder* aDisplayListBuilder)
 {
   // If this function is called in layers mode that means we created a
   // WebRenderDisplayItemLayer for a display item that is a subclass of
   // nsDisplayWrapList, but we didn't actually implement the overridden
   // CreateWebRenderCommandsFromDisplayList on it. That doesn't seem correct.
   MOZ_ASSERT(aManager->IsLayersFreeTransaction());
@@ -6249,17 +6239,16 @@ nsDisplayOpacity::WriteDebugInfo(std::st
 {
   aStream << " (opacity " << mOpacity << ")";
 }
 
 bool
 nsDisplayOpacity::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                           mozilla::wr::IpcResourceUpdateQueue& aResources,
                                           const StackingContextHelper& aSc,
-                                          nsTArray<WebRenderParentCommand>& aParentCommands,
                                           mozilla::layers::WebRenderLayerManager* aManager,
                                           nsDisplayListBuilder* aDisplayListBuilder)
 {
   float* opacityForSC = &mOpacity;
 
   RefPtr<WebRenderAnimationData> animationData = aManager->CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(this);
   AnimationInfo& animationInfo = animationData->GetAnimationInfo();
   AddAnimationsForProperty(Frame(), aDisplayListBuilder,
@@ -6333,26 +6322,25 @@ nsDisplayBlendMode::GetLayerState(nsDisp
 {
   return LAYER_ACTIVE;
 }
 
 bool
 nsDisplayBlendMode::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                             mozilla::wr::IpcResourceUpdateQueue& aResources,
                                             const StackingContextHelper& aSc,
-                                            nsTArray<WebRenderParentCommand>& aParentCommands,
                                             mozilla::layers::WebRenderLayerManager* aManager,
                                             nsDisplayListBuilder* aDisplayListBuilder)
 {
   nsTArray<mozilla::wr::WrFilterOp> filters;
   StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this,
                            &mList, nullptr, 0, nullptr, nullptr, nullptr,
                            filters, nsCSSRendering::GetGFXBlendMode(mBlendMode));
 
-  return nsDisplayWrapList::CreateWebRenderCommands(aBuilder,aResources, sc, aParentCommands,
+  return nsDisplayWrapList::CreateWebRenderCommands(aBuilder,aResources, sc,
                                                     aManager, aDisplayListBuilder);
 }
 
 // nsDisplayBlendMode uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
                                   LayerManager* aManager,
                                   const ContainerLayerParameters& aContainerParameters) {
@@ -6465,24 +6453,23 @@ nsDisplayBlendContainer::GetLayerState(n
 {
   return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, GetAnimatedGeometryRoot());
 }
 
 bool
 nsDisplayBlendContainer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                  mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                  const StackingContextHelper& aSc,
-                                                 nsTArray<WebRenderParentCommand>& aParentCommands,
                                                  mozilla::layers::WebRenderLayerManager* aManager,
                                                  nsDisplayListBuilder* aDisplayListBuilder)
 {
   StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this,
                            &mList, nullptr, 0, nullptr, nullptr);
 
-  return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aParentCommands,
+  return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc,
                                                     aManager, aDisplayListBuilder);
 }
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList,
                                      const ActiveScrolledRoot* aActiveScrolledRoot,
                                      uint32_t aFlags, ViewID aScrollTarget,
                                      const ScrollThumbData& aThumbData,
@@ -6559,39 +6546,38 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayL
   }
   return layer.forget();
 }
 
 bool
 nsDisplayOwnLayer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                            mozilla::wr::IpcResourceUpdateQueue& aResources,
                                            const StackingContextHelper& aSc,
-                                           nsTArray<WebRenderParentCommand>& aParentCommands,
                                            WebRenderLayerManager* aManager,
                                            nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (!aManager->AsyncPanZoomEnabled() ||
       mThumbData.mDirection == ScrollDirection::NONE) {
     return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, aSc,
-        aParentCommands, aManager, aDisplayListBuilder);
+                                                      aManager, aDisplayListBuilder);
   }
 
   // APZ is enabled and this is a scroll thumb, so we need to create and
   // set an animation id. That way APZ can move this scrollthumb around as
   // needed.
   RefPtr<WebRenderAnimationData> animationData = aManager->CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(this);
   AnimationInfo& animationInfo = animationData->GetAnimationInfo();
   animationInfo.EnsureAnimationsId();
   mWrAnimationId = animationInfo.GetCompositorAnimationsId();
 
   StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this,
                            &mList, nullptr, mWrAnimationId, nullptr, nullptr);
 
   nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc,
-      aParentCommands, aManager, aDisplayListBuilder);
+                                             aManager, aDisplayListBuilder);
   return true;
 }
 
 bool
 nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                     mozilla::layers::WebRenderLayerScrollData* aLayerData)
 {
   bool ret = false;
@@ -7900,17 +7886,16 @@ nsDisplayTransform::ShouldBuildLayerEven
   // rendering correctly.
   return MayBeAnimated(aBuilder) || mFrame->Combines3DTransformWithAncestors();
 }
 
 bool
 nsDisplayTransform::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                             mozilla::wr::IpcResourceUpdateQueue& aResources,
                                             const StackingContextHelper& aSc,
-                                            nsTArray<WebRenderParentCommand>& aParentCommands,
                                             WebRenderLayerManager* aManager,
                                             nsDisplayListBuilder* aDisplayListBuilder)
 {
   Matrix4x4 newTransformMatrix = GetTransformForRendering();
   gfx::Matrix4x4* transformForSC = &newTransformMatrix;
   if (newTransformMatrix.IsIdentity()) {
     // If the transform is an identity transform, strip it out so that WR
     // doesn't turn this stacking context into a reference frame, as it
@@ -7955,17 +7940,17 @@ nsDisplayTransform::CreateWebRenderComma
                            mStoredList.GetChildren(),
                            &boundTransform,
                            animationsId,
                            nullptr,
                            transformForSC,
                            nullptr,
                            filters);
 
-  return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc, aParentCommands,
+  return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                              aManager, aDisplayListBuilder);
 }
 
 bool
 nsDisplayTransform::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                      mozilla::layers::WebRenderLayerScrollData* aLayerData)
 {
   if (aLayerData) {
@@ -8513,17 +8498,16 @@ nsDisplayPerspective::GetLayerState(nsDi
 {
   return LAYER_ACTIVE_FORCE;
 }
 
 bool
 nsDisplayPerspective::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                               mozilla::wr::IpcResourceUpdateQueue& aResources,
                                               const StackingContextHelper& aSc,
-                                              nsTArray<WebRenderParentCommand>& aParentCommands,
                                               WebRenderLayerManager* aManager,
                                               nsDisplayListBuilder* aDisplayListBuilder)
 {
   float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   Matrix4x4 perspectiveMatrix;
   DebugOnly<bool> hasPerspective =
     nsDisplayTransform::ComputePerspectiveMatrix(mTransformFrame, appUnitsPerPixel,
                                                  perspectiveMatrix);
@@ -8561,17 +8545,17 @@ nsDisplayPerspective::CreateWebRenderCom
                            mList.GetChildren(),
                            nullptr,
                            0,
                            nullptr,
                            &transformForSC,
                            &perspectiveMatrix,
                            filters);
 
-  return mList.CreateWebRenderCommands(aBuilder, aResources, sc, aParentCommands,
+  return mList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                        aManager, aDisplayListBuilder);
 }
 
 int32_t
 nsDisplayPerspective::ZIndex() const
 {
   return ZIndexForFrame(mTransformFrame);
 }
@@ -9027,17 +9011,16 @@ nsDisplayMask::PaintAsLayer(nsDisplayLis
 
   nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
 }
 
 bool
 nsDisplayMask::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder)
 {
   bool snap;
   float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsRect displayBound = GetBounds(aDisplayListBuilder, &snap);
   LayerRect bounds = ViewAs<LayerPixel>(LayoutDeviceRect::FromAppUnits(displayBound, appUnitsPerDevPixel),
                                         PixelCastJustification::WebRenderHasUnitResolution);
@@ -9048,17 +9031,17 @@ nsDisplayMask::CreateWebRenderCommands(m
     wr::WrClipId clipId = aBuilder.DefineClip(
         aSc.ToRelativeLayoutRect(bounds), nullptr, mask.ptr());
     // Don't record this clip push in aBuilder's internal clip stack, because
     // otherwise any nested ScrollingLayersHelper instances that are created
     // will get confused about which clips are pushed.
     aBuilder.PushClip(clipId, /*aRecordInStack*/ false);
   }
 
-  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, aSc, aParentCommands, aManager, aDisplayListBuilder);
+  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
 
   if (mask) {
     aBuilder.PopClip(/*aRecordInStack*/ false);
   }
 
   return true;
 }
 
@@ -9254,17 +9237,16 @@ nsDisplayFilter::PaintAsLayer(nsDisplayL
   nsSVGIntegrationUtils::PaintFilter(params);
   nsDisplayFilterGeometry::UpdateDrawResult(this, imgParams.result);
 }
 
 bool
 nsDisplayFilter::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
-                                         nsTArray<WebRenderParentCommand>& aParentCommands,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       // TODO: should have a fallback path to paint the child list
       return false;
@@ -9285,17 +9267,17 @@ nsDisplayFilter::CreateWebRenderCommands
                            &mList,
                            nullptr,
                            0,
                            nullptr,
                            nullptr,
                            nullptr,
                            wrFilters);
 
-  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, sc, aParentCommands, aManager, aDisplayListBuilder);
+  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, sc, aManager, aDisplayListBuilder);
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayFilter::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -58,17 +58,16 @@ class nsCaret;
 namespace mozilla {
 class FrameLayerBuilder;
 namespace layers {
 class Layer;
 class ImageLayer;
 class ImageContainer;
 class StackingContextHelper;
 class WebRenderCommand;
-class WebRenderParentCommand;
 class WebRenderDisplayItemLayer;
 class WebRenderScrollData;
 class WebRenderLayerScrollData;
 } // namespace layers
 namespace wr {
 class DisplayListBuilder;
 } // namespace wr
 } // namespace mozilla
@@ -2047,17 +2046,16 @@ public:
    * active first and have an early return if the layer state is
    * not active.
    *
    * @return true if successfully creating webrender commands.
    */
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) { return false; }
 
   /**
    * Updates the provided aLayerData with any APZ-relevant scroll data
    * that is specific to this display item. This is stuff that would normally
    * be put on the layer during BuildLayer, but this is only called in
    * layers-free webrender mode, where we don't have layers.
@@ -3016,17 +3014,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
 protected:
   RefPtr<nsCaret> mCaret;
   nsRect mBounds;
 };
 
@@ -3051,17 +3048,16 @@ public:
                                    const ContainerLayerParameters& aParameters) override;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
 
   NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
 
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
@@ -3074,18 +3070,18 @@ public:
                                   bool* aSnap) const override
   {
     *aSnap = true;
     return CalculateBounds(*mFrame->StyleBorder());
   }
 
 protected:
   void CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                          mozilla::wr::IpcResourceUpdateQueue& aResource,
                                           const StackingContextHelper& aSc,
-                                          nsTArray<WebRenderParentCommand>& aParentCommands,
                                           mozilla::layers::WebRenderLayerManager* aManager,
                                           nsDisplayListBuilder* aDisplayListBuilder);
   nsRegion CalculateBounds(const nsStyleBorder& aStyleBorder) const;
 
   mozilla::Array<mozilla::gfx::Color, 4> mColors;
   mozilla::Array<mozilla::LayerCoord, 4> mWidths;
   mozilla::Array<mozilla::LayerSize, 4> mCorners;
   mozilla::Array<uint8_t, 4> mBorderStyles;
@@ -3180,17 +3176,16 @@ public:
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
 
   virtual void WriteDebugInfo(std::stringstream& aStream) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
 
 private:
   nsRect  mBounds;
 };
@@ -3233,17 +3228,16 @@ public:
     } else {
       aInvalidRegion->Or(geometry->mRegion.GetBounds(), mRegion.GetBounds());
     }
   }
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   NS_DISPLAY_DECL_NAME("SolidColorRegion", TYPE_SOLID_COLOR_REGION)
 
 protected:
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
@@ -3318,17 +3312,16 @@ public:
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion) override;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) const override;
@@ -3554,17 +3547,16 @@ public:
                                    const ContainerLayerParameters& aParameters) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) const override;
   virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override;
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override;
 
@@ -3725,17 +3717,16 @@ public:
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
 
   bool CanBuildWebRenderDisplayItems();
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   nsRect GetBoundsInternal();
 
 private:
   nsRegion mVisibleRegion;
   nsRect mBounds;
   float mOpacity;
@@ -3791,17 +3782,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
 private:
   nsRegion mVisibleRegion;
 };
 
 /**
@@ -3823,17 +3813,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual bool IsInvisibleInRect(const nsRect& aRect) const override;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE)
 
   mozilla::Maybe<nsCSSBorderRenderer> mBorderRenderer;
@@ -4140,17 +4129,16 @@ public:
                                            nsDisplayItem* aItem) {
     NS_NOTREACHED("We never returned nullptr for GetUnderlyingFrame!");
     return nullptr;
   }
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
 protected:
   nsDisplayWrapList() = delete;
 
   void MergeFromTrackingMergedFrames(const nsDisplayWrapList* aOther)
   {
@@ -4260,17 +4248,16 @@ public:
   NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
   virtual void WriteDebugInfo(std::stringstream& aStream) override;
 
   bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
 private:
   float mOpacity;
   bool mForEventsAndPluginsOnly;
 };
 
@@ -4306,17 +4293,16 @@ public:
     return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
   }
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                mozilla::wr::IpcResourceUpdateQueue& aResources,
                                const StackingContextHelper& aSc,
-                               nsTArray<WebRenderParentCommand>& aParentCommands,
                                mozilla::layers::WebRenderLayerManager* aManager,
                                nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion) override;
 
   virtual bool CanMerge(const nsDisplayItem* aItem) const override;
 
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override
@@ -4357,17 +4343,16 @@ public:
                                                LayerManager* aManager,
                                                const ContainerLayerParameters& aContainerParameters) override;
     virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      const ContainerLayerParameters& aParameters) override;
     bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                  mozilla::wr::IpcResourceUpdateQueue& aResources,
                                  const StackingContextHelper& aSc,
-                                 nsTArray<WebRenderParentCommand>& aParentCommands,
                                  mozilla::layers::WebRenderLayerManager* aManager,
                                  nsDisplayListBuilder* aDisplayListBuilder) override;
 
     virtual bool CanMerge(const nsDisplayItem* aItem) const override
     {
       // Items for the same content element should be merged into a single
       // compositing group.
       return HasSameTypeAndClip(aItem) && HasSameContent(aItem);
@@ -4445,17 +4430,16 @@ public:
 
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual bool UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                 mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
 
@@ -4886,17 +4870,16 @@ public:
   const nsTArray<nsRect>& GetDestRects()
   {
     return mDestRects;
   }
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 private:
   // According to mask property and the capability of aManager, determine
   // whether paint mask onto a dedicate mask layer.
   bool ShouldPaintOnMaskLayer(LayerManager* aManager);
 
   nsTArray<nsRect> mDestRects;
@@ -4965,17 +4948,16 @@ public:
 
   void PaintAsLayer(nsDisplayListBuilder* aBuilder,
                     gfxContext* aCtx,
                     LayerManager* aManager);
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
 private:
   // relative to mFrame
   nsRect mEffectsBounds;
 };
 
@@ -5102,17 +5084,16 @@ public:
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual bool UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                 mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const override;
   virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder,
                                  nsRegion *aVisibleRegion) override;
 
@@ -5437,17 +5418,16 @@ public:
   }
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                mozilla::wr::IpcResourceUpdateQueue& aResources,
                                const StackingContextHelper& aSc,
-                               nsTArray<WebRenderParentCommand>& aParentCommands,
                                mozilla::layers::WebRenderLayerManager* aManager,
                                nsDisplayListBuilder* aDisplayListBuilder) override;
 
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const override
   {
     if (!mList.GetChildren()->GetTop()) {
       return false;
     }
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -580,30 +580,30 @@ nsImageRenderer::Draw(nsPresContext*    
                     DrawSurfaceOptions(SamplingFilter::POINT),
                     DrawOptions(1.0f, aRenderingContext.CurrentOp()));
   }
 
   return result;
 }
 
 DrawResult
-nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
-                                            mozilla::wr::DisplayListBuilder&            aBuilder,
+nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext* aPresContext,
+                                            mozilla::wr::DisplayListBuilder& aBuilder,
+                                            mozilla::wr::IpcResourceUpdateQueue& aResources,
                                             const mozilla::layers::StackingContextHelper& aSc,
-                                            nsTArray<WebRenderParentCommand>&           aParentCommands,
                                             mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                             mozilla::layers::WebRenderLayerManager* aManager,
-                                            nsDisplayItem*       aItem,
-                                            const nsRect&        aDirtyRect,
-                                            const nsRect&        aDest,
-                                            const nsRect&        aFill,
-                                            const nsPoint&       aAnchor,
-                                            const nsSize&        aRepeatSize,
-                                            const CSSIntRect&    aSrc,
-                                            float                aOpacity)
+                                            nsDisplayItem* aItem,
+                                            const nsRect& aDirtyRect,
+                                            const nsRect& aDest,
+                                            const nsRect& aFill,
+                                            const nsPoint& aAnchor,
+                                            const nsSize& aRepeatSize,
+                                            const CSSIntRect& aSrc,
+                                            float aOpacity)
 {
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return DrawResult::NOT_READY;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
     return DrawResult::SUCCESS;
@@ -629,17 +629,17 @@ nsImageRenderer::BuildWebRenderDisplayIt
       RefPtr<layers::ImageContainer> container =
         mImageContainer->GetImageContainer(aManager, containerFlags);
       if (!container) {
         NS_WARNING("Failed to get image container");
         return DrawResult::NOT_READY;
       }
 
       gfx::IntSize size;
-      Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aSc, size);
+      Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aResources, aSc, size);
 
       if (key.isNothing()) {
         return DrawResult::BAD_IMAGE;
       }
 
       const int32_t appUnitsPerDevPixel = mForFrame->PresContext()->AppUnitsPerDevPixel();
       LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(
           aDest, appUnitsPerDevPixel);
@@ -729,18 +729,18 @@ nsImageRenderer::DrawLayer(nsPresContext
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
               aOpacity);
 }
 
 DrawResult
 nsImageRenderer::BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
                                                     mozilla::wr::DisplayListBuilder& aBuilder,
+                                                    mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                     const mozilla::layers::StackingContextHelper& aSc,
-                                                    nsTArray<WebRenderParentCommand>& aParentCommands,
                                                     WebRenderDisplayItemLayer*       aLayer,
                                                     mozilla::layers::WebRenderLayerManager* aManager,
                                                     nsDisplayItem*       aItem,
                                                     const nsRect&        aDest,
                                                     const nsRect&        aFill,
                                                     const nsPoint&       aAnchor,
                                                     const nsRect&        aDirty,
                                                     const nsSize&        aRepeatSize,
@@ -749,17 +749,17 @@ nsImageRenderer::BuildWebRenderDisplayIt
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return mPrepareResult;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
     return DrawResult::SUCCESS;
   }
-  return BuildWebRenderDisplayItems(aPresContext, aBuilder, aSc, aParentCommands,
+  return BuildWebRenderDisplayItems(aPresContext, aBuilder, aResources, aSc,
                                     aLayer, aManager, aItem,
                                     aDirty, aDest, aFill, aAnchor, aRepeatSize,
                                     CSSIntRect(0, 0,
                                                nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                                                nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
                                     aOpacity);
 }
 
--- a/layout/painting/nsImageRenderer.h
+++ b/layout/painting/nsImageRenderer.h
@@ -17,16 +17,17 @@ namespace layers {
 class StackingContextHelper;
 class WebRenderParentCommand;
 class WebRenderDisplayItemLayer;
 class WebRenderLayerManager;
 } // namespace layers
 
 namespace wr {
 class DisplayListBuilder;
+class IpcResourceUpdateQueue;
 } // namespace wr
 
 // A CSSSizeOrRatio represents a (possibly partially specified) size for use
 // in computing image sizes. Either or both of the width and height might be
 // given. A ratio of width to height may also be given. If we at least two
 // of these then we can compute a concrete size, that is a width and height.
 struct CSSSizeOrRatio
 {
@@ -205,18 +206,18 @@ public:
 
   /**
    * Builds WebRender DisplayItems for an image using
    * {background|mask}-specific arguments.
    * @see nsLayoutUtils::DrawImage() for parameters.
    */
   DrawResult BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
                                                 mozilla::wr::DisplayListBuilder& aBuilder,
+                                                mozilla::wr::IpcResourceUpdateQueue& aResource,
                                                 const mozilla::layers::StackingContextHelper& aSc,
-                                                nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                 mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                                 mozilla::layers::WebRenderLayerManager* aManager,
                                                 nsDisplayItem*       aItem,
                                                 const nsRect&        aDest,
                                                 const nsRect&        aFill,
                                                 const nsPoint&       aAnchor,
                                                 const nsRect&        aDirty,
                                                 const nsSize&        aRepeatSize,
@@ -292,18 +293,18 @@ private:
    * Builds WebRender DisplayItems for the image.
    * aSrc is a rect on the source image which will be mapped to aDest; it's
    * currently only used for gradients.
    *
    * @see nsLayoutUtils::DrawImage() for other parameters.
    */
   DrawResult BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
                                         mozilla::wr::DisplayListBuilder& aBuilder,
+                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                         const mozilla::layers::StackingContextHelper& aSc,
-                                        nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                         mozilla::layers::WebRenderDisplayItemLayer* aLayer,
                                         mozilla::layers::WebRenderLayerManager* aManager,
                                         nsDisplayItem*       aItem,
                                         const nsRect&        aDirtyRect,
                                         const nsRect&        aDest,
                                         const nsRect&        aFill,
                                         const nsPoint&       aAnchor,
                                         const nsSize&        aRepeatSize,
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2437,43 +2437,41 @@ Gecko_XBLBinding_GetRawServoStyleSet(Raw
 }
 
 bool
 Gecko_XBLBinding_InheritsStyle(RawGeckoXBLBindingBorrowed aXBLBinding)
 {
   return aXBLBinding->InheritsStyle();
 }
 
-// XXX: temporarily disabled due to a leak, see bug 1401427
-//static StaticRefPtr<UACacheReporter> gUACacheReporter;
+static StaticRefPtr<UACacheReporter> gUACacheReporter;
 
 void
 InitializeServo()
 {
   URLExtraData::InitDummy();
   Servo_Initialize(URLExtraData::Dummy());
 
-  // XXX: temporarily disabled due to a leak, see bug 1401427
-  //gUACacheReporter = new UACacheReporter();
-  //RegisterWeakMemoryReporter(gUACacheReporter);
+  gUACacheReporter = new UACacheReporter();
+  RegisterWeakMemoryReporter(gUACacheReporter);
 
   sServoFontMetricsLock = new Mutex("Gecko_GetFontMetrics");
   sServoWidgetLock = new Mutex("Servo::WidgetLock");
   sServoLangFontPrefsLock = new RWLock("nsPresContext::GetDefaultFont");
 }
 
 void
 ShutdownServo()
 {
   MOZ_ASSERT(sServoFontMetricsLock);
   MOZ_ASSERT(sServoWidgetLock);
   MOZ_ASSERT(sServoLangFontPrefsLock);
 
-  // XXX: temporarily disabled due to a leak, see bug 1401427
-  //UnregisterWeakMemoryReporter(gUACacheReporter);
+  UnregisterWeakMemoryReporter(gUACacheReporter);
+  gUACacheReporter = nullptr;
 
   delete sServoFontMetricsLock;
   delete sServoWidgetLock;
   delete sServoLangFontPrefsLock;
   Servo_Shutdown();
 }
 
 namespace mozilla {
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1272,17 +1272,16 @@ public:
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      gfxContext* aCtx) override;
   virtual already_AddRefed<layers::Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                                      LayerManager* aManager,
                                                      const ContainerLayerParameters& aContainerParameters) override;
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   NS_DISPLAY_DECL_NAME("TableBorderCollapse", TYPE_TABLE_BORDER_COLLAPSE)
 };
 
@@ -1312,30 +1311,28 @@ nsDisplayTableBorderCollapse::BuildLayer
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayTableBorderCollapse::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                       wr::IpcResourceUpdateQueue& aResources,
                                                       const StackingContextHelper& aSc,
-                                                      nsTArray<WebRenderParentCommand>& aParentCommands,
                                                       mozilla::layers::WebRenderLayerManager* aManager,
                                                       nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
   }
 
   static_cast<nsTableFrame *>(mFrame)->CreateWebRenderCommandsForBCBorders(aBuilder,
                                                                           aSc,
-                                                                          aParentCommands,
                                                                           ToReferenceFrame());
   return true;
 }
 
 LayerState
 nsDisplayTableBorderCollapse::GetLayerState(nsDisplayListBuilder* aBuilder,
                                             LayerManager* aManager,
                                             const ContainerLayerParameters& aParameters)
@@ -6521,17 +6518,16 @@ struct BCBlockDirSeg
                                                   BCPixelSize aInlineSegBSize);
   void Paint(BCPaintBorderIterator& aIter,
              DrawTarget&            aDrawTarget,
              BCPixelSize            aInlineSegBSize);
   void CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                BCPixelSize aInlineSegBSize,
                                wr::DisplayListBuilder& aBuilder,
                                const layers::StackingContextHelper& aSc,
-                               nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                const nsPoint& aPt);
   void AdvanceOffsetB();
   void IncludeCurrentBorder(BCPaintBorderIterator& aIter);
 
 
   union {
     nsTableColFrame*  mCol;
     int32_t           mColWidth;
@@ -6576,17 +6572,16 @@ struct BCInlineDirSeg
                      BCPixelSize            aIStartSegISize);
   void AdvanceOffsetI();
   void IncludeCurrentBorder(BCPaintBorderIterator& aIter);
   Maybe<BCBorderParameters> BuildBorderParameters(BCPaintBorderIterator& aIter);
   void Paint(BCPaintBorderIterator& aIter, DrawTarget& aDrawTarget);
   void CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                wr::DisplayListBuilder& aBuilder,
                                const layers::StackingContextHelper& aSc,
-                               nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                const nsPoint& aPt);
 
   nscoord            mOffsetI;       // i-offset with respect to the table edge
   nscoord            mOffsetB;       // b-offset with respect to the table edge
   nscoord            mLength;        // inline-dir length including corners
   BCPixelSize        mWidth;         // border thickness in pixels
   nscoord            mIStartBevelOffset; // how much to bevel at the iStart
   LogicalSide        mIStartBevelSide;   // direction to bevel at the iStart
@@ -6614,45 +6609,41 @@ struct BCPaintData
 
   DrawTarget& mDrawTarget;
 };
 
 struct BCCreateWebRenderCommandsData
 {
   BCCreateWebRenderCommandsData(wr::DisplayListBuilder& aBuilder,
                                 const layers::StackingContextHelper& aSc,
-                                nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                 const nsPoint& aOffsetToReferenceFrame)
     : mBuilder(aBuilder)
     , mSc(aSc)
-    , mParentCommands(aParentCommands)
     , mOffsetToReferenceFrame(aOffsetToReferenceFrame)
   {
   }
 
   wr::DisplayListBuilder& mBuilder;
   const layers::StackingContextHelper& mSc;
-  nsTArray<layers::WebRenderParentCommand>& mParentCommands;
   const nsPoint& mOffsetToReferenceFrame;
 };
 
 struct BCPaintBorderAction
 {
   explicit BCPaintBorderAction(DrawTarget& aDrawTarget)
     : mMode(Mode::PAINT)
     , mPaintData(aDrawTarget)
   {
   }
 
   BCPaintBorderAction(wr::DisplayListBuilder& aBuilder,
                       const layers::StackingContextHelper& aSc,
-                      nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                       const nsPoint& aOffsetToReferenceFrame)
     : mMode(Mode::CREATE_WEBRENDER_COMMANDS)
-    , mCreateWebRenderCommandsData(aBuilder, aSc, aParentCommands, aOffsetToReferenceFrame)
+    , mCreateWebRenderCommandsData(aBuilder, aSc, aOffsetToReferenceFrame)
   {
     mMode = Mode::CREATE_WEBRENDER_COMMANDS;
   }
 
   enum class Mode {
     PAINT,
     CREATE_WEBRENDER_COMMANDS,
   };
@@ -7457,17 +7448,16 @@ BCBlockDirSeg::Paint(BCPaintBorderIterat
                                          param->mEndBevelSide, param->mEndBevelOffset);
 }
 
 void
 BCBlockDirSeg::CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                        BCPixelSize aInlineSegBSize,
                                        wr::DisplayListBuilder& aBuilder,
                                        const layers::StackingContextHelper& aSc,
-                                       nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                        const nsPoint& aOffset)
 {
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter, aInlineSegBSize);
   if (param.isNothing()) {
     return;
   }
 
   //TODO: Currently, we don't support border with m{Start,End}Bevel{Side,Offset} attributes.
@@ -7716,17 +7706,16 @@ BCInlineDirSeg::Paint(BCPaintBorderItera
                                          param->mStartBevelSide, param->mStartBevelOffset,
                                          param->mEndBevelSide, param->mEndBevelOffset);
 }
 
 void
 BCInlineDirSeg::CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                         wr::DisplayListBuilder& aBuilder,
                                         const layers::StackingContextHelper& aSc,
-                                        nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                         const nsPoint& aPt)
 {
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter);
   if (param.isNothing()) {
     return;
   }
 
   //TODO: Currently, we don't support border with m{Start,End}Bevel{Side,Offset} attributes.
@@ -7845,17 +7834,16 @@ BCPaintBorderIterator::AccumulateOrDoAct
       if (mInlineSeg.mWidth > 0) {
         if (aAction.mMode == BCPaintBorderAction::Mode::PAINT) {
           mInlineSeg.Paint(*this, aAction.mPaintData.mDrawTarget);
         } else {
           MOZ_ASSERT(aAction.mMode == BCPaintBorderAction::Mode::CREATE_WEBRENDER_COMMANDS);
           mInlineSeg.CreateWebRenderCommands(*this,
                                              aAction.mCreateWebRenderCommandsData.mBuilder,
                                              aAction.mCreateWebRenderCommandsData.mSc,
-                                             aAction.mCreateWebRenderCommandsData.mParentCommands,
                                              aAction.mCreateWebRenderCommandsData.mOffsetToReferenceFrame);
         }
       }
       mInlineSeg.AdvanceOffsetI();
     }
     mInlineSeg.Start(*this, borderOwner, iStartSegISize, bStartSegBSize);
   }
   mInlineSeg.IncludeCurrentBorder(*this);
@@ -7898,17 +7886,16 @@ BCPaintBorderIterator::AccumulateOrDoAct
         if (aAction.mMode == BCPaintBorderAction::Mode::PAINT) {
           blockDirSeg.Paint(*this, aAction.mPaintData.mDrawTarget, inlineSegBSize);
         } else {
           MOZ_ASSERT(aAction.mMode == BCPaintBorderAction::Mode::CREATE_WEBRENDER_COMMANDS);
           blockDirSeg.CreateWebRenderCommands(*this,
                                               inlineSegBSize,
                                               aAction.mCreateWebRenderCommandsData.mBuilder,
                                               aAction.mCreateWebRenderCommandsData.mSc,
-                                              aAction.mCreateWebRenderCommandsData.mParentCommands,
                                               aAction.mCreateWebRenderCommandsData.mOffsetToReferenceFrame);
         }
       }
       blockDirSeg.AdvanceOffsetB();
     }
     blockDirSeg.Start(*this, borderOwner, blockSegISize, inlineSegBSize);
   }
   blockDirSeg.IncludeCurrentBorder(*this);
@@ -7973,20 +7960,19 @@ nsTableFrame::PaintBCBorders(DrawTarget&
 {
   BCPaintBorderAction action(aDrawTarget);
   IterateBCBorders(action, aDirtyRect);
 }
 
 void
 nsTableFrame::CreateWebRenderCommandsForBCBorders(wr::DisplayListBuilder& aBuilder,
                                                   const mozilla::layers::StackingContextHelper& aSc,
-                                                  nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                   const nsPoint& aOffsetToReferenceFrame)
 {
-  BCPaintBorderAction action(aBuilder, aSc, aParentCommands, aOffsetToReferenceFrame);
+  BCPaintBorderAction action(aBuilder, aSc, aOffsetToReferenceFrame);
   // We always draw whole table border for webrender. Passing the table rect as
   // dirty rect.
   IterateBCBorders(action, GetRect());
 }
 
 bool
 nsTableFrame::RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols)
 {
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -295,17 +295,16 @@ public:
   friend class nsDelayedCalcBCBorders;
 
   void AddBCDamageArea(const mozilla::TableArea& aValue);
   bool BCRecalcNeeded(nsStyleContext* aOldStyleContext,
                         nsStyleContext* aNewStyleContext);
   void PaintBCBorders(DrawTarget& aDrawTarget, const nsRect& aDirtyRect);
   void CreateWebRenderCommandsForBCBorders(mozilla::wr::DisplayListBuilder& aBuilder,
                                            const mozilla::layers::StackingContextHelper& aSc,
-                                           nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
                                            const nsPoint& aPt);
 
   virtual void MarkIntrinsicISizesDirty() override;
   // For border-collapse tables, the caller must not add padding and
   // border to the results of these functions.
   virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
   virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
   virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override;
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -442,17 +442,19 @@ nsImageBoxFrame::CreateWebRenderCommands
   RefPtr<layers::ImageContainer> container =
     imgCon->GetImageContainer(aManager, containerFlags);
   if (!container) {
     NS_WARNING("Failed to get image container");
     return DrawResult::NOT_READY;
   }
 
   gfx::IntSize size;
-  Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aSc, size);
+  Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container,
+                                                     aBuilder, aResources,
+                                                     aSc, size);
   if (key.isNothing()) {
     return DrawResult::BAD_IMAGE;
   }
   const int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
   LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(dest,
                                                              appUnitsPerDevPixel);
   wr::LayoutRect fill = aSc.ToRelativeLayoutRect(fillRect);
 
@@ -548,17 +550,16 @@ nsDisplayXULImage::BuildLayer(nsDisplayL
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 bool
 nsDisplayXULImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                            mozilla::wr::IpcResourceUpdateQueue& aResources,
                                            const StackingContextHelper& aSc,
-                                           nsTArray<WebRenderParentCommand>& aParentCommands,
                                            mozilla::layers::WebRenderLayerManager* aManager,
                                            nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (aManager->IsLayersFreeTransaction()) {
     ContainerLayerParameters parameter;
     if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
       return false;
     }
--- a/layout/xul/nsImageBoxFrame.h
+++ b/layout/xul/nsImageBoxFrame.h
@@ -179,16 +179,15 @@ public:
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
-                                       nsTArray<WebRenderParentCommand>& aParentCommands,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE)
 };
 
 #endif /* nsImageBoxFrame_h___ */
new file mode 100644
--- /dev/null
+++ b/media/mtransport/fuzztest/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Library('FuzzingStun')
+
+DEFINES['HAVE_STRDUP'] = True
+
+LOCAL_INCLUDES += [
+  '/ipc/chromium/src',
+  '/media/mtransport',
+  '/media/mtransport/third_party/nICEr/src/net',
+  '/media/mtransport/third_party/nICEr/src/stun',
+  '/media/mtransport/third_party/nrappkit/src/event',
+  '/media/mtransport/third_party/nrappkit/src/log',
+  '/media/mtransport/third_party/nrappkit/src/plugin',
+  '/media/mtransport/third_party/nrappkit/src/port/darwin/include',
+  '/media/mtransport/third_party/nrappkit/src/share',
+  '/media/mtransport/third_party/nrappkit/src/stats',
+  '/media/mtransport/third_party/nrappkit/src/util/libekr',
+]
+
+SOURCES += [
+    'stun_parser_libfuzz.cpp',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
new file mode 100644
--- /dev/null
+++ b/media/mtransport/fuzztest/stun_parser_libfuzz.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "FuzzingInterface.h"
+#include "LibFuzzerRegistry.h"
+
+extern "C" {
+#include <csi_platform.h>
+#include "stun_msg.h"
+#include "stun_codec.h"
+}
+
+int FuzzingInitStunParser(int *argc, char ***argv) {
+  return 0;
+}
+
+static int
+RunStunParserFuzzing(const uint8_t* data, size_t size) {
+  nr_stun_message *req = 0;
+
+  UCHAR* mes = (UCHAR*)data;
+
+  nr_stun_message_create2(&req, mes, size);
+
+  nr_stun_decode_message(req, nullptr, nullptr);
+
+  nr_stun_message_destroy(&req);
+
+  return 0;
+}
+
+MOZ_FUZZING_INTERFACE_RAW(FuzzingInitStunParser, RunStunParserFuzzing, StunParser);
--- a/media/mtransport/moz.build
+++ b/media/mtransport/moz.build
@@ -9,8 +9,18 @@ with Files("**"):
 
 include("/ipc/chromium/chromium-config.mozbuild")
 
 DIRS += [
     '/media/mtransport/third_party',
     '/media/mtransport/build',
     '/media/mtransport/ipc',
 ]
+
+if CONFIG['FUZZING']:
+    if CONFIG['LIBFUZZER']:
+        # Add trace-pc coverage for libfuzzer
+        CFLAGS += ['-fsanitize-coverage=trace-pc-guard']
+        CXXFLAGS += ['-fsanitize-coverage=trace-pc-guard']
+
+    TEST_DIRS += [
+        'fuzztest'
+    ]
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
@@ -732,17 +732,20 @@ nr_stun_attr_codec_fingerprint_decode(nr
     /* the length must include the FINGERPRINT attribute when computing
      * the fingerprint */
     length = offset;  /* right before FINGERPRINT */
     length -= sizeof(*header); /* remove header length */
     length += 8;  /* add length of Fingerprint */
     header->length = htons(length);
 
     /* make sure FINGERPRINT is final attribute in message */
-    assert(length + sizeof(*header) == buflen);
+    if (length + sizeof(*header) != buflen) {
+        r_log(NR_LOG_STUN, LOG_WARNING, "Fingerprint is not final attribute in message");
+        ABORT(R_FAILED);
+    }
 
     if (r_crc32((char*)buf, offset, &checksum)) {
         r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint");
         ABORT(R_FAILED);
     }
 
     fingerprint->valid = (fingerprint->checksum == (checksum ^ 0x5354554e));
 
--- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/IGeckoEditableParent.aidl
+++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/IGeckoEditableParent.aidl
@@ -11,17 +11,17 @@ import org.mozilla.gecko.IGeckoEditableC
 
 // Interface for GeckoEditable calls from child to parent
 interface IGeckoEditableParent {
     // Notify an IME event of a type defined in GeckoEditableListener.
     void notifyIME(IGeckoEditableChild child, int type);
 
     // Notify a change in editor state or type.
     void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint,
-                          boolean inPrivateBrowsing);
+                          boolean inPrivateBrowsing, boolean isUserAction);
 
     // Notify a change in editor selection.
     void onSelectionChange(IBinder token, int start, int end);
 
     // Notify a change in editor text.
     void onTextChange(IBinder token, in CharSequence text,
                       int start, int unboundedOldEnd);
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
@@ -1131,17 +1131,18 @@ final class GeckoEditable extends IGecko
                 }
             }
         });
     }
 
     @Override // IGeckoEditableParent
     public void notifyIMEContext(final int state, final String typeHint,
                                  final String modeHint, final String actionHint,
-