Merge inbound to mozilla-central. a=merge
authorCsoregi Natalia <ncsoregi@mozilla.com>
Wed, 07 Nov 2018 11:52:57 +0200
changeset 504014 070757a0160c8e6156cf6d8d567a0af280dc33e8
parent 503985 bc83ec5a338dd6070dc14d6f08efd208fc1c69b0 (current diff)
parent 504013 274f95b85267d07ae0d2eceb95c683dda098ce82 (diff)
child 504028 4de987e47323c74954cef79540e5a0bbe887c232
child 504058 64e32a13c4826d10460564ee555cf8e956a7891d
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
070757a0160c / 65.0a1 / 20181107100135 / files
nightly linux64
070757a0160c / 65.0a1 / 20181107100135 / files
nightly mac
070757a0160c / 65.0a1 / 20181107100135 / files
nightly win32
070757a0160c / 65.0a1 / 20181107100135 / files
nightly win64
070757a0160c / 65.0a1 / 20181107100135 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/nsFrameLoader.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
gfx/2d/2D.h
layout/ipc/PRenderFrame.ipdl
layout/ipc/RenderFrameChild.cpp
layout/ipc/RenderFrameChild.h
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
modules/libpref/init/StaticPrefList.h
mozilla-config.h.in
--- a/browser/components/downloads/test/browser/browser.ini
+++ b/browser/components/downloads/test/browser/browser.ini
@@ -5,13 +5,14 @@ support-files = head.js
 [browser_first_download_panel.js]
 skip-if = os == "linux" # Bug 949434
 [browser_overflow_anchor.js]
 skip-if = os == "linux" # Bug 952422
 [browser_confirm_unblock_download.js]
 [browser_iframe_gone_mid_download.js]
 [browser_indicatorDrop.js]
 [browser_libraryDrop.js]
+skip-if = (os == 'win' && os_version == '10.0' && ccov) # Bug 1306510
 [browser_library_clearall.js]
 [browser_downloads_panel_block.js]
 skip-if = true # Bug 1352792
 [browser_downloads_panel_height.js]
 [browser_downloads_autohide.js]
--- a/devtools/server/actors/replay/graphics.js
+++ b/devtools/server/actors/replay/graphics.js
@@ -20,18 +20,17 @@ const CC = Components.Constructor;
 const sandbox = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")());
 Cu.evalInSandbox(
   "Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
   "addDebuggerToGlobal(this);",
   sandbox
 );
 
 // Windows in the middleman process are initially set up as about:blank pages.
-// This method fills them in with a canvas filling the tab, and an overlay that
-// can be displayed over that canvas.
+// This method fills them in with a canvas filling the tab.
 function setupContents(window) {
   // The middlemanCanvas element fills the tab's contents.
   const canvas = window.middlemanCanvas = window.document.createElement("canvas");
   canvas.style.position = "absolute";
   window.document.body.style.margin = "0px";
   window.document.body.prepend(canvas);
 }
 
@@ -86,18 +85,12 @@ function UpdateCanvas(buffer, width, hei
     for (const window of Services.ww.getWindowEnumerator()) {
       updateWindowCanvas(window, buffer, width, height, hadFailure);
     }
   } catch (e) {
     dump("Middleman Graphics UpdateCanvas Exception: " + e + "\n");
   }
 }
 
-// Entry point for when we need to update the overlay's contents or visibility.
-// eslint-disable-next-line no-unused-vars
-function UpdateOverlay() {
-}
-
 // eslint-disable-next-line no-unused-vars
 var EXPORTED_SYMBOLS = [
   "UpdateCanvas",
-  "UpdateOverlay",
 ];
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -77,17 +77,17 @@
 #include "mozilla/NullPrincipal.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/ChromeMessageSender.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/FrameLoaderBinding.h"
 #include "mozilla/gfx/CrossProcessPaint.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
-#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/layout/RenderFrame.h"
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/ServoStyleSet.h"
 #include "nsGenericHTMLFrameElement.h"
 #include "GeckoProfiler.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
@@ -848,22 +848,22 @@ nsFrameLoader::ShowRemoteFrame(const Scr
     }
 
     // We never want to host remote frameloaders in simple popups, like menus.
     nsIWidget* widget = nsContentUtils::WidgetForContent(mOwnerContent);
     if (!widget || static_cast<nsBaseWidget*>(widget)->IsSmallPopup()) {
       return false;
     }
 
-    RenderFrameParent* rfp = GetCurrentRenderFrame();
-    if (!rfp) {
+    RenderFrame* rf = GetCurrentRenderFrame();
+    if (!rf) {
       return false;
     }
 
-    if (!rfp->AttachLayerManager()) {
+    if (!rf->AttachLayerManager()) {
       // This is just not going to work.
       return false;
     }
 
     mRemoteBrowser->Show(size, ParentWindowIsActive(mOwnerContent->OwnerDoc()));
     mRemoteBrowserShown = true;
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
@@ -1801,17 +1801,17 @@ nsFrameLoader::SetOwnerContent(Element* 
   JS::RootedObject wrapper(jsapi.cx(), GetWrapper());
   if (wrapper) {
     JSAutoRealm ar(jsapi.cx(), wrapper);
     IgnoredErrorResult rv;
     ReparentWrapper(jsapi.cx(), wrapper, rv);
     Unused << NS_WARN_IF(rv.Failed());
   }
 
-  if (RenderFrameParent* rfp = GetCurrentRenderFrame()) {
+  if (RenderFrame* rfp = GetCurrentRenderFrame()) {
     rfp->OwnerContentChanged(aContent);
   }
 }
 
 bool
 nsFrameLoader::OwnerIsMozBrowserFrame()
 {
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
@@ -2611,18 +2611,18 @@ nsFrameLoader::TryRemoteBrowser()
   nsCOMPtr<Element> ownerElement = mOwnerContent;
   mRemoteBrowser = ContentParent::CreateBrowser(context, ownerElement,
                                                 openerContentParent,
                                                 sameTabGroupAs,
                                                 nextTabParentId);
   if (!mRemoteBrowser) {
     return false;
   }
-  // Now that mRemoteBrowser is set, we can initialize the RenderFrameParent
-  mRemoteBrowser->InitRenderFrame();
+  // Now that mRemoteBrowser is set, we can initialize the RenderFrame
+  mRemoteBrowser->InitRendering();
 
   MaybeUpdatePrimaryTabParent(eTabParentChanged);
 
   mChildID = mRemoteBrowser->Manager()->ChildID();
 
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
   nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem->GetWindow();
@@ -2665,17 +2665,17 @@ nsFrameLoader::TryRemoteBrowser()
 }
 
 mozilla::dom::PBrowserParent*
 nsFrameLoader::GetRemoteBrowser() const
 {
   return mRemoteBrowser;
 }
 
-RenderFrameParent*
+RenderFrame*
 nsFrameLoader::GetCurrentRenderFrame() const
 {
   if (mRemoteBrowser) {
     return mRemoteBrowser->GetRenderFrame();
   }
   return nullptr;
 }
 
@@ -2936,16 +2936,17 @@ nsFrameLoader::SetRemoteBrowser(nsITabPa
 {
   MOZ_ASSERT(!mRemoteBrowser);
   mRemoteFrame = true;
   mRemoteBrowser = TabParent::GetFrom(aTabParent);
   mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
   MaybeUpdatePrimaryTabParent(eTabParentChanged);
   ReallyLoadFrameScripts();
   InitializeBrowserAPI();
+  mRemoteBrowser->InitRendering();
   ShowRemoteFrame(ScreenIntSize(0, 0));
 }
 
 void
 nsFrameLoader::SetDetachedSubdocFrame(nsIFrame* aDetachedFrame,
                                       nsIDocument* aContainerDoc)
 {
   mDetachedSubdocFrame = aDetachedFrame;
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -60,17 +60,17 @@ class MutableTabContext;
 
 namespace ipc {
 class StructuredCloneData;
 } // namespace ipc
 
 } // namespace dom
 
 namespace layout {
-class RenderFrameParent;
+class RenderFrame;
 } // namespace layout
 } // namespace mozilla
 
 #if defined(MOZ_WIDGET_GTK)
 typedef struct _GtkWidget GtkWidget;
 #endif
 
 // IID for nsFrameLoader, because some places want to QI to it.
@@ -81,17 +81,17 @@ typedef struct _GtkWidget GtkWidget;
 class nsFrameLoader final : public nsStubMutationObserver,
                             public mozilla::dom::ipc::MessageManagerCallback,
                             public nsWrapperCache
 {
   friend class AutoResetInShow;
   friend class AutoResetInFrameSwap;
   typedef mozilla::dom::PBrowserParent PBrowserParent;
   typedef mozilla::dom::TabParent TabParent;
-  typedef mozilla::layout::RenderFrameParent RenderFrameParent;
+  typedef mozilla::layout::RenderFrame RenderFrame;
 
 public:
   static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
                                nsPIDOMWindowOuter* aOpener,
                                bool aNetworkCreated,
                                int32_t aJSPluginID = nsFakePluginTag::NOT_JSPLUGIN);
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID)
@@ -291,17 +291,17 @@ public:
    *
    * Note that the returned render frame might not be a frame
    * constructed for this->GetURL().  This can happen, e.g., if the
    * <browser> was just navigated to a new URL, but hasn't painted the
    * new page yet.  A render frame for the previous page may be
    * returned.  (In-process <browser> behaves similarly, and this
    * behavior seems desirable.)
    */
-  RenderFrameParent* GetCurrentRenderFrame() const;
+  RenderFrame* GetCurrentRenderFrame() const;
 
   mozilla::dom::ChromeMessageSender* GetFrameMessageManager() { return mMessageManager; }
 
   mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
   bool ShouldClipSubdocument() { return mClipSubdocument; }
 
   bool ShouldClampScrollPosition() { return mClampScrollPosition; }
 
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -5473,16 +5473,24 @@ nsGlobalWindowOuter::RevisePopupAbuseLev
   if (abuse == openAbused ||
       abuse == openBlocked ||
       abuse == openControlled) {
     int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
     if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
       abuse = openOverridden;
   }
 
+  // If this popup is allowed, let's block any other for this event, forcing
+  // openBlocked state.
+  if ((abuse == openAllowed || abuse == openControlled) &&
+      StaticPrefs::dom_block_multiple_popups() &&
+      !PopupWhitelisted()) {
+    nsContentUtils::PushPopupControlState(openBlocked, true);
+  }
+
   return abuse;
 }
 
 /* If a window open is blocked, fire the appropriate DOM events. */
 void
 nsGlobalWindowOuter::FireAbuseEvents(const nsAString &aPopupURL,
                                      const nsAString &aPopupWindowName,
                                      const nsAString &aPopupWindowFeatures)
@@ -5509,17 +5517,17 @@ nsGlobalWindowOuter::FireAbuseEvents(con
     baseURL = doc->GetDocBaseURI();
 
   // use the base URI to build what would have been the popup's URI
   nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
   if (ios)
     ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), nullptr, baseURL,
                 getter_AddRefs(popupURI));
 
-  // fire an event chock full of informative URIs
+  // fire an event block full of informative URIs
   FirePopupBlockedEvent(topDoc, popupURI, aPopupWindowName,
                         aPopupWindowFeatures);
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindowOuter::OpenOuter(const nsAString& aUrl, const nsAString& aName,
                                const nsAString& aOptions, ErrorResult& aError)
 {
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -52,8 +52,10 @@ skip-if = e10s # this tests non-e10s beh
 [browser_promiseDocumentFlushed.js]
 [browser_state_notifications.js]
 skip-if = true # Bug 1271028
 [browser_use_counters.js]
 skip-if = verify
 [browser_timeout_throttling_with_audio_playback.js]
 [browser_bug1303838.js]
 [browser_inputStream_structuredClone.js]
+[browser_multiple_popups.js]
+support-files = browser_multiple_popups.html
new file mode 100644
--- /dev/null
+++ b/dom/base/test/browser_multiple_popups.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<body>
+  <button onclick="openPopups();" id="openPopups">open popups</button>
+  <button onclick="openNestedPopups();" id="openNestedPopups">open tested popups</button>
+  <button onclick="openPopupAndClick();" id="openPopupAndClick">open popups and click</button>
+  <button onclick="closeAllWindows();" id="closeAllWindows">close all windows</button>
+  <input type="text" id="input" />
+  <script>
+let windows = [];
+
+function openPopups() {
+  windows.push(window.open('empty.html', '_blank', 'width=100,height=100'));
+  windows.push(window.open('empty.html', '_blank', 'width=100,height=100'));
+}
+
+function openNestedPopups() {
+  var w = window.open('empty.html', '_blank', 'width=100,height=100');
+  windows.push(w);
+  windows.push(w.open('empty.html', '_blank', 'width=100,height=100'));
+}
+
+var recursion = false;
+function openPopupAndClick() {
+  windows.push(window.open('empty.html', '_blank', 'width=100,height=100'));
+  if (!recursion) {
+    recursion = true;
+    document.getElementById("openPopupAndClick").click();
+  }
+}
+
+function closeAllWindows() {
+  windows.forEach(w => {
+    try {
+      w.close();
+    } catch(e) {}
+  });
+}
+
+if (location.search.includes("openPopups")) {
+  let id = setInterval(() => {
+    if (document.getElementById('start')) {
+      clearInterval(id);
+      openPopups();
+    }
+  }, 500);
+}
+
+document.getElementById("input").onmouseup = _ => {
+  openPopups();
+}
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/browser_multiple_popups.js
@@ -0,0 +1,362 @@
+/**
+ * In this test, we check that the content can't open more than one popup at a
+ * time (depending on "dom.allow_mulitple_popups" preference value).
+ */
+
+const TEST_DOMAIN = "http://example.net";
+const TEST_PATH = "/browser/dom/base/test/";
+const CHROME_DOMAIN = "chrome://mochitests/content";
+
+requestLongerTimeout(2);
+
+function WindowObserver(count) {
+  return new Promise(resolve => {
+    let windowObserver = function(aSubject, aTopic, aData) {
+      if (aTopic != "domwindowopened") {
+        return;
+      }
+
+      if (--count == 0) {
+        Services.ww.unregisterNotification(windowObserver);
+        resolve();
+      }
+    }
+    Services.ww.registerNotification(windowObserver);
+  });
+}
+
+add_task(async _ => {
+  info("All opened if the pref is off");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", false],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let obs = new WindowObserver(2);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);
+
+  await obs;
+  ok(true, "We had 2 windows.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async _ => {
+  info("2 window.open()s in a click event allowed because whitelisted domain.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  const uri = Services.io.newURI(TEST_DOMAIN);
+  const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+
+  Services.perms.addFromPrincipal(principal, "popup", Services.perms.ALLOW_ACTION);
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let obs = new WindowObserver(2);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);
+
+  await obs;
+  ok(true, "We had 2 windows.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+
+  await new Promise(aResolve => {
+    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => {
+      Assert.equal(value, 0);
+      aResolve();
+    });
+  });
+});
+
+add_task(async _ => {
+  info("2 window.open()s in a mouseup event allowed because whitelisted domain.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  const uri = Services.io.newURI(TEST_DOMAIN);
+  const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+
+  Services.perms.addFromPrincipal(principal, "popup", Services.perms.ALLOW_ACTION);
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let obs = new WindowObserver(2);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#input", { type: "mouseup" }, tab.linkedBrowser);
+
+  await obs;
+  ok(true, "We had 2 windows.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+
+  await new Promise(aResolve => {
+    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => {
+      Assert.equal(value, 0);
+      aResolve();
+    });
+  });
+});
+
+add_task(async _ => {
+  info("2 window.open()s in a single click event: only the first one is allowed.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let p = ContentTask.spawn(browser, null, () => {
+    return new content.Promise(resolve => {
+      content.addEventListener("DOMPopupBlocked", () => {
+        ok(true, "The popup has been blocked");
+        resolve();
+      }, {once:true});
+    });
+  });
+
+  let obs = new WindowObserver(1);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);
+
+  await p;
+  await obs;
+  ok(true, "We had only 1 window.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async _ => {
+  info("2 window.open()s in a single mouseup event: only the first one is allowed.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let p = ContentTask.spawn(browser, null, () => {
+    return new content.Promise(resolve => {
+      content.addEventListener("DOMPopupBlocked", () => {
+        ok(true, "The popup has been blocked");
+        resolve();
+      }, {once:true});
+    });
+  });
+
+  let obs = new WindowObserver(1);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#input", { type: "mouseup" }, tab.linkedBrowser);
+
+  await p;
+  await obs;
+  ok(true, "We had only 1 window.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async _ => {
+  info("2 window.open()s by non-event code: no windows allowed.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html?openPopups")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  await ContentTask.spawn(browser, null, () => {
+    return new content.Promise(resolve => {
+      let count = 0;
+      content.addEventListener("DOMPopupBlocked", function cb() {
+        if (++count == 2) {
+          content.removeEventListener("DOMPopupBlocked", cb);
+          ok(true, "The popup has been blocked");
+          resolve();
+        }
+      });
+
+      let p = content.document.createElement("p");
+      p.setAttribute('id', 'start');
+      content.document.body.appendChild(p);
+    });
+  });
+
+  ok(true, "We had 0 windows.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async _ => {
+  info("2 window.open()s by non-event code allowed by permission");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  const uri = Services.io.newURI(TEST_DOMAIN);
+  const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+
+  Services.perms.addFromPrincipal(principal, "popup", Services.perms.ALLOW_ACTION);
+
+  let obs = new WindowObserver(2);
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html?openPopups")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  ok(true, "We had 2 windows.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+
+  await new Promise(aResolve => {
+    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => {
+      Assert.equal(value, 0);
+      aResolve();
+    });
+  });
+});
+
+add_task(async _ => {
+  info("1 window.open() executing another window.open(): only the first one is allowed.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  // We don't receive DOMPopupBlocked for nested windows. Let's use just the observer.
+  let obs = new WindowObserver(1);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#openNestedPopups", {}, tab.linkedBrowser);
+
+  await obs;
+  ok(true, "We had 1 window.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async _ => {
+  info("window.open() and .click() on the element opening the window.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let p = ContentTask.spawn(browser, null, () => {
+    return new content.Promise(resolve => {
+      content.addEventListener("DOMPopupBlocked", () => {
+        ok(true, "The popup has been blocked");
+        resolve();
+      }, {once:true});
+    });
+  });
+
+  let obs = new WindowObserver(1);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopupAndClick", {}, tab.linkedBrowser);
+
+  await p;
+  await obs;
+  ok(true, "We had only 1 window.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async _ => {
+  info("All opened from chrome.");
+
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["dom.block_multiple_popups", true],
+    ["dom.disable_open_during_load", true],
+  ]});
+
+  let tab = BrowserTestUtils.addTab(gBrowser, CHROME_DOMAIN + TEST_PATH + "browser_multiple_popups.html")
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  let obs = new WindowObserver(2);
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, tab.linkedBrowser);
+
+  await obs;
+  ok(true, "We had 2 windows.");
+
+  await BrowserTestUtils.synthesizeMouseAtCenter("#closeAllWindows", {}, tab.linkedBrowser);
+
+  BrowserTestUtils.removeTab(tab);
+});
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -17,17 +17,16 @@
 #include "BrowserElementParent.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
 #include "mozilla/dom/CustomEvent.h"
-#include "mozilla/layout/RenderFrameParent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 
 namespace {
 
@@ -172,22 +171,19 @@ BrowserElementParent::DispatchOpenWindow
 
   return BrowserElementParent::OPEN_WINDOW_IGNORED;
 }
 
 /*static*/
 BrowserElementParent::OpenWindowResult
 BrowserElementParent::OpenWindowOOP(TabParent* aOpenerTabParent,
                                     TabParent* aPopupTabParent,
-                                    PRenderFrameParent* aRenderFrame,
                                     const nsAString& aURL,
                                     const nsAString& aName,
-                                    const nsAString& aFeatures,
-                                    TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                                    layers::LayersId* aLayersId)
+                                    const nsAString& aFeatures)
 {
   // Create an iframe owned by the same document which owns openerFrameElement.
   nsCOMPtr<Element> openerFrameElement = aOpenerTabParent->GetOwnerElement();
   NS_ENSURE_TRUE(openerFrameElement,
                  BrowserElementParent::OPEN_WINDOW_IGNORED);
   RefPtr<HTMLIFrameElement> popupFrameElement =
     CreateIframe(openerFrameElement, aName, /* aRemote = */ true);
 
@@ -212,22 +208,16 @@ BrowserElementParent::OpenWindowOOP(TabP
   }
 
   // The popup was not blocked, so hook up the frame element and the popup tab
   // parent, and return success.
   aPopupTabParent->SetOwnerElement(popupFrameElement);
   popupFrameElement->AllowCreateFrameLoader();
   popupFrameElement->CreateRemoteFrameLoader(aPopupTabParent);
 
-  RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
-  if (!aPopupTabParent->SetRenderFrame(rfp) ||
-      !aPopupTabParent->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
-    return BrowserElementParent::OPEN_WINDOW_IGNORED;
-  }
-
   return opened;
 }
 
 /* static */
 BrowserElementParent::OpenWindowResult
 BrowserElementParent::OpenWindowInProcess(nsPIDOMWindowOuter* aOpenerWindow,
                                           nsIURI* aURI,
                                           const nsAString& aName,
--- a/dom/browser-element/BrowserElementParent.h
+++ b/dom/browser-element/BrowserElementParent.h
@@ -17,24 +17,16 @@ class nsIDOMWindow;
 class nsIURI;
 
 namespace mozilla {
 
 namespace dom {
 class TabParent;
 } // namespace dom
 
-namespace layers {
-struct TextureFactoryIdentifier;
-} // namespace layers
-
-namespace layout {
-class PRenderFrameParent;
-} // namespace layout
-
 /**
  * BrowserElementParent implements a portion of the parent-process side of
  * <iframe mozbrowser>.
  *
  * Most of the parent-process side of <iframe mozbrowser> is implemented in
  * BrowserElementParent.js.  This file implements the few parts of this
  * functionality which must be written in C++.
  *
@@ -90,22 +82,19 @@ public:
    *                        live.
    * @return an OpenWindowresult that describes whether the embedder added the
    *         frame to a document and whether it called preventDefault to prevent
    *         the platform from handling the open request.
    */
   static OpenWindowResult
   OpenWindowOOP(dom::TabParent* aOpenerTabParent,
                 dom::TabParent* aPopupTabParent,
-                layout::PRenderFrameParent* aRenderFrame,
                 const nsAString& aURL,
                 const nsAString& aName,
-                const nsAString& aFeatures,
-                layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                layers::LayersId* aLayersId);
+                const nsAString& aFeatures);
 
   /**
    * Handle a window.open call from an in-process <iframe mozbrowser>.
    *
    * (These parameter types are silly, but they match what our caller has in
    * hand.  Feel free to add an override, if they are inconvenient to you.)
    *
    * @param aURI the URI the new window should load.  May be null.
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1074,16 +1074,17 @@ CanvasRenderingContext2D::CanvasRenderin
   , mIsSkiaGL(false)
   , mHasPendingStableStateCallback(false)
   , mDrawObserver(nullptr)
   , mIsEntireFrameInvalid(false)
   , mPredictManyRedrawCalls(false)
   , mIsCapturedFrameInvalid(false)
   , mPathTransformWillUpdate(false)
   , mInvalidateCount(0)
+  , mWriteOnly(false)
 {
   if (!sMaxContextsInitialized) {
     sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
     sMaxContextsInitialized = true;
   }
 
   sNumLivingContexts++;
 
@@ -2560,17 +2561,18 @@ CanvasRenderingContext2D::CreatePattern(
       aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return nullptr;
     }
 
     // An ImageBitmap never taints others so we set principalForSecurityCheck to
     // nullptr and set CORSUsed to true for passing the security check in
     // CanvasUtils::DoDrawImageSecurityCheck().
     RefPtr<CanvasPattern> pat =
-      new CanvasPattern(this, srcSurf, repeatMode, nullptr, false, true);
+      new CanvasPattern(this, srcSurf, repeatMode, nullptr,
+                        imgBitmap.IsWriteOnly(), true);
 
     return pat.forget();
   }
 
   EnsureTarget();
   if (!IsTargetValid()) {
     aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
@@ -4915,24 +4917,32 @@ CanvasRenderingContext2D::DrawImage(cons
   if (aImage.IsHTMLCanvasElement()) {
     HTMLCanvasElement* canvas = &aImage.GetAsHTMLCanvasElement();
     element = canvas;
     nsIntSize size = canvas->GetSize();
     if (size.width == 0 || size.height == 0) {
       aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
+
+    if (canvas->IsWriteOnly()) {
+      SetWriteOnly();
+    }
   } else if (aImage.IsImageBitmap()) {
     ImageBitmap& imageBitmap = aImage.GetAsImageBitmap();
     srcSurf = imageBitmap.PrepareForDrawTarget(mTarget);
 
     if (!srcSurf) {
       return;
     }
 
+    if (imageBitmap.IsWriteOnly()) {
+      SetWriteOnly();
+    }
+
     imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
   }
   else {
     if (aImage.IsHTMLImageElement()) {
       HTMLImageElement* img = &aImage.GetAsHTMLImageElement();
       element = img;
     } else if (aImage.IsSVGImageElement()) {
       SVGImageElement* img = &aImage.GetAsSVGImageElement();
@@ -5443,17 +5453,18 @@ CanvasRenderingContext2D::GetImageData(J
   if (!mCanvasElement && !mDocShell) {
     NS_ERROR("No canvas element and no docshell in GetImageData!!!");
     aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Check only if we have a canvas element; if we were created with a docshell,
   // then it's special internal use.
-  if (mCanvasElement && !mCanvasElement->CallerCanRead(aCx)) {
+  if (IsWriteOnly() ||
+      (mCanvasElement && !mCanvasElement->CallerCanRead(aCx))) {
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   if (!IsFinite(aSx) || !IsFinite(aSy) ||
       !IsFinite(aSw) || !IsFinite(aSh)) {
     aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -36,16 +36,17 @@ class nsXULElement;
 namespace mozilla {
 namespace gl {
 class SourceSurface;
 } // namespace gl
 
 namespace dom {
 class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
 typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
+class ImageBitmap;
 class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class OwningStringOrCanvasGradientOrCanvasPattern;
 class TextMetrics;
 class CanvasPath;
 
 extern const mozilla::gfx::Float SIGMA_MAX;
 
@@ -1187,16 +1188,29 @@ protected:
     if (aPerDevPixel)
       *aPerDevPixel = devPixel;
     if (aPerCSSPixel)
       *aPerCSSPixel = cssPixel;
   }
 
   friend struct CanvasBidiProcessor;
   friend class CanvasDrawObserver;
+  friend class ImageBitmap;
+
+  void SetWriteOnly()
+  {
+    mWriteOnly = true;
+  }
+
+  bool IsWriteOnly() const
+  {
+    return mWriteOnly;
+  }
+
+  bool mWriteOnly;
 };
 
 size_t BindingJSObjectMallocBytes(CanvasRenderingContext2D* aContext);
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* CanvasRenderingContext2D_h */
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -466,46 +466,45 @@ CheckSecurityForElements(const nsLayoutU
 }
 
 /*
  * A wrapper to the nsLayoutUtils::SurfaceFromElement() function followed by the
  * security checking.
  */
 template<class ElementType>
 static already_AddRefed<SourceSurface>
-GetSurfaceFromElement(nsIGlobalObject* aGlobal, ElementType& aElement, ErrorResult& aRv)
+GetSurfaceFromElement(nsIGlobalObject* aGlobal, ElementType& aElement,
+                      bool* aWriteOnly, ErrorResult& aRv)
 {
   nsLayoutUtils::SurfaceFromElementResult res =
     nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
 
   RefPtr<SourceSurface> surface = res.GetSourceSurface();
   if (NS_WARN_IF(!surface)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
 
-  // check origin-clean
-  if (!CheckSecurityForElements(res)) {
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return nullptr;
-  }
+  // check write-only mode
+  *aWriteOnly = !CheckSecurityForElements(res);
 
   return surface.forget();
 }
 
 ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
-                         gfxAlphaType aAlphaType)
+                         bool aWriteOnly, gfxAlphaType aAlphaType)
   : mParent(aGlobal)
   , mData(aData)
   , mSurface(nullptr)
   , mDataWrapper(new ImageUtils(mData))
   , mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height)
   , mAlphaType(aAlphaType)
   , mAllocatedImageData(false)
+  , mWriteOnly(aWriteOnly)
 {
   MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
 
   mShutdownObserver = new ImageBitmapShutdownObserver(this);
   mShutdownObserver->RegisterObserver();
 }
 
 ImageBitmap::~ImageBitmap()
@@ -758,135 +757,141 @@ ImageBitmap::ToCloneData() const
   }
 
   UniquePtr<ImageBitmapCloneData> result(new ImageBitmapCloneData());
   result->mPictureRect = mPictureRect;
   result->mAlphaType = mAlphaType;
   RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
   result->mSurface = surface->GetDataSurface();
   MOZ_ASSERT(result->mSurface);
+  result->mWriteOnly = mWriteOnly;
 
   return result;
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateFromSourceSurface(nsIGlobalObject* aGlobal,
                                      gfx::SourceSurface* aSource,
                                      ErrorResult& aRv)
 {
   RefPtr<layers::Image> data = CreateImageFromSurface(aSource);
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data,
+                                            false /* writeOnly */);
   ret->mAllocatedImageData = true;
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal,
                                  ImageBitmapCloneData* aData)
 {
   RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
 
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mAlphaType);
+  RefPtr<ImageBitmap> ret =
+    new ImageBitmap(aGlobal, data, aData->mWriteOnly, aData->mAlphaType);
 
   ret->mAllocatedImageData = true;
 
   ErrorResult rv;
   ret->SetPictureRect(aData->mPictureRect, rv);
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
                                        OffscreenCanvas& aOffscreenCanvas,
                                        ErrorResult& aRv)
 {
-  // Check origin-clean.
-  if (aOffscreenCanvas.IsWriteOnly()) {
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return nullptr;
-  }
+  // Check write-only mode.
+  bool writeOnly = aOffscreenCanvas.IsWriteOnly();
 
   nsLayoutUtils::SurfaceFromElementResult res =
     nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas,
                                               nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
 
   RefPtr<SourceSurface> surface = res.GetSourceSurface();
 
   if (NS_WARN_IF(!surface)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
   RefPtr<layers::Image> data =
     CreateImageFromSurface(surface);
 
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
 
   ret->mAllocatedImageData = true;
 
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
   // Check if the image element is completely available or not.
   if (!aImageEl.Complete()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
+  bool writeOnly = true;
+
   // Get the SourceSurface out from the image element and then do security
   // checking.
-  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
+  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl,
+                                                        &writeOnly, aRv);
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // Create ImageBitmap.
   RefPtr<layers::Image> data = CreateImageFromSurface(surface);
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
+  bool writeOnly = true;
+
   // Get the SourceSurface out from the image element and then do security
   // checking.
-  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
+  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl,
+                                                        &writeOnly, aRv);
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // Create ImageBitmap.
   RefPtr<layers::Image> data = CreateImageFromSurface(surface);
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
   return ret.forget();
 }
@@ -908,28 +913,25 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   if (aVideoEl.ReadyState() <= HAVE_METADATA) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Check security.
   nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
   bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
-  if (!CheckSecurityForElements(false, CORSUsed, principal)) {
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return nullptr;
-  }
+  bool writeOnly = !CheckSecurityForElements(false, CORSUsed, principal);
 
   // Create ImageBitmap.
   RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
   if (!data) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
   return ret.forget();
 }
@@ -938,22 +940,28 @@ ImageBitmap::CreateInternal(nsIGlobalObj
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
   if (aCanvasEl.Width() == 0 || aCanvasEl.Height() == 0) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl, aRv);
+  bool writeOnly = true;
+  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl,
+                                                        &writeOnly, aRv);
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
+  if (!writeOnly) {
+    writeOnly = aCanvasEl.IsWriteOnly();
+  }
+
   // Crop the source surface if needed.
   RefPtr<SourceSurface> croppedSurface;
   IntRect cropRect = aCropRect.valueOr(IntRect());
 
   // If the HTMLCanvasElement's rendering context is WebGL, then the snapshot
   // we got from the HTMLCanvasElement is a DataSourceSurface which is a copy
   // of the rendering context. We handle cropping in this case.
   bool needToReportMemoryAllocation = false;
@@ -977,17 +985,17 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   // Create an Image from the SourceSurface.
   RefPtr<layers::Image> data = CreateImageFromSurface(croppedSurface);
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly);
 
   if (needToReportMemoryAllocation) {
     ret->mAllocatedImageData = true;
   }
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(cropRect, aRv);
@@ -1042,17 +1050,18 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   }
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Create an ImageBimtap.
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, alphaType);
+  RefPtr<ImageBitmap> ret =
+    new ImageBitmap(aGlobal, data, false /* write-only */, alphaType);
 
   ret->mAllocatedImageData = true;
 
   // The cropping information has been handled in the CreateImageFromRawData()
   // function.
 
   return ret.forget();
 }
@@ -1065,21 +1074,18 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(win);
   if (NS_WARN_IF(!window) || !window->GetExtantDoc()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   window->GetExtantDoc()->WarnOnceAbout(nsIDocument::eCreateImageBitmapCanvasRenderingContext2D);
 
-  // Check origin-clean.
-  if (aCanvasCtx.GetCanvas()->IsWriteOnly()) {
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return nullptr;
-  }
+  // Check write-only mode.
+  bool writeOnly = aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly();
 
   RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
 
   if (NS_WARN_IF(!surface)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
@@ -1091,17 +1097,18 @@ ImageBitmap::CreateInternal(nsIGlobalObj
 
   RefPtr<layers::Image> data = CreateImageFromSurface(surface);
 
   if (NS_WARN_IF(!data)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+  RefPtr<ImageBitmap> ret =
+    new ImageBitmap(aGlobal, data, writeOnly);
 
   ret->mAllocatedImageData = true;
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
@@ -1113,17 +1120,19 @@ ImageBitmap::CreateInternal(nsIGlobalObj
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
   if (!aImageBitmap.mData) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   RefPtr<layers::Image> data = aImageBitmap.mData;
-  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mAlphaType);
+  RefPtr<ImageBitmap> ret =
+    new ImageBitmap(aGlobal, data, aImageBitmap.mWriteOnly,
+                    aImageBitmap.mAlphaType);
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
     ret->SetPictureRect(aCropRect.ref(), aRv);
   }
 
   return ret.forget();
 }
@@ -1427,26 +1436,24 @@ ImageBitmap::ReadStructuredClone(JSConte
   MOZ_ASSERT(aReader);
   // aParent might be null.
 
   uint32_t picRectX_;
   uint32_t picRectY_;
   uint32_t picRectWidth_;
   uint32_t picRectHeight_;
   uint32_t alphaType_;
-  uint32_t dummy;
+  uint32_t writeOnly;
 
   if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
       !JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) ||
-      !JS_ReadUint32Pair(aReader, &alphaType_, &dummy)) {
+      !JS_ReadUint32Pair(aReader, &alphaType_, &writeOnly)) {
     return nullptr;
   }
 
-  MOZ_ASSERT(dummy == 0);
-
   int32_t picRectX = BitwiseCast<int32_t>(picRectX_);
   int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
   int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
   int32_t picRectHeight = BitwiseCast<int32_t>(picRectHeight_);
   const auto alphaType = BitwiseCast<gfxAlphaType>(alphaType_);
 
   // Create a new ImageBitmap.
   MOZ_ASSERT(!aClonedSurfaces.IsEmpty());
@@ -1460,17 +1467,18 @@ ImageBitmap::ReadStructuredClone(JSConte
   JS::Rooted<JS::Value> value(aCx);
   {
 #ifdef FUZZING
     if (aIndex >= aClonedSurfaces.Length()) {
       return nullptr;
     }
 #endif
     RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]);
-    RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aParent, img, alphaType);
+    RefPtr<ImageBitmap> imageBitmap =
+      new ImageBitmap(aParent, img, !!writeOnly, alphaType);
 
     ErrorResult error;
     imageBitmap->SetPictureRect(IntRect(picRectX, picRectY,
                                         picRectWidth, picRectHeight), error);
     if (NS_WARN_IF(error.Failed())) {
       error.SuppressException();
       return nullptr;
     }
@@ -1500,17 +1508,17 @@ ImageBitmap::WriteStructuredClone(JSStru
   const uint32_t alphaType = BitwiseCast<uint32_t>(aImageBitmap->mAlphaType);
 
   // Indexing the cloned surfaces and send the index to the receiver.
   uint32_t index = aClonedSurfaces.Length();
 
   if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) ||
       NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
       NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) ||
-      NS_WARN_IF(!JS_WriteUint32Pair(aWriter, alphaType, 0))) {
+      NS_WARN_IF(!JS_WriteUint32Pair(aWriter, alphaType, aImageBitmap->mWriteOnly))) {
     return false;
   }
 
   RefPtr<SourceSurface> surface =
     aImageBitmap->mData->GetAsSourceSurface();
   RefPtr<DataSourceSurface> snapshot = surface->GetDataSurface();
   RefPtr<DataSourceSurface> dstDataSurface;
   {
@@ -1834,17 +1842,18 @@ CreateImageBitmapFromBlob::MimeTypeAndDe
   });
 
   if (NS_WARN_IF(NS_FAILED(aStatus))) {
     mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   // Create ImageBitmap object.
-  RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, aImage);
+  RefPtr<ImageBitmap> imageBitmap =
+    new ImageBitmap(mGlobalObject, aImage, false /* write-only */);
 
   if (mCropRect.isSome()) {
     ErrorResult rv;
     imageBitmap->SetPictureRect(mCropRect.ref(), rv);
 
     if (rv.Failed()) {
       mPromise->MaybeReject(rv);
       return;
--- a/dom/canvas/ImageBitmap.h
+++ b/dom/canvas/ImageBitmap.h
@@ -55,16 +55,17 @@ class Promise;
 class PostMessageEvent; // For StructuredClone between windows.
 class SVGImageElement;
 
 struct ImageBitmapCloneData final
 {
   RefPtr<gfx::DataSourceSurface> mSurface;
   gfx::IntRect mPictureRect;
   gfxAlphaType mAlphaType;
+  bool mWriteOnly;
 };
 
 /*
  * ImageBitmap is an opaque handler to several kinds of image-like objects from
  * HTMLImageElement, HTMLVideoElement, HTMLCanvasElement, ImageData to
  * CanvasRenderingContext2D and Image Blob.
  *
  * An ImageBitmap could be painted to a canvas element.
@@ -147,16 +148,21 @@ public:
   friend CreateImageBitmapFromBlob;
   friend CreateImageBitmapFromBlobTask;
   friend CreateImageBitmapFromBlobWorkerTask;
 
   size_t GetAllocatedSize() const;
 
   void OnShutdown();
 
+  bool IsWriteOnly() const
+  {
+    return mWriteOnly;
+  }
+
 protected:
 
   /*
    * The default value of aIsPremultipliedAlpha is TRUE because that the
    * data stored in HTMLImageElement, HTMLVideoElement, HTMLCanvasElement,
    * CanvasRenderingContext2D are alpha-premultiplied in default.
    *
    * Actually, if one HTMLCanvasElement's rendering context is WebGLContext, it
@@ -169,16 +175,17 @@ protected:
    *    re-decoding if the original decoded data is alpha-premultiplied) and
    * 2) while decoding a blob. But we do not do it in both code path too.
    *
    * ImageData's underlying data is triggered as non-premultipliedAlpha, so set
    * the aIsPremultipliedAlpha to be false in the
    * CreateInternal(from ImageData) method.
    */
   ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
+              bool aWriteOnly,
               gfxAlphaType aAlphaType = gfxAlphaType::Premult);
 
   virtual ~ImageBitmap();
 
   void SetPictureRect(const gfx::IntRect& aRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
@@ -250,16 +257,23 @@ protected:
   const gfxAlphaType mAlphaType;
 
   RefPtr<ImageBitmapShutdownObserver> mShutdownObserver;
 
   /*
    * Whether this object allocated allocated and owns the image data.
    */
   bool mAllocatedImageData;
+
+  /*
+   * Write-Only flag is set to true if this image has been generated from a
+   * cross-origin source. This is the opposite of what is called 'origin-clean'
+   * in the spec.
+   */
+  bool mWriteOnly;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ImageBitmap_h
 
 
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -240,18 +240,21 @@ struct TexImageSourceAdapter final : pub
     TexImageSourceAdapter(const WebGLsizeiptr* pboOffset, GLuint ignored1, GLuint ignored2 = 0) {
         mPboOffset = pboOffset;
     }
 
     TexImageSourceAdapter(const WebGLsizeiptr* pboOffset, ErrorResult* ignored) {
         mPboOffset = pboOffset;
     }
 
-    TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult*) {
+    TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap,
+                          ErrorResult* out_error)
+    {
         mImageBitmap = imageBitmap;
+        mOut_error = out_error;
     }
 
     TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) {
         mImageData = imageData;
     }
 
     TexImageSourceAdapter(const dom::Element* domElem, ErrorResult* const out_error) {
         mDomElem = domElem;
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -7,16 +7,17 @@
 
 #include <algorithm>
 
 #include "CanvasUtils.h"
 #include "gfxPrefs.h"
 #include "GLBlitHelper.h"
 #include "GLContext.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/Unused.h"
 #include "ScopedGLHelpers.h"
 #include "TexUnpackBlob.h"
@@ -217,21 +218,26 @@ FromPboOffset(WebGLContext* webgl, TexIm
     const auto ptr = (const uint8_t*)pboOffset;
     return MakeUnique<webgl::TexUnpackBytes>(webgl, target, width, height, depth,
                                              isClientData, ptr, availBufferBytes);
 }
 
 static UniquePtr<webgl::TexUnpackBlob>
 FromImageBitmap(WebGLContext* webgl, TexImageTarget target,
                 uint32_t width, uint32_t height, uint32_t depth,
-                const dom::ImageBitmap& imageBitmap)
+                const dom::ImageBitmap& imageBitmap, ErrorResult* aRv)
 {
+    if (imageBitmap.IsWriteOnly()) {
+        aRv->Throw(NS_ERROR_DOM_SECURITY_ERR);
+        return nullptr;
+    }
+
     UniquePtr<dom::ImageBitmapCloneData> cloneData = imageBitmap.ToCloneData();
     if (!cloneData) {
-      return nullptr;
+        return nullptr;
     }
 
     const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface;
 
     if (!width) {
         width = surf->GetSize().width;
     }
 
@@ -295,16 +301,24 @@ FromImageData(WebGLContext* webgl, TexIm
                                                alphaType);
 }
 
 UniquePtr<webgl::TexUnpackBlob>
 WebGLContext::FromDomElem(TexImageTarget target, uint32_t width,
                           uint32_t height, uint32_t depth, const dom::Element& elem,
                           ErrorResult* const out_error)
 {
+    if (elem.IsHTMLElement(nsGkAtoms::canvas)) {
+        const dom::HTMLCanvasElement* canvas = static_cast<const dom::HTMLCanvasElement*>(&elem);
+        if (canvas->IsWriteOnly()) {
+            out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
+            return nullptr;
+        }
+    }
+
     // The canvas spec says that drawImage should draw the first frame of
     // animated images. The webgl spec doesn't mention the issue, so we do the
     // same as drawImage.
     uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
                      nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
                      nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
 
     if (mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
@@ -416,17 +430,17 @@ WebGLContext::From(TexImageTarget target
 
     if (mBoundPixelUnpackBuffer) {
         ErrorInvalidOperation("PIXEL_UNPACK_BUFFER must be null.");
         return nullptr;
     }
 
     if (src.mImageBitmap) {
         return FromImageBitmap(this, target, width, height, depth,
-                               *(src.mImageBitmap));
+                               *(src.mImageBitmap), src.mOut_error);
     }
 
     if (src.mImageData) {
         return FromImageData(this, target, width, height, depth,
                              *(src.mImageData), scopedArr);
     }
 
     if (src.mDomElem) {
--- a/dom/canvas/test/test_imagebitmap.html
+++ b/dom/canvas/test/test_imagebitmap.html
@@ -265,23 +265,32 @@ function testSecurityErrors() {
         reject();
       }
 
       uncleanImage.src = "http://example.com/tests/dom/canvas/test/crossorigin/image.png";
     });
   }
 
   function checkPromiseFailedWithSecurityError(p) {
-    return p.then( function(reason) { ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully."); },
-                   function(reason) { if (reason == "SecurityError: The operation is insecure.") {
-                                        ok(true, reason);
-                                      }
-                                      else {
-                                        ok(false, "Did not get SecurityError with unclean source. Error Message: " + reason);
-                                      }});
+    return p.then(imageBitmap => {
+      ok(!!imageBitmap, "ImageBitmaps are always created");
+      const context = document.createElement("canvas").getContext("2d");
+      context.drawImage(imageBitmap, 0, 0);
+      try {
+        context.getImageData(0, 0, 1, 1);
+        ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully.");
+      } catch (ex) {
+        if (ex == "SecurityError: The operation is insecure.") {
+          ok(true, ex);
+        }
+        else {
+          ok(false, "Did not get SecurityError with unclean source. Error Message: " + ex);
+        }
+      }
+    });
   }
 
   return Promise.all([
     checkPromiseFailedWithSecurityError(getUncleanImagePromise()),
     checkPromiseFailedWithSecurityError(getUncleanVideoPromise()),
     checkPromiseFailedWithSecurityError(getTaintedCanvasPromise()),
     checkPromiseFailedWithSecurityError(getTaintedCanvasRenderingContex2dPromise()),
   ]);
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -1078,17 +1078,17 @@ HTMLCanvasElement::MozGetIPCContext(cons
 
 nsIntSize
 HTMLCanvasElement::GetSize()
 {
   return GetWidthHeight();
 }
 
 bool
-HTMLCanvasElement::IsWriteOnly()
+HTMLCanvasElement::IsWriteOnly() const
 {
   return mWriteOnly;
 }
 
 void
 HTMLCanvasElement::SetWriteOnly()
 {
   mExpandedReader = nullptr;
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -218,17 +218,17 @@ public:
   /**
    * Get the size in pixels of this canvas element
    */
   nsIntSize GetSize();
 
   /**
    * Determine whether the canvas is write-only.
    */
-  bool IsWriteOnly();
+  bool IsWriteOnly() const;
 
   /**
    * Force the canvas to be write-only.
    */
   void SetWriteOnly();
 
   /**
    * Force the canvas to be write-only, except for readers from
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -63,17 +63,16 @@
 #include "mozilla/intl/LocaleService.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/jsipc/PJavaScript.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/CompositorManagerChild.h"
 #include "mozilla/layers/ContentProcessController.h"
 #include "mozilla/layers/ImageBridgeChild.h"
-#include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/loader/ScriptCacheActors.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/net/CookieServiceChild.h"
 #include "mozilla/net/CaptivePortalService.h"
 #include "mozilla/PerformanceMetricsCollector.h"
 #include "mozilla/PerformanceUtils.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/plugins/PluginModuleParent.h"
@@ -967,19 +966,16 @@ ContentChild::ProvideWindowCommon(TabChi
   SetEventTargetForActor(newChild, target);
 
   Unused << SendPBrowserConstructor(
     // We release this ref in DeallocPBrowserChild
     RefPtr<TabChild>(newChild).forget().take(),
     tabId, TabId(0), *ipcContext, aChromeFlags,
     GetID(), IsForBrowser());
 
-
-  PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
-
   nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
   if (aParent) {
     nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow =
       nsPIDOMWindowOuter::From(aParent)->GetTop();
     if (parentTopWindow) {
       parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow();
     }
   }
@@ -990,19 +986,16 @@ ContentChild::ProvideWindowCommon(TabChi
   // NOTE: Capturing by reference here is safe, as this function won't return
   // until one of these callbacks is called.
   auto resolve = [&] (const CreatedWindowInfo& info) {
     MOZ_RELEASE_ASSERT(NS_IsMainThread());
     rv = info.rv();
     *aWindowIsNew = info.windowOpened();
     nsTArray<FrameScriptInfo> frameScripts(info.frameScripts());
     nsCString urlToLoad = info.urlToLoad();
-    TextureFactoryIdentifier textureFactoryIdentifier = info.textureFactoryIdentifier();
-    layers::LayersId layersId = info.layersId();
-    CompositorOptions compositorOptions = info.compositorOptions();
     uint32_t maxTouchPoints = info.maxTouchPoints();
     DimensionInfo dimensionInfo = info.dimensions();
     bool hasSiblings = info.hasSiblings();
 
     // Once this function exits, we should try to exit the nested event loop.
     ready = true;
 
     // NOTE: We have to handle this immediately in the resolve callback in order
@@ -1021,20 +1014,16 @@ ContentChild::ProvideWindowCommon(TabChi
     }
 
     // If the TabChild has been torn down, we don't need to do this anymore.
     if (NS_WARN_IF(!newChild->IPCOpen() || newChild->IsDestroyed())) {
       rv = NS_ERROR_ABORT;
       return;
     }
 
-    if (!layersId.IsValid()) { // if renderFrame is invalid.
-      renderFrame = nullptr;
-    }
-
     ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0, 0);
     auto* opener = nsPIDOMWindowOuter::From(aParent);
     nsIDocShell* openerShell;
     if (opener && (openerShell = opener->GetDocShell())) {
       nsCOMPtr<nsILoadContext> context = do_QueryInterface(openerShell);
       showInfo = ShowInfo(EmptyString(), false,
                           context->UsePrivateBrowsing(), true, false,
                           aTabOpener->WebWidget()->GetDPI(),
@@ -1053,18 +1042,17 @@ ContentChild::ProvideWindowCommon(TabChi
     if (!aForceNoOpener && windowProxy && aParent) {
       nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::From(windowProxy);
       nsPIDOMWindowOuter* parent = nsPIDOMWindowOuter::From(aParent);
       outer->SetOpenerWindow(parent, *aWindowIsNew);
     }
 
     // Unfortunately we don't get a window unless we've shown the frame.  That's
     // pretty bogus; see bug 763602.
-    newChild->DoFakeShow(textureFactoryIdentifier, layersId, compositorOptions,
-                        renderFrame, showInfo);
+    newChild->DoFakeShow(showInfo);
 
     newChild->RecvUpdateDimensions(dimensionInfo);
 
     for (size_t i = 0; i < frameScripts.Length(); i++) {
       FrameScriptInfo& info = frameScripts[i];
       if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
         MOZ_CRASH();
       }
@@ -1097,17 +1085,17 @@ ContentChild::ProvideWindowCommon(TabChi
       // We can't actually send a nullptr up as the URI, since IPDL doesn't let us
       // send nullptr's for primitives. We indicate that the nsString for the URI
       // should be converted to a nullptr by voiding the string.
       url.SetIsVoid(true);
     }
 
     // NOTE: BrowserFrameOpenWindowPromise is the same type as
     // CreateWindowPromise, and this code depends on that fact.
-    newChild->SendBrowserFrameOpenWindow(aTabOpener, renderFrame,
+    newChild->SendBrowserFrameOpenWindow(aTabOpener,
                                          NS_ConvertUTF8toUTF16(url),
                                          name, NS_ConvertUTF8toUTF16(features),
                                          std::move(resolve), std::move(reject));
   } else {
     nsAutoCString baseURIString;
     float fullZoom;
     nsCOMPtr<nsIPrincipal> triggeringPrincipal;
     uint32_t referrerPolicy = mozilla::net::RP_Unset;
@@ -1120,17 +1108,17 @@ ContentChild::ProvideWindowCommon(TabChi
 
     OptionalURIParams uriToLoad;
     if (aURI) {
       SerializeURI(aURI, uriToLoad);
     } else {
       uriToLoad = mozilla::void_t();
     }
 
-    SendCreateWindow(aTabOpener, newChild, renderFrame,
+    SendCreateWindow(aTabOpener, newChild,
                      aChromeFlags, aCalledFromJS, aPositionSpecified,
                      aSizeSpecified, uriToLoad, features, baseURIString,
                      fullZoom, Principal(triggeringPrincipal), referrerPolicy,
                      std::move(resolve), std::move(reject));
   }
 
   // =======================
   // Begin Nested Event Loop
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -78,17 +78,16 @@
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/IPCStreamUtils.h"
 #include "mozilla/intl/LocaleService.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/PAPZParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
-#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/loader/ScriptCacheActors.h"
 #include "mozilla/LoginReputationIPC.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/PCookieServiceParent.h"
@@ -1256,17 +1255,16 @@ ContentParent::CreateBrowser(const TabCo
       chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
     }
 
     if (tabId == 0) {
       return nullptr;
     }
     RefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
                                        aContext, chromeFlags));
-    tp->SetInitedByParent();
 
     PBrowserParent* browser =
     constructorSender->SendPBrowserConstructor(
       // DeallocPBrowserParent() releases this ref.
       tp.forget().take(), tabId,
       aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0),
       aContext.AsIPCTabContext(),
       chromeFlags,
@@ -1652,91 +1650,16 @@ ContentParent::ProcessingError(Result aC
     return;
   }
 #ifndef FUZZING
   // Other errors are big deals.
   KillHard(aReason);
 #endif
 }
 
-/* static */
-bool
-ContentParent::AllocateLayerTreeId(TabParent* aTabParent, layers::LayersId* aId)
-{
-  return AllocateLayerTreeId(aTabParent->Manager()->AsContentParent(),
-                             aTabParent, aTabParent->GetTabId(), aId);
-}
-
-/* static */
-bool
-ContentParent::AllocateLayerTreeId(ContentParent* aContent,
-                                   TabParent* aTopLevel, const TabId& aTabId,
-                                   layers::LayersId* aId)
-{
-  GPUProcessManager* gpu = GPUProcessManager::Get();
-
-  *aId = gpu->AllocateLayerTreeId();
-
-  if (!aContent || !aTopLevel) {
-    return false;
-  }
-
-  gpu->MapLayerTreeId(*aId, aContent->OtherPid());
-
-  return true;
-}
-
-mozilla::ipc::IPCResult
-ContentParent::RecvAllocateLayerTreeId(const ContentParentId& aCpId,
-                                       const TabId& aTabId, layers::LayersId* aId)
-{
-  // Protect against spoofing by a compromised child. aCpId must either
-  // correspond to the process that this ContentParent represents or be a
-  // child of it.
-  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
-  RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId);
-  if (!contentParent ||
-      (ChildID() != aCpId && !contentParent->CanCommunicateWith(ChildID()))) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-
-  // GetTopLevelTabParentByProcessAndTabId will make sure that aTabId
-  // lives in the process for aCpId.
-  RefPtr<TabParent> browserParent =
-    cpm->GetTopLevelTabParentByProcessAndTabId(aCpId, aTabId);
-  MOZ_ASSERT(contentParent && browserParent);
-
-  if (!AllocateLayerTreeId(contentParent, browserParent, aTabId, aId)) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-ContentParent::RecvDeallocateLayerTreeId(const ContentParentId& aCpId,
-                                         const layers::LayersId& aId)
-{
-  GPUProcessManager* gpu = GPUProcessManager::Get();
-
-  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
-  RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId);
-  if (!contentParent || !contentParent->CanCommunicateWith(ChildID())) {
-    return IPC_FAIL(this, "Spoofed DeallocateLayerTreeId call");
-  }
-
-  if (!gpu->IsLayerTreeIdMapped(aId, contentParent->OtherPid())) {
-    // You can't deallocate layer tree ids that you didn't allocate
-    KillHard("DeallocateLayerTreeId");
-  }
-
-  gpu->UnmapLayerTreeId(aId, contentParent->OtherPid());
-
-  return IPC_OK();
-}
-
 namespace {
 
 void
 DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
 {
   RefPtr<DeleteTask<GeckoChildProcessHost>> task = new DeleteTask<GeckoChildProcessHost>(aSubprocess);
   XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
@@ -5156,17 +5079,16 @@ ContentParent::CommonCreateWindow(PBrows
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
                                 PBrowserParent* aNewTab,
-                                PRenderFrameParent* aRenderFrame,
                                 const uint32_t& aChromeFlags,
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
                                 const OptionalURIParams& aURIToLoad,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const float& aFullZoom,
@@ -5174,17 +5096,16 @@ ContentParent::RecvCreateWindow(PBrowser
                                 const uint32_t& aReferrerPolicy,
                                 CreateWindowResolver&& aResolve)
 {
   nsresult rv = NS_OK;
   CreatedWindowInfo cwi;
 
   // We always expect to open a new window here. If we don't, it's an error.
   cwi.windowOpened() = true;
-  cwi.layersId() = LayersId{0};
   cwi.maxTouchPoints() = 0;
   cwi.hasSiblings() = false;
 
   // Make sure to resolve the resolver when this function exits, even if we
   // failed to generate a valid response.
   auto resolveOnExit = MakeScopeExit([&] {
     // Copy over the nsresult, and then resolve.
     cwi.rv() = rv;
@@ -5232,23 +5153,17 @@ ContentParent::RecvCreateWindow(PBrowser
   }
 
   if (sNextTabParents.GetAndRemove(nextTabParentId).valueOr(nullptr)) {
     cwi.windowOpened() = false;
   }
   MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
 
   newTab->SwapFrameScriptsFrom(cwi.frameScripts());
-
-  RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
-  if (!newTab->SetRenderFrame(rfp) ||
-      !newTab->GetRenderFrameInfo(&cwi.textureFactoryIdentifier(), &cwi.layersId())) {
-    rv = NS_ERROR_FAILURE;
-  }
-  cwi.compositorOptions() = rfp->GetCompositorOptions();
+  newTab->MaybeShowFrame();
 
   nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
   if (widget) {
     cwi.maxTouchPoints() = widget->GetMaxTouchPoints();
     cwi.dimensions() = newTab->GetDimensionInfo();
   }
 
   cwi.hasSiblings() = (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -87,20 +87,16 @@ class ProtocolFuzzerHelper;
 namespace jsipc {
 class PJavaScriptParent;
 } // namespace jsipc
 
 namespace layers {
 struct TextureFactoryIdentifier;
 } // namespace layers
 
-namespace layout {
-class PRenderFrameParent;
-} // namespace layout
-
 namespace dom {
 
 class Element;
 class TabParent;
 class ClonedMessageData;
 class MemoryReport;
 class TabContext;
 class ContentBridgeParent;
@@ -538,17 +534,16 @@ public:
 
   virtual bool HandleWindowsMessages(const Message& aMsg) const override;
 
   void ForkNewProcess(bool aBlocking);
 
   virtual mozilla::ipc::IPCResult
   RecvCreateWindow(PBrowserParent* aThisTabParent,
                    PBrowserParent* aNewTab,
-                   layout::PRenderFrameParent* aRenderFrame,
                    const uint32_t& aChromeFlags,
                    const bool& aCalledFromJS,
                    const bool& aPositionSpecified,
                    const bool& aSizeSpecified,
                    const OptionalURIParams& aURIToLoad,
                    const nsCString& aFeatures,
                    const nsCString& aBaseURI,
                    const float& aFullZoom,
@@ -565,18 +560,16 @@ public:
     const OptionalURIParams& aURIToLoad,
     const nsCString& aFeatures,
     const nsCString& aBaseURI,
     const float& aFullZoom,
     const nsString& aName,
     const IPC::Principal& aTriggeringPrincipal,
     const uint32_t& aReferrerPolicy) override;
 
-  static bool AllocateLayerTreeId(TabParent* aTabParent, layers::LayersId* aId);
-
   static void
   BroadcastBlobURLRegistration(const nsACString& aURI,
                                BlobImpl* aBlobImpl,
                                nsIPrincipal* aPrincipal,
                                ContentParent* aIgnoreThisCP = nullptr);
 
   static void
   BroadcastBlobURLUnregistration(const nsACString& aURI,
@@ -865,20 +858,16 @@ private:
   // content process.
   //
   // See nsIPermissionManager::GetPermissionsForKey for more information on
   // these keys.
   void EnsurePermissionsByKey(const nsCString& aKey);
 
   static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
 
-  static bool AllocateLayerTreeId(ContentParent* aContent,
-                                  TabParent* aTopLevel, const TabId& aTabId,
-                                  layers::LayersId* aId);
-
   /**
    * Get or create the corresponding content parent array to |aContentProcessType|.
    */
   static nsTArray<ContentParent*>& GetOrCreatePool(const nsAString& aContentProcessType);
 
   virtual mozilla::ipc::IPCResult RecvInitBackground(Endpoint<mozilla::ipc::PBackgroundParent>&& aEndpoint) override;
 
   mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport) override;
@@ -1135,23 +1124,16 @@ public:
 
   virtual mozilla::ipc::IPCResult RecvCopyFavicon(const URIParams& aOldURI,
                                                   const URIParams& aNewURI,
                                                   const IPC::Principal& aLoadingPrincipal,
                                                   const bool& aInPrivateBrowsing) override;
 
   virtual void ProcessingError(Result aCode, const char* aMsgName) override;
 
-  virtual mozilla::ipc::IPCResult RecvAllocateLayerTreeId(const ContentParentId& aCpId,
-                                                          const TabId& aTabId,
-                                                          layers::LayersId* aId) override;
-
-  virtual mozilla::ipc::IPCResult RecvDeallocateLayerTreeId(const ContentParentId& aCpId,
-                                                            const layers::LayersId& aId) override;
-
   virtual mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override;
 
   virtual mozilla::ipc::IPCResult
   RecvBeginDriverCrashGuard(const uint32_t& aGuardType,
                             bool* aOutCrashed) override;
 
   virtual mozilla::ipc::IPCResult RecvEndDriverCrashGuard(const uint32_t& aGuardType) override;
 
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -20,19 +20,16 @@ using struct mozilla::SerializedStructur
 using LayoutDeviceIntRect from "Units.h";
 using DesktopIntRect from "Units.h";
 using DesktopToLayoutDeviceScale from "Units.h";
 using CSSToLayoutDeviceScale from "Units.h";
 using CSSRect from "Units.h";
 using CSSSize from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using hal::ScreenOrientation from "mozilla/HalScreenConfiguration.h";
-using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
-using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
-using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h";
 using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
 
 
 namespace mozilla {
 namespace dom {
 
 struct MessagePortIdentifier
 {
@@ -115,19 +112,16 @@ struct FrameScriptInfo
  * The information required to complete a window creation request.
  */
 struct CreatedWindowInfo
 {
   nsresult rv;
   bool windowOpened;
   FrameScriptInfo[] frameScripts;
   nsCString urlToLoad;
-  TextureFactoryIdentifier textureFactoryIdentifier;
-  LayersId layersId;
-  CompositorOptions compositorOptions;
   uint32_t maxTouchPoints;
   DimensionInfo dimensions;
   bool hasSiblings;
 };
 
 
 /**
  * PerformanceInfo is used to pass performance info stored
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -6,17 +6,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PColorPicker;
 include protocol PContent;
 include protocol PContentBridge;
 include protocol PDocAccessible;
 include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
-include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include protocol PIPCBlobInputStream;
 include protocol PPaymentRequest;
 
@@ -112,30 +111,23 @@ union OptionalShmem
 nested(upto inside_cpow) sync protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDocAccessible;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
-    manages PRenderFrame;
     manages PPluginWidget;
     manages PPaymentRequest;
 
 both:
     async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                        Principal aPrincipal, ClonedMessageData aData);
 
-    /**
-     * Create a layout frame (encapsulating a remote layer tree) for
-     * the page that is currently loaded in the <browser>.
-     */
-    async PRenderFrame();
-
 parent:
     /**
      * Tell the parent process a new accessible document has been created.
      * aParentDoc is the accessible document it was created in if any, and
      * aParentAcc is the id of the accessible in that document the new document
      * is a child of. aMsaaID is the MSAA id for this content process, and
      * is only valid on Windows. Set to 0 on other platforms. aDocCOMProxy
      * is also Windows-specific and should be set to 0 on other platforms.
@@ -434,17 +426,17 @@ parent:
      * process), then calls BrowserFrameOpenWindow on it.
      *
      * The parent process gets a chance to accept or reject the window.open
      * call, and windowOpened is set to true if we ended up going through with
      * the window.open.
      *
      * @param opener the PBrowser whose content called window.open.
      */
-    async BrowserFrameOpenWindow(PBrowser opener, PRenderFrame renderFrame,
+    async BrowserFrameOpenWindow(PBrowser opener,
                                  nsString aURL, nsString aName, nsString aFeatures)
         returns (CreatedWindowInfo window);
 
     /**
      * Tells the containing widget whether the given input block results in a
      * swipe. Should be called in response to a WidgetWheelEvent that has
      * mFlags.mCanTriggerSwipe set on it.
      */
@@ -530,16 +522,21 @@ parent:
      * compositing.  This is sent when all pending changes have been
      * sent to the compositor and are ready to be shown on the next composite.
      * @see PCompositor
      * @see RequestNotifyAfterRemotePaint
      */
     async RemotePaintIsReady();
 
     /**
+     * Child informs the parent that a compositor transaction has ocurred.
+     */
+    async NotifyCompositorTransaction();
+
+    /**
      * Child informs the parent that the content is ready to handle input
      * events. This is sent when the TabChild is created.
      */
     async RemoteIsReadyToHandleInputEvents();
 
     /**
      * Child informs the parent that the layer tree is already available.
      */
@@ -595,18 +592,17 @@ child:
     async Show(ScreenIntSize size,
                ShowInfo info,
                bool parentIsActive,
                nsSizeMode sizeMode);
 
     async InitRendering(TextureFactoryIdentifier textureFactoryIdentifier,
                         LayersId layersId,
                         CompositorOptions compositorOptions,
-                        bool layersConnected,
-                        nullable PRenderFrame renderFrame);
+                        bool layersConnected);
 
     async LoadURL(nsCString uri, ShowInfo info);
 
     async UpdateDimensions(DimensionInfo dimensions) compressall;
 
     async SizeModeChanged(nsSizeMode sizeMode);
 
     async ParentActivated(bool aActivated);
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -27,17 +27,16 @@ include protocol PStreamFilter;
 include protocol PGMPContent;
 include protocol PGMPService;
 include protocol PPluginModule;
 include protocol PGMP;
 include protocol PPrinting;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol POfflineCacheUpdate;
-include protocol PRenderFrame;
 include protocol PSpeechSynthesis;
 include protocol PTestShell;
 include protocol PJavaScript;
 include protocol PRemoteSpellcheckEngine;
 include protocol PWebBrowserPersistDocument;
 include protocol PWebrtcGlobal;
 include protocol PPresentation;
 include protocol PURLClassifier;
@@ -908,21 +907,16 @@ parent:
 
     sync KeywordToURI(nsCString keyword)
         returns (nsString providerName, nsIInputStream postData, OptionalURIParams uri);
 
     sync NotifyKeywordSearchLoading(nsString providerName, nsString keyword);
 
     async CopyFavicon(URIParams oldURI, URIParams newURI, Principal aLoadingPrincipal, bool isPrivate);
 
-    // Tell the compositor to allocate a layer tree id for nested remote mozbrowsers.
-    sync AllocateLayerTreeId(ContentParentId cpId, TabId tabId)
-        returns (LayersId id);
-    async DeallocateLayerTreeId(ContentParentId cpId, LayersId id);
-
     /**
      * Notifies the parent about a recording device is starting or shutdown.
      * @param recordingStatus starting or shutdown
      * @param pageURL URL that request that changing the recording status
      * @param isAudio recording start with microphone
      * @param isVideo recording start with camera
      */
     async RecordingDeviceEvents(nsString recordingStatus,
@@ -1049,17 +1043,16 @@ parent:
     /**
      * Request graphics initialization information from the parent.
      */
     sync GetGraphicsDeviceInitData()
         returns (ContentDeviceData aData);
 
     async CreateWindow(nullable PBrowser aThisTab,
                        PBrowser aNewTab,
-                       PRenderFrame aRenderFrame,
                        uint32_t aChromeFlags,
                        bool aCalledFromJS,
                        bool aPositionSpecified,
                        bool aSizeSpecified,
                        OptionalURIParams aURIToLoad,
                        nsCString aFeatures,
                        nsCString aBaseURI,
                        float aFullZoom,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -37,18 +37,16 @@
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/DoubleTapToZoom.h"
 #include "mozilla/layers/IAPZCTreeManager.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
-#include "mozilla/layout/RenderFrameChild.h"
-#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/plugins/PPluginWidgetChild.h"
 #include "mozilla/recordreplay/ParentIPC.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Move.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ScopeExit.h"
@@ -392,17 +390,16 @@ TabChild::Create(nsIContentChild* aManag
 
 TabChild::TabChild(nsIContentChild* aManager,
                    const TabId& aTabId,
                    dom::TabGroup* aTabGroup,
                    const TabContext& aContext,
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mTabGroup(aTabGroup)
-  , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mMaxTouchPoints(0)
   , mLayersId{0}
   , mBeforeUnloadListeners(0)
   , mDidFakeShow(false)
   , mNotified(false)
   , mTriedBrowserInit(false)
@@ -803,20 +800,20 @@ TabChild::IsWindowModal(bool* aRetVal)
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::SetStatusWithContext(uint32_t aStatusType,
                                const nsAString& aStatusText,
                                nsISupports* aStatusContext)
 {
-  // We can only send the status after the ipc machinery is set up,
-  // mRemoteFrame is a good indicator.
-  if (mRemoteFrame)
+  // We can only send the status after the ipc machinery is set up
+  if (IPCOpen()) {
     SendSetStatus(aStatusType, nsString(aStatusText));
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
                         int32_t aCx, int32_t aCy)
 {
   // The parent is in charge of the dimension changes. If JS code wants to
@@ -1021,28 +1018,21 @@ TabChild::DestroyWindow()
         static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
       data.reset();
     }
 
     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
     if (baseWindow)
         baseWindow->Destroy();
 
-    // NB: the order of mPuppetWidget->Destroy() and mRemoteFrame->Destroy()
-    // is important: we want to kill off remote layers before their
-    // frames
     if (mPuppetWidget) {
         mPuppetWidget->Destroy();
     }
 
-    if (mRemoteFrame) {
-        mRemoteFrame->Destroy();
-        mRemoteFrame = nullptr;
-    }
-
+    mLayersConnected = Nothing();
 
     if (mLayersId.IsValid()) {
       StaticMutexAutoLock lock(sTabChildrenMutex);
 
       MOZ_ASSERT(sTabChildren);
       sTabChildren->Remove(uint64_t(mLayersId));
       if (!sTabChildren->Count()) {
         delete sTabChildren;
@@ -1124,23 +1114,18 @@ TabChild::RecvLoadURL(const nsCString& a
   }
 
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aURI);
 
   return IPC_OK();
 }
 
 void
-TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
-                     const layers::LayersId& aLayersId,
-                     const CompositorOptions& aCompositorOptions,
-                     PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo)
+TabChild::DoFakeShow(const ShowInfo& aShowInfo)
 {
-  mLayersConnected = aRenderFrame ? Some(true) : Some(false);
-  InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions, aRenderFrame);
   RecvShow(ScreenIntSize(0, 0), aShowInfo, mParentIsActive, nsSizeMode_Normal);
   mDidFakeShow = true;
 }
 
 void
 TabChild::ApplyShowInfo(const ShowInfo& aInfo)
 {
   // Even if we already set real show info, the dpi / rounding & scale may still
@@ -1231,32 +1216,29 @@ TabChild::RecvShow(const ScreenIntSize& 
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                             const layers::LayersId& aLayersId,
                             const CompositorOptions& aCompositorOptions,
-                            const bool& aLayersConnected,
-                            PRenderFrameChild* aRenderFrame)
+                            const bool& aLayersConnected)
 {
-  MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame));
-
   mLayersConnected = Some(aLayersConnected);
-  InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions, aRenderFrame);
+  InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvUpdateDimensions(const DimensionInfo& aDimensionInfo)
 {
     // When recording/replaying we need to make sure the dimensions are up to
     // date on the compositor used in this process.
-    if (!mRemoteFrame && !recordreplay::IsRecordingOrReplaying()) {
+    if (mLayersConnected.isNothing() && !recordreplay::IsRecordingOrReplaying()) {
         return IPC_OK();
     }
 
     mUnscaledOuterRect = aDimensionInfo.rect();
     mClientOffset = aDimensionInfo.clientOffset();
     mChromeOffset = aDimensionInfo.chromeOffset();
 
     mOrientation = aDimensionInfo.orientation();
@@ -2726,29 +2708,16 @@ TabChild::RecvHandledWindowedPluginKeyEv
 {
   if (NS_WARN_IF(!mPuppetWidget)) {
     return IPC_OK();
   }
   mPuppetWidget->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
   return IPC_OK();
 }
 
-PRenderFrameChild*
-TabChild::AllocPRenderFrameChild()
-{
-    return new RenderFrameChild();
-}
-
-bool
-TabChild::DeallocPRenderFrameChild(PRenderFrameChild* aFrame)
-{
-    delete aFrame;
-    return true;
-}
-
 bool
 TabChild::InitTabChildMessageManager()
 {
   if (!mTabChildMessageManager) {
     nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
     NS_ENSURE_TRUE(window, false);
     nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
     NS_ENSURE_TRUE(chromeHandler, false);
@@ -2775,42 +2744,34 @@ TabChild::InitTabChildMessageManager()
   }
 
   return true;
 }
 
 void
 TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                              const layers::LayersId& aLayersId,
-                             const CompositorOptions& aCompositorOptions,
-                             PRenderFrameChild* aRenderFrame)
+                             const CompositorOptions& aCompositorOptions)
 {
     mPuppetWidget->InitIMEState();
 
-    if (!aRenderFrame) {
-      mLayersConnected = Some(false);
-      NS_WARNING("failed to construct RenderFrame");
-      return;
-    }
-
     MOZ_ASSERT(aLayersId.IsValid());
     mTextureFactoryIdentifier = aTextureFactoryIdentifier;
 
     // Pushing layers transactions directly to a separate
     // compositor context.
     PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
     if (!compositorChild) {
       mLayersConnected = Some(false);
       NS_WARNING("failed to get CompositorBridgeChild instance");
       return;
     }
 
     mCompositorOptions = Some(aCompositorOptions);
 
-    mRemoteFrame = static_cast<RenderFrameChild*>(aRenderFrame);
     if (aLayersId.IsValid()) {
       StaticMutexAutoLock lock(sTabChildrenMutex);
 
       if (!sTabChildren) {
         sTabChildren = new TabChildMap;
       }
       MOZ_ASSERT(!sTabChildren->Get(uint64_t(aLayersId)));
       sTabChildren->Put(uint64_t(aLayersId), this);
@@ -2918,17 +2879,17 @@ TabChild::InitAPZState()
 }
 
 void
 TabChild::NotifyPainted()
 {
     if (!mNotified) {
         // Recording/replaying processes have a compositor but not a remote frame.
         if (!recordreplay::IsRecordingOrReplaying()) {
-            mRemoteFrame->SendNotifyCompositorTransaction();
+            SendNotifyCompositorTransaction();
         }
         mNotified = true;
     }
 }
 
 void
 TabChild::MakeVisible()
 {
@@ -3297,17 +3258,17 @@ TabChild::OnHideTooltip()
 mozilla::ipc::IPCResult
 TabChild::RecvRequestNotifyAfterRemotePaint()
 {
   // Get the CompositorBridgeChild instance for this content thread.
   CompositorBridgeChild* compositor = CompositorBridgeChild::Get();
 
   // Tell the CompositorBridgeChild that, when it gets a RemotePaintIsReady
   // message that it should forward it us so that we can bounce it to our
-  // RenderFrameParent.
+  // TabParent.
   compositor->RequestNotifyAfterRemotePaint(this);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvUIResolutionChanged(const float& aDpi,
                                   const int32_t& aRounding,
                                   const double& aScale)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -49,19 +49,16 @@ class nsIHttpChannel;
 class nsISerialEventTarget;
 class nsWebBrowser;
 
 template<typename T> class nsTHashtable;
 template<typename T> class nsPtrHashKey;
 
 namespace mozilla {
 class AbstractThread;
-namespace layout {
-class RenderFrameChild;
-} // namespace layout
 
 namespace layers {
 class APZChild;
 class APZEventState;
 class AsyncDragMetrics;
 class IAPZCTreeManager;
 class ImageCompositeNotification;
 class PCompositorBridgeChild;
@@ -206,17 +203,16 @@ class TabChild final : public TabChildBa
                        public nsIObserver,
                        public TabContext,
                        public nsITooltipListener,
                        public mozilla::ipc::IShmemAllocator
 {
   typedef mozilla::dom::ClonedMessageData ClonedMessageData;
   typedef mozilla::dom::CoalescedMouseData CoalescedMouseData;
   typedef mozilla::dom::CoalescedWheelData CoalescedWheelData;
-  typedef mozilla::layout::RenderFrameChild RenderFrameChild;
   typedef mozilla::layers::APZEventState APZEventState;
   typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback;
   typedef mozilla::layers::TouchBehaviorFlags TouchBehaviorFlags;
 
 public:
   /**
    * Find TabChild of aTabId in the same content process of the
    * caller.
@@ -302,18 +298,17 @@ public:
            const ShowInfo& aInfo,
            const bool& aParentIsActive,
            const nsSizeMode& aSizeMode) override;
 
   virtual mozilla::ipc::IPCResult
   RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                     const layers::LayersId& aLayersId,
                     const mozilla::layers::CompositorOptions& aCompositorOptions,
-                    const bool& aLayersConnected,
-                    PRenderFrameChild* aRenderFrame) override;
+                    const bool& aLayersConnected) override;
 
   virtual mozilla::ipc::IPCResult
   RecvUpdateDimensions(const mozilla::dom::DimensionInfo& aDimensionInfo) override;
   virtual mozilla::ipc::IPCResult
   RecvSizeModeChanged(const nsSizeMode& aSizeMode) override;
 
   mozilla::ipc::IPCResult RecvActivate();
 
@@ -601,21 +596,17 @@ public:
   }
 
   const mozilla::layers::CompositorOptions& GetCompositorOptions() const;
   bool AsyncPanZoomEnabled() const;
 
   virtual ScreenIntSize GetInnerSize() override;
 
   // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
-  void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
-                  const layers::LayersId& aLayersId,
-                  const mozilla::layers::CompositorOptions& aCompositorOptions,
-                  PRenderFrameChild* aRenderFrame,
-                  const ShowInfo& aShowInfo);
+  void DoFakeShow(const ShowInfo& aShowInfo);
 
   void ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
                                  uint64_t aInputBlockId,
                                  bool aPreventDefault) const;
   void SetTargetAPZC(uint64_t aInputBlockId,
                     const nsTArray<ScrollableLayerGuid>& aTargets) const;
   MOZ_CAN_RUN_SCRIPT
   mozilla::ipc::IPCResult RecvHandleTap(const layers::GeckoContentController::TapType& aType,
@@ -709,20 +700,16 @@ public:
   {
     MOZ_ASSERT(HasVisibleTabs());
     return *sVisibleTabs;
   }
 
 protected:
   virtual ~TabChild();
 
-  virtual PRenderFrameChild* AllocPRenderFrameChild() override;
-
-  virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
-
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
 
   virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(const bool& aIsActive) override;
 
   virtual mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled, const bool& aForce, const layers::LayersObserverEpoch& aEpoch) override;
 
   virtual mozilla::ipc::IPCResult RecvRequestRootPaint(const IntRect& aRect, const float& aScale, const nscolor& aBackgroundColor, RequestRootPaintResolver&& aResolve) override;
 
@@ -770,18 +757,17 @@ private:
   void UpdateFrameType();
 
   void ActorDestroy(ActorDestroyReason why) override;
 
   bool InitTabChildMessageManager();
 
   void InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                           const layers::LayersId& aLayersId,
-                          const mozilla::layers::CompositorOptions& aCompositorOptions,
-                          PRenderFrameChild* aRenderFrame);
+                          const mozilla::layers::CompositorOptions& aCompositorOptions);
   void InitAPZState();
 
   void DestroyWindow();
 
   void ApplyShowInfo(const ShowInfo& aInfo);
 
   bool HasValidInnerSize();
 
@@ -821,17 +807,16 @@ private:
   class DelayedDeleteRunnable;
 
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   RefPtr<nsWebBrowser> mWebBrowser;
   nsCOMPtr<nsIWebNavigation> mWebNav;
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
   RefPtr<PuppetWidget> mPuppetWidget;
   nsCOMPtr<nsIURI> mLastURI;
-  RenderFrameChild* mRemoteFrame;
   RefPtr<nsIContentChild> mManager;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
   layers::LayersId mLayersId;
   int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
   Maybe<bool> mLayersConnected;
   bool mDidFakeShow;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -26,17 +26,17 @@
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Hal.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/AsyncDragMetrics.h"
 #include "mozilla/layers/InputAPZContext.h"
-#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/layout/RenderFrame.h"
 #include "mozilla/plugins/PPluginWidgetParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -151,17 +151,16 @@ TabParent::TabParent(nsIContentParent* a
   , mUpdatedDimensions(false)
   , mSizeMode(nsSizeMode_Normal)
   , mManager(aManager)
   , mDocShellIsActive(false)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mChromeFlags(aChromeFlags)
   , mDragValid(false)
-  , mInitedByParent(false)
   , mTabId(aTabId)
   , mCreatingWindow(false)
   , mCursor(eCursorInvalid)
   , mCustomCursorHotspotX(0)
   , mCustomCursorHotspotY(0)
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
@@ -354,21 +353,16 @@ TabParent::DestroyInternal()
   }
 #endif
 
   // If this fails, it's most likely due to a content-process crash,
   // and auto-cleanup will kick in.  Otherwise, the child side will
   // destroy itself and send back __delete__().
   Unused << SendDestroy();
 
-  if (RenderFrameParent* frame = GetRenderFrame()) {
-    RemoveTabParentFromTable(frame->GetLayersId());
-    frame->Destroy();
-  }
-
 #ifdef XP_WIN
   // Let all PluginWidgets know we are tearing down. Prevents
   // these objects from sending async events after the child side
   // is shut down.
   const ManagedContainer<PPluginWidgetParent>& kids =
     ManagedPPluginWidgetParent();
   for (auto iter = kids.ConstIter(); !iter.Done(); iter.Next()) {
     static_cast<mozilla::plugins::PluginWidgetParent*>(
@@ -401,18 +395,18 @@ TabParent::Destroy()
   }
 
   mMarkedDestroying = true;
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvEnsureLayersConnected(CompositorOptions* aCompositorOptions)
 {
-  if (RenderFrameParent* frame = GetRenderFrame()) {
-    frame->EnsureLayersConnected(aCompositorOptions);
+  if (mRenderFrame.IsInitialized()) {
+    mRenderFrame.EnsureLayersConnected(aCompositorOptions);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::Recv__delete__()
 {
   if (XRE_IsParentProcess()) {
@@ -428,16 +422,24 @@ TabParent::Recv__delete__()
   }
 
   return IPC_OK();
 }
 
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
+  if (mRenderFrame.IsInitialized()) {
+    // It's important to unmap layers after the remote browser has been destroyed,
+    // otherwise it may still send messages to the compositor which will reject them,
+    // causing assertions.
+    RemoveTabParentFromTable(mRenderFrame.GetLayersId());
+    mRenderFrame.Destroy();
+  }
+
   // Even though TabParent::Destroy calls this, we need to do it here too in
   // case of a crash.
   IMEStateManager::OnTabParentDestroying(this);
 
   // Prevent executing ContentParent::NotifyTabDestroying in
   // TabParent::Destroy() called by frameLoader->DestroyComplete() below
   // when tab crashes in contentprocess because ContentParent::ActorDestroy()
   // in main process will be triggered before this function
@@ -625,56 +627,59 @@ TabParent::LoadURL(nsIURI* aURI)
         mDelayedURL = spec;
         return;
     }
 
     Unused << SendLoadURL(spec, GetShowInfo());
 }
 
 void
-TabParent::InitRenderFrame()
+TabParent::InitRendering()
 {
-  if (IsInitedByParent()) {
-    // If TabParent is initialized by parent side then the RenderFrame must also
-    // be created here. If TabParent is initialized by child side,
-    // child side will create RenderFrame.
-    MOZ_ASSERT(!GetRenderFrame());
-    RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
-    MOZ_ASSERT(frameLoader);
-    if (frameLoader) {
-      RenderFrameParent* renderFrame = new RenderFrameParent(frameLoader);
-      MOZ_ASSERT(renderFrame->IsInitted());
-      layers::LayersId layersId = renderFrame->GetLayersId();
-      AddTabParentToTable(layersId, this);
-      if (!SendPRenderFrameConstructor(renderFrame)) {
-        return;
-      }
-
-      TextureFactoryIdentifier textureFactoryIdentifier;
-      renderFrame->GetTextureFactoryIdentifier(&textureFactoryIdentifier);
-      Unused << SendInitRendering(textureFactoryIdentifier, layersId,
-        renderFrame->GetCompositorOptions(),
-        renderFrame->IsLayersConnected(), renderFrame);
-    }
-  } else {
-    // Otherwise, the child should have constructed the RenderFrame,
-    // and we should already know about it.
-    MOZ_ASSERT(GetRenderFrame());
+  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+
+  MOZ_ASSERT(!mRenderFrame.IsInitialized());
+  MOZ_ASSERT(frameLoader);
+
+  if (!frameLoader) {
+    return;
   }
+
+  mRenderFrame.Initialize(frameLoader);
+  MOZ_ASSERT(mRenderFrame.IsInitialized());
+
+  layers::LayersId layersId = mRenderFrame.GetLayersId();
+  AddTabParentToTable(layersId, this);
+
+  TextureFactoryIdentifier textureFactoryIdentifier;
+  mRenderFrame.GetTextureFactoryIdentifier(&textureFactoryIdentifier);
+  Unused << SendInitRendering(textureFactoryIdentifier, layersId,
+    mRenderFrame.GetCompositorOptions(),
+    mRenderFrame.IsLayersConnected());
+}
+
+void
+TabParent::MaybeShowFrame()
+{
+  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+  if (!frameLoader) {
+    return;
+  }
+  frameLoader->MaybeShowFrame();
 }
 
 void
 TabParent::Show(const ScreenIntSize& size, bool aParentIsActive)
 {
     mDimensions = size;
     if (mIsDestroyed) {
         return;
     }
 
-    MOZ_ASSERT(GetRenderFrame());
+    MOZ_ASSERT(mRenderFrame.IsInitialized());
 
     nsCOMPtr<nsISupports> container = mFrameElement->OwnerDoc()->GetContainer();
     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
     nsCOMPtr<nsIWidget> mainWidget;
     baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
     mSizeMode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
 
     Unused << SendShow(size, GetShowInfo(), aParentIsActive, mSizeMode);
@@ -1649,19 +1654,29 @@ TabParent::SendHandleTap(TapType aType,
                          const LayoutDevicePoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId)
 {
   if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
     return false;
   }
-  if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap) &&
-      GetRenderFrame()) {
-    GetRenderFrame()->TakeFocusForClickFromTap();
+  if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap)) {
+    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+    if (fm) {
+      RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+      if (frameLoader) {
+        RefPtr<Element> element = frameLoader->GetOwnerContent();
+        if (element) {
+          fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
+                                nsIFocusManager::FLAG_BYTOUCH |
+                                nsIFocusManager::FLAG_NOSCROLL);
+        }
+      }
+    }
   }
   LayoutDeviceIntPoint offset = GetChildProcessOffset();
   return Manager()->AsContentParent()->IsInputPriorityEventEnabled()
     ? PBrowserParent::SendHandleTap(aType, aPoint + offset, aModifiers, aGuid,
                                     aInputBlockId)
     : PBrowserParent::SendNormalPriorityHandleTap(aType, aPoint + offset,
                                                   aModifiers, aGuid,
                                                   aInputBlockId);
@@ -2363,23 +2378,23 @@ TabParent::GetTabIdFrom(nsIDocShell *doc
 {
   nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
   if (tabChild) {
     return static_cast<TabChild*>(tabChild.get())->GetTabId();
   }
   return TabId(0);
 }
 
-RenderFrameParent*
+RenderFrame*
 TabParent::GetRenderFrame()
 {
-  PRenderFrameParent* p = LoneManagedOrNullAsserts(ManagedPRenderFrameParent());
-  RenderFrameParent* frame = static_cast<RenderFrameParent*>(p);
-
-  return frame;
+  if (!mRenderFrame.IsInitialized()) {
+    return nullptr;
+  }
+  return &mRenderFrame;
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvRequestIMEToCommitComposition(const bool& aCancel,
                                              bool* aIsCommitted,
                                              nsString* aCommittedString)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
@@ -2592,78 +2607,16 @@ TabParent::AllocPColorPickerParent(const
 
 bool
 TabParent::DeallocPColorPickerParent(PColorPickerParent* actor)
 {
   delete actor;
   return true;
 }
 
-PRenderFrameParent*
-TabParent::AllocPRenderFrameParent()
-{
-  MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty());
-  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
-
-  RenderFrameParent* rfp = new RenderFrameParent(frameLoader);
-  if (rfp->IsInitted()) {
-    layers::LayersId layersId = rfp->GetLayersId();
-    AddTabParentToTable(layersId, this);
-  }
-  return rfp;
-}
-
-bool
-TabParent::DeallocPRenderFrameParent(PRenderFrameParent* aFrame)
-{
-  delete aFrame;
-  return true;
-}
-
-bool
-TabParent::SetRenderFrame(PRenderFrameParent* aRFParent)
-{
-  if (IsInitedByParent()) {
-    return false;
-  }
-
-  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
-
-  if (!frameLoader) {
-    return false;
-  }
-
-  RenderFrameParent* renderFrame = static_cast<RenderFrameParent*>(aRFParent);
-  bool success = renderFrame->Init(frameLoader);
-  if (!success) {
-    return false;
-  }
-
-  frameLoader->MaybeShowFrame();
-
-  layers::LayersId layersId = renderFrame->GetLayersId();
-  AddTabParentToTable(layersId, this);
-
-  return true;
-}
-
-bool
-TabParent::GetRenderFrameInfo(TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                              layers::LayersId* aLayersId)
-{
-  RenderFrameParent* rfp = GetRenderFrame();
-  if (!rfp) {
-    return false;
-  }
-
-  *aLayersId = rfp->GetLayersId();
-  rfp->GetTextureFactoryIdentifier(aTextureFactoryIdentifier);
-  return true;
-}
-
 already_AddRefed<nsFrameLoader>
 TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const
 {
   if (mIsDestroyed && !aUseCachedFrameLoaderAfterDestroy) {
     return nullptr;
   }
 
   if (mFrameLoader) {
@@ -2727,19 +2680,19 @@ TabParent::ApzAwareEventRoutingToChild(S
     if (aOutTargetGuid) {
       *aOutTargetGuid = InputAPZContext::GetTargetLayerGuid();
 
       // There may be cases where the APZ hit-testing code came to a different
       // conclusion than the main-thread hit-testing code as to where the event
       // is destined. In such cases the layersId of the APZ result may not match
       // the layersId of this renderframe. In such cases the main-thread hit-
       // testing code "wins" so we need to update the guid to reflect this.
-      if (RenderFrameParent* rfp = GetRenderFrame()) {
-        if (aOutTargetGuid->mLayersId != rfp->GetLayersId()) {
-          *aOutTargetGuid = ScrollableLayerGuid(rfp->GetLayersId(), 0, ScrollableLayerGuid::NULL_SCROLL_ID);
+      if (mRenderFrame.IsInitialized()) {
+        if (aOutTargetGuid->mLayersId != mRenderFrame.GetLayersId()) {
+          *aOutTargetGuid = ScrollableLayerGuid(mRenderFrame.GetLayersId(), 0, ScrollableLayerGuid::NULL_SCROLL_ID);
         }
       }
     }
     if (aOutInputBlockId) {
       *aOutInputBlockId = InputAPZContext::GetInputBlockId();
     }
     if (aOutApzResponse) {
       *aOutApzResponse = InputAPZContext::GetApzResponse();
@@ -2751,34 +2704,28 @@ TabParent::ApzAwareEventRoutingToChild(S
     if (aOutApzResponse) {
       *aOutApzResponse = nsEventStatus_eIgnore;
     }
   }
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
-                                      PRenderFrameParent* aRenderFrame,
                                       const nsString& aURL,
                                       const nsString& aName,
                                       const nsString& aFeatures,
                                       BrowserFrameOpenWindowResolver&& aResolve)
 {
   CreatedWindowInfo cwi;
   cwi.rv() = NS_OK;
-  cwi.layersId() = LayersId{0};
   cwi.maxTouchPoints() = 0;
 
   BrowserElementParent::OpenWindowResult opened =
     BrowserElementParent::OpenWindowOOP(TabParent::GetFrom(aOpener),
-                                        this, aRenderFrame, aURL, aName, aFeatures,
-                                        &cwi.textureFactoryIdentifier(),
-                                        &cwi.layersId());
-  cwi.compositorOptions() =
-    static_cast<RenderFrameParent*>(aRenderFrame)->GetCompositorOptions();
+                                        this, aURL, aName, aFeatures);
   cwi.windowOpened() = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     cwi.maxTouchPoints() = widget->GetMaxTouchPoints();
     cwi.dimensions() = GetDimensionInfo();
   }
 
   // Resolve the request with the information we collected.
@@ -3180,16 +3127,40 @@ TabParent::RecvRemotePaintIsReady()
   event->InitEvent(NS_LITERAL_STRING("MozAfterRemotePaint"), false, false);
   event->SetTrusted(true);
   event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   mFrameElement->DispatchEvent(*event);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+TabParent::RecvNotifyCompositorTransaction()
+{
+  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+
+  if (!frameLoader) {
+    return IPC_OK();
+  }
+
+  nsIFrame* docFrame = frameLoader->GetPrimaryFrameOfOwningContent();
+
+  if (!docFrame) {
+    // Bad, but nothing we can do about it (XXX/cjones: or is there?
+    // maybe bug 589337?).  When the new frame is created, we'll
+    // probably still be the current render frame and will get to draw
+    // our content then.  Or, we're shutting down and this update goes
+    // to /dev/null.
+    return IPC_OK();
+  }
+
+  docFrame->InvalidateLayer(DisplayItemType::TYPE_REMOTE);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 TabParent::RecvRemoteIsReadyToHandleInputEvents()
 {
   // When enabling input event prioritization, input events may preempt other
   // normal priority IPC messages. To prevent the input events preempt
   // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
   // notify the parent that TabChild is created and ready to handle input
   // events.
   SetReadyToHandleInputEvents();
@@ -3550,18 +3521,18 @@ TabParent::StartApzAutoscroll(float aAnc
                               bool* aOutRetval)
 {
   if (!AsyncPanZoomEnabled()) {
     *aOutRetval = false;
     return NS_OK;
   }
 
   bool success = false;
-  if (RenderFrameParent* renderFrame = GetRenderFrame()) {
-    layers::LayersId layersId = renderFrame->GetLayersId();
+  if (mRenderFrame.IsInitialized()) {
+    layers::LayersId layersId = mRenderFrame.GetLayersId();
     if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
       ScrollableLayerGuid guid{layersId, aPresShellId, aScrollId};
 
       // The anchor coordinates that are passed in are relative to the origin
       // of the screen, but we are sending them to APZ which only knows about
       // coordinates relative to the widget, so convert them accordingly.
       CSSPoint anchorCss{aAnchorX, aAnchorY};
       LayoutDeviceIntPoint anchor = RoundedToInt(anchorCss * widget->GetDefaultScale());
@@ -3578,18 +3549,18 @@ TabParent::StartApzAutoscroll(float aAnc
 
 NS_IMETHODIMP
 TabParent::StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId)
 {
   if (!AsyncPanZoomEnabled()) {
     return NS_OK;
   }
 
-  if (RenderFrameParent* renderFrame = GetRenderFrame()) {
-    layers::LayersId layersId = renderFrame->GetLayersId();
+  if (mRenderFrame.IsInitialized()) {
+    layers::LayersId layersId = mRenderFrame.GetLayersId();
     if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
       ScrollableLayerGuid guid{layersId, aPresShellId, aScrollId};
       widget->StopAsyncAutoscroll(guid);
     }
   }
   return NS_OK;
 }
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -14,16 +14,17 @@
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/gfx/CrossProcessPaint.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layout/RenderFrame.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Move.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDOMEventListener.h"
 #include "nsIKeyEventInPluginCallback.h"
 #include "nsITabParent.h"
@@ -50,20 +51,16 @@ class DocAccessibleParent;
 namespace jsipc {
 class CpowHolder;
 } // namespace jsipc
 
 namespace layers {
 struct TextureFactoryIdentifier;
 } // namespace layers
 
-namespace layout {
-class RenderFrameParent;
-} // namespace layout
-
 namespace widget {
 struct IMENotification;
 } // namespace widget
 
 namespace gfx {
 class SourceSurface;
 class DataSourceSurface;
 } // namespace gfx
@@ -157,17 +154,16 @@ public:
   virtual mozilla::ipc::IPCResult
   RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult
   RecvSetHasBeforeUnload(const bool& aHasBeforeUnload) override;
 
   virtual mozilla::ipc::IPCResult
   RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
-                             PRenderFrameParent* aRenderFrame,
                              const nsString& aURL,
                              const nsString& aName,
                              const nsString& aFeatures,
                              BrowserFrameOpenWindowResolver&& aResolve) override;
 
   virtual mozilla::ipc::IPCResult
   RecvSyncMessage(const nsString& aMessage,
                   const ClonedMessageData& aData,
@@ -328,17 +324,18 @@ public:
 
   /**
    * Return the top level doc accessible parent for this tab.
    */
   a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
 
   void LoadURL(nsIURI* aURI);
 
-  void InitRenderFrame();
+  void InitRendering();
+  void MaybeShowFrame();
 
   // XXX/cjones: it's not clear what we gain by hiding these
   // message-sending functions under a layer of indirection and
   // eating the return values
   void Show(const ScreenIntSize& aSize, bool aParentIsActive);
 
   void UpdateDimensions(const nsIntRect& aRect, const ScreenIntSize& aSize);
 
@@ -549,20 +546,16 @@ public:
   DeallocPPluginWidgetParent(PPluginWidgetParent* aActor) override;
 
   virtual PPaymentRequestParent*
   AllocPPaymentRequestParent() override;
 
   virtual bool
   DeallocPPaymentRequestParent(PPaymentRequestParent* aActor) override;
 
-  void SetInitedByParent() { mInitedByParent = true; }
-
-  bool IsInitedByParent() const { return mInitedByParent; }
-
   bool SendLoadRemoteScript(const nsString& aURL,
                             const bool& aRunInGlobalScope);
 
   void LayerTreeUpdate(const LayersObserverEpoch& aEpoch, bool aActive);
 
   void RequestRootPaint(gfx::CrossProcessPaint* aPaint, IntRect aRect, float aScale, nscolor aBackgroundColor);
   void RequestSubPaint(gfx::CrossProcessPaint* aPaint, float aScale, nscolor aBackgroundColor);
 
@@ -575,21 +568,17 @@ public:
                         const nsCString& aPrincipalURISpec) override;
 
   void AddInitialDnDDataTo(DataTransfer* aDataTransfer,
                            nsACString& aPrincipalURISpec);
 
   bool TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
                              LayoutDeviceIntRect* aDragRect);
 
-  layout::RenderFrameParent* GetRenderFrame();
-
-  bool SetRenderFrame(PRenderFrameParent* aRFParent);
-  bool GetRenderFrameInfo(TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                          layers::LayersId* aLayersId);
+  layout::RenderFrame* GetRenderFrame();
 
   mozilla::ipc::IPCResult RecvEnsureLayersConnected(CompositorOptions* aCompositorOptions) override;
 
   // LiveResizeListener implementation
   void LiveResizeStarted() override;
   void LiveResizeStopped() override;
 
   void SetReadyToHandleInputEvents() { mIsReadyToHandleInputEvents = true; }
@@ -615,21 +604,19 @@ protected:
 
   virtual mozilla::ipc::IPCResult Recv__delete__() override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   Element* mFrameElement;
   nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
 
-  virtual PRenderFrameParent* AllocPRenderFrameParent() override;
+  virtual mozilla::ipc::IPCResult RecvRemotePaintIsReady() override;
 
-  virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
-
-  virtual mozilla::ipc::IPCResult RecvRemotePaintIsReady() override;
+  virtual mozilla::ipc::IPCResult RecvNotifyCompositorTransaction() override;
 
   virtual mozilla::ipc::IPCResult RecvRemoteIsReadyToHandleInputEvents() override;
 
   virtual mozilla::ipc::IPCResult RecvPaintWhileInterruptingJSNoOp(const LayersObserverEpoch& aEpoch) override;
 
   virtual mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
                                                     const int32_t& aX, const int32_t& aY,
                                                     const int32_t& aCx, const int32_t& aCy) override;
@@ -692,20 +679,16 @@ private:
 
   nsTArray<nsTArray<IPCDataTransferItem>> mInitialDataTransferItems;
 
   RefPtr<gfx::DataSourceSurface> mDnDVisualization;
   bool mDragValid;
   LayoutDeviceIntRect mDragRect;
   nsCString mDragPrincipalURISpec;
 
-  // When true, the TabParent is initialized without child side's request.
-  // When false, the TabParent is initialized by window.open() from child side.
-  bool mInitedByParent;
-
   nsCOMPtr<nsILoadContext> mLoadContext;
 
   // We keep a strong reference to the frameloader after we've sent the
   // Destroy message and before we've received __delete__. This allows us to
   // dispatch message manager messages during this time.
   RefPtr<nsFrameLoader> mFrameLoader;
 
   TabId mTabId;
@@ -767,16 +750,17 @@ private:
   // to dispatch events.
   typedef nsDataHashtable<nsUint64HashKey, TabParent*> LayerToTabParentTable;
   static LayerToTabParentTable* sLayerToTabParentTable;
 
   static void AddTabParentToTable(layers::LayersId aLayersId, TabParent* aTabParent);
 
   static void RemoveTabParentFromTable(layers::LayersId aLayersId);
 
+  layout::RenderFrame mRenderFrame;
   LayersObserverEpoch mLayerTreeEpoch;
 
   // If this flag is set, then the tab's layers will be preserved even when
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
   // Holds the most recent value passed to the RenderLayers function. This
   // does not necessarily mean that the layers have finished rendering
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -58,16 +58,17 @@ typedef FT_FaceRec_* FT_Face;
 typedef int FT_Error;
 
 struct ID3D11Texture2D;
 struct ID3D11Device;
 struct ID2D1Device;
 struct IDWriteFactory;
 struct IDWriteRenderingParams;
 struct IDWriteFontFace;
+struct IDWriteFontCollection;
 
 class GrContext;
 class SkCanvas;
 struct gfxFontStyle;
 
 struct CGContext;
 typedef struct CGContext *CGContextRef;
 
@@ -1855,19 +1856,19 @@ public:
    * Attempts to create and install a D2D1 device from the supplied Direct3D11 device.
    * Returns true on success, or false on failure and leaves the D2D1/Direct3D11 devices unset.
    */
   static bool SetDirect3D11Device(ID3D11Device *aDevice);
   static RefPtr<ID3D11Device> GetDirect3D11Device();
   static RefPtr<ID2D1Device> GetD2D1Device(uint32_t* aOutSeqNo = nullptr);
   static bool HasD2D1Device();
   static RefPtr<IDWriteFactory> GetDWriteFactory();
-  static bool SetDWriteFactory(IDWriteFactory *aFactory);
   static RefPtr<IDWriteFactory> EnsureDWriteFactory();
   static bool SupportsD2D1();
+  static RefPtr<IDWriteFontCollection> GetDWriteSystemFonts(bool aUpdate = false);
 
   static uint64_t GetD2DVRAMUsageDrawTarget();
   static uint64_t GetD2DVRAMUsageSourceSurface();
   static void D2DCleanup();
 
   static already_AddRefed<ScaledFont>
     CreateScaledFontForDWriteFont(IDWriteFontFace* aFontFace,
                                   const gfxFontStyle* aStyle,
@@ -1881,16 +1882,17 @@ public:
 
   static void SetSystemTextQuality(uint8_t aQuality);
 
 private:
   static StaticRefPtr<ID2D1Device> mD2D1Device;
   static StaticRefPtr<ID3D11Device> mD3D11Device;
   static StaticRefPtr<IDWriteFactory> mDWriteFactory;
   static bool mDWriteFactoryInitialized;
+  static StaticRefPtr<IDWriteFontCollection> mDWriteSystemFonts;
 
 protected:
   // This guards access to the singleton devices above, as well as the
   // singleton devices in DrawTargetD2D1.
   static StaticMutex mDeviceLock;
   // This synchronizes access between different D2D drawtargets and their
   // implied dependency graph.
   static StaticMutex mDTDependencyLock;
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -224,16 +224,17 @@ Mutex* Factory::mFTLock = nullptr;
 
 #ifdef WIN32
 // Note: mDeviceLock must be held when mutating these values.
 static uint32_t mDeviceSeq = 0;
 StaticRefPtr<ID3D11Device> Factory::mD3D11Device;
 StaticRefPtr<ID2D1Device> Factory::mD2D1Device;
 StaticRefPtr<IDWriteFactory> Factory::mDWriteFactory;
 bool Factory::mDWriteFactoryInitialized = false;
+StaticRefPtr<IDWriteFontCollection> Factory::mDWriteSystemFonts;
 StaticMutex Factory::mDeviceLock;
 StaticMutex Factory::mDTDependencyLock;
 #endif
 
 DrawEventRecorder *Factory::mRecorder;
 
 mozilla::gfx::Config* Factory::sConfig = nullptr;
 
@@ -946,16 +947,40 @@ Factory::EnsureDWriteFactory()
 
   if (FAILED(hr)) {
     gfxWarning() << "Failed to create DWrite Factory.";
   }
 
   return mDWriteFactory;
 }
 
+RefPtr<IDWriteFontCollection>
+Factory::GetDWriteSystemFonts(bool aUpdate)
+{
+  StaticMutexAutoLock lock(mDeviceLock);
+
+  if (mDWriteSystemFonts && !aUpdate) {
+    return mDWriteSystemFonts;
+  }
+
+  if (!mDWriteFactory) {
+    return nullptr;
+  }
+
+  RefPtr<IDWriteFontCollection> systemFonts;
+  HRESULT hr = mDWriteFactory->GetSystemFontCollection(getter_AddRefs(systemFonts));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create DWrite system font collection";
+    return nullptr;
+  }
+  mDWriteSystemFonts = systemFonts;
+
+  return mDWriteSystemFonts;
+}
+
 bool
 Factory::SupportsD2D1()
 {
   return !!D2DFactory();
 }
 
 BYTE sSystemTextQuality = CLEARTYPE_QUALITY;
 void
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -380,16 +380,28 @@ UnscaledFontDWrite::GetWRFontDescriptor(
     return false;
   }
 
   std::vector<WCHAR> familyName;
   if (!GetDWriteFamilyName(family, familyName)) {
     return false;
   }
 
+  RefPtr<IDWriteFontCollection> systemFonts = Factory::GetDWriteSystemFonts();
+  if (!systemFonts) {
+    return false;
+  }
+
+  UINT32 idx;
+  BOOL exists;
+  hr = systemFonts->FindFamilyName(familyName.data(), &idx, &exists);
+  if (FAILED(hr) || !exists) {
+    return false;
+  }
+
   // The style information that identifies the font can be encoded easily in
   // less than 32 bits. Since the index is needed for font descriptors, only
   // the family name and style information, pass along the style in the index
   // data to avoid requiring a more complicated structure packing for it in
   // the data payload.
   uint32_t index = weight | (stretch << 16) | (style << 24);
   aCb(reinterpret_cast<const uint8_t*>(familyName.data()),
       (familyName.size() - 1) * sizeof(WCHAR),
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -607,20 +607,20 @@ GPUProcessManager::HandleProcessLost()
   //
   //  (7) In addition, each ContentChild will ask each of its TabChildren
   //      to re-request association with the compositor for the window
   //      owning the tab. The sequence of calls looks like:
   //        (a) [CONTENT] ContentChild::RecvReinitRendering
   //        (b) [CONTENT] TabChild::ReinitRendering
   //        (c) [CONTENT] TabChild::SendEnsureLayersConnected
   //        (d)      [UI] TabParent::RecvEnsureLayersConnected
-  //        (e)      [UI] RenderFrameParent::EnsureLayersConnected
+  //        (e)      [UI] RenderFrame::EnsureLayersConnected
   //        (f)      [UI] CompositorBridgeChild::SendNotifyChildRecreated
   //
-  //      Note that at step (e), RenderFrameParent will call GetLayerManager
+  //      Note that at step (e), RenderFrame will call GetLayerManager
   //      on the nsIWidget owning the tab. This step ensures that a compositor
   //      exists for the window. If we decided to launch a new GPU Process,
   //      at this point we block until the process has launched and we're
   //      able to create a new window compositor. Otherwise, if compositing
   //      is now in-process, this will simply create a new
   //      CompositorBridgeParent in the UI process. If there are multiple tabs
   //      in the same window, additional tabs will simply return the already-
   //      established compositor.
--- a/gfx/layers/apz/src/FocusTarget.cpp
+++ b/gfx/layers/apz/src/FocusTarget.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/FocusTarget.h"
 
 #include "mozilla/dom/EventTarget.h" // for EventTarget
 #include "mozilla/dom/TabParent.h"   // for TabParent
 #include "mozilla/EventDispatcher.h" // for EventDispatcher
-#include "mozilla/layout/RenderFrameParent.h" // For RenderFrameParent
+#include "mozilla/layout/RenderFrame.h" // For RenderFrame
 #include "nsIContentInlines.h" // for nsINode::IsEditable()
 #include "nsIPresShell.h"  // for nsIPresShell
 #include "nsLayoutUtils.h" // for nsLayoutUtils
 
 #define ENABLE_FT_LOGGING 0
 // #define ENABLE_FT_LOGGING 1
 
 #if ENABLE_FT_LOGGING
@@ -161,26 +161,26 @@ FocusTarget::FocusTarget(nsIPresShell* a
            aFocusSequenceNumber,
            static_cast<int>(mFocusHasKeyEventListeners));
 
     return;
   }
 
   // Check if the key event target is a remote browser
   if (TabParent* browserParent = TabParent::GetFrom(keyEventTarget)) {
-    RenderFrameParent* rfp = browserParent->GetRenderFrame();
+    RenderFrame* rf = browserParent->GetRenderFrame();
 
     // The globally focused element for scrolling is in a remote layer tree
-    if (rfp) {
+    if (rf) {
       FT_LOG("Creating reflayer target with seq=%" PRIu64 ", kl=%d, lt=%" PRIu64 "\n",
              aFocusSequenceNumber,
              mFocusHasKeyEventListeners,
-             rfp->GetLayersId());
+             rf->GetLayersId());
 
-      mData = AsVariant<LayersId>(rfp->GetLayersId());
+      mData = AsVariant<LayersId>(rf->GetLayersId());
       return;
     }
 
     FT_LOG("Creating nil target with seq=%" PRIu64 ", kl=%d (remote browser missing layers id)\n",
            aFocusSequenceNumber,
            mFocusHasKeyEventListeners);
 
     return;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -58,17 +58,16 @@
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayerManagerMLGPU.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/layers/RemoteContentController.h"
 #include "mozilla/layers/WebRenderBridgeParent.h"
 #include "mozilla/layers/AsyncImagePipelineManager.h"
-#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/Telemetry.h"
 #ifdef MOZ_WIDGET_GTK
 #include "basic/X11BasicCompositor.h" // for X11BasicCompositor
 #endif
 #include "nsCOMPtr.h"                   // for already_AddRefed
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -10,20 +10,16 @@
 #include <stdint.h>                     // for uint32_t
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
-namespace layout {
-class RenderFrameChild;
-} // namespace layout
-
 namespace layers {
 
 class ShadowLayerForwarder;
 
 class LayerTransactionChild : public PLayerTransactionChild
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild)
@@ -68,17 +64,16 @@ protected:
     AddRef();
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
   friend class CompositorBridgeChild;
-  friend class layout::RenderFrameChild;
 
   ShadowLayerForwarder* mForwarder;
   bool mIPCOpen;
   bool mDestroyed;
   LayersId mId;
 };
 
 } // namespace layers
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -34,18 +34,16 @@
 #include "nsMathUtils.h"                // for NS_round
 #include "nsPoint.h"                    // for nsPoint
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "TreeTraversal.h"              // for ForEachNode
 #include "GeckoProfiler.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/AsyncCompositionManager.h"
 
-using mozilla::layout::RenderFrameParent;
-
 namespace mozilla {
 namespace layers {
 
 //--------------------------------------------------
 // LayerTransactionParent
 LayerTransactionParent::LayerTransactionParent(HostLayerManager* aManager,
                                                CompositorBridgeParentBase* aBridge,
                                                CompositorAnimationStorage* aAnimStorage,
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -17,34 +17,29 @@
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 
 namespace mozilla {
 
 namespace ipc {
 class Shmem;
 } // namespace ipc
 
-namespace layout {
-class RenderFrameParent;
-} // namespace layout
-
 namespace layers {
 
 class Layer;
 class HostLayerManager;
 class ShadowLayerParent;
 class CompositableParent;
 class CompositorAnimationStorage;
 class CompositorBridgeParentBase;
 
 class LayerTransactionParent final : public PLayerTransactionParent,
                                      public CompositableParentManager,
                                      public ShmemAllocator
 {
-  typedef mozilla::layout::RenderFrameParent RenderFrameParent;
   typedef InfallibleTArray<Edit> EditArray;
   typedef InfallibleTArray<OpDestroy> OpDestroyArray;
   typedef InfallibleTArray<PluginWindowData> PluginsArray;
 
 public:
   LayerTransactionParent(HostLayerManager* aManager,
                          CompositorBridgeParentBase* aBridge,
                          CompositorAnimationStorage* aAnimStorage,
@@ -163,17 +158,16 @@ protected:
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
   friend class CompositorBridgeParent;
   friend class CrossProcessCompositorBridgeParent;
-  friend class layout::RenderFrameParent;
 
 private:
   // This is a function so we can log or breakpoint on why hit
   // testing tree changes are made.
   void UpdateHitTestingTree(Layer* aLayer, const char* aWhy) {
     mUpdateHitTestingTree = true;
   }
 
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -2,17 +2,16 @@
  * vim: sw=2 ts=8 et :
  */
 /* 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 LayersSurfaces;
 include protocol PCompositorBridge;
-include protocol PRenderFrame;
 include protocol PTexture;
 
 include "gfxipc/ShadowLayerUtils.h";
 include "mozilla/GfxMessageUtils.h";
 include "ImageLayers.h";
 
 using mozilla::gfx::Glyph from "mozilla/gfx/2D.h";
 using mozilla::gfx::SamplingFilter from "mozilla/gfx/2D.h";
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -3,17 +3,16 @@
  */
 /* 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 LayersSurfaces;
 include LayersMessages;
 include protocol PCompositorBridge;
-include protocol PRenderFrame;
 include protocol PTexture;
 
 include "mozilla/GfxMessageUtils.h";
 include "mozilla/layers/LayersMessageUtils.h";
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -9,17 +9,16 @@
 #include "base/message_loop.h"
 #include "base/task.h"
 #include "MainThreadUtils.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
 #include "mozilla/layers/APZThreadUtils.h"
-#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Unused.h"
 #include "Units.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -4,17 +4,16 @@
  * 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 "mozilla/layers/WebRenderScrollData.h"
 
 #include "Layers.h"
 #include "LayersLogging.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
-#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/Unused.h"
 #include "nsDisplayList.h"
 #include "nsTArray.h"
 #include "UnitTransforms.h"
 
 namespace mozilla {
 namespace layers {
 
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -1052,31 +1052,30 @@ gfxDWriteFontList::InitFontListForPlatfo
     HRESULT hr;
     mGDIFontTableAccess =
         Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading",
                              false);
 
     mFontSubstitutes.Clear();
     mNonExistingFonts.Clear();
 
-    hr = Factory::GetDWriteFactory()->
-        GetGdiInterop(getter_AddRefs(mGDIInterop));
+    RefPtr<IDWriteFactory> factory =
+        Factory::GetDWriteFactory();
+
+    hr = factory->GetGdiInterop(getter_AddRefs(mGDIInterop));
     if (FAILED(hr)) {
         Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
                               uint32_t(errGDIInterop));
         return NS_ERROR_FAILURE;
     }
 
     QueryPerformanceCounter(&t2); // base-class/interop initialization
 
-    RefPtr<IDWriteFactory> factory =
-        Factory::GetDWriteFactory();
-
-    hr = factory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
-    NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
+    mSystemFonts = Factory::GetDWriteSystemFonts(true);
+    NS_ASSERTION(mSystemFonts != nullptr, "GetSystemFontCollection failed!");
 
     if (FAILED(hr)) {
         Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
                               uint32_t(errSystemFontCollection));
         return NS_ERROR_FAILURE;
     }
 
     QueryPerformanceCounter(&t3); // system font collection
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -877,18 +877,16 @@ description = Retrieve supported clipboa
 [PContent::GetIconForExtension]
 description =
 [PContent::GetShowPasswordSetting]
 description =
 [PContent::KeywordToURI]
 description =
 [PContent::NotifyKeywordSearchLoading]
 description =
-[PContent::AllocateLayerTreeId]
-description =
 [PContent::BeginDriverCrashGuard]
 description =
 [PContent::EndDriverCrashGuard]
 description =
 [PContent::KeygenProcessValue]
 description =
 [PContent::KeygenProvideContent]
 description =
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -131,106 +131,16 @@ BinASTParser<Tok>::parseSumAssignmentTar
         break;
       default:
         return raiseInvalidKind("AssignmentTarget", kind);
     }
     return result;
 }
 
 /*
-AssignmentTargetOrAssignmentTargetWithInitializer ::= ArrayAssignmentTarget
-    AssignmentTargetIdentifier
-    AssignmentTargetWithInitializer
-    ComputedMemberAssignmentTarget
-    ObjectAssignmentTarget
-    StaticMemberAssignmentTarget
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseAssignmentTargetOrAssignmentTargetWithInitializer()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumAssignmentTargetOrAssignmentTargetWithInitializer(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::ArrayAssignmentTarget:
-        MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
-        break;
-      case BinKind::AssignmentTargetIdentifier:
-        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
-        break;
-      case BinKind::AssignmentTargetWithInitializer:
-        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetWithInitializer(start, kind, fields));
-        break;
-      case BinKind::ComputedMemberAssignmentTarget:
-        MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields));
-        break;
-      case BinKind::ObjectAssignmentTarget:
-        MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields));
-        break;
-      case BinKind::StaticMemberAssignmentTarget:
-        MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("AssignmentTargetOrAssignmentTargetWithInitializer", kind);
-    }
-    return result;
-}
-
-/*
-AssignmentTargetProperty ::= AssignmentTargetPropertyIdentifier
-    AssignmentTargetPropertyProperty
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseAssignmentTargetProperty()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumAssignmentTargetProperty(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::AssignmentTargetPropertyIdentifier:
-        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyIdentifier(start, kind, fields));
-        break;
-      case BinKind::AssignmentTargetPropertyProperty:
-        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyProperty(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("AssignmentTargetProperty", kind);
-    }
-    return result;
-}
-
-/*
 Binding ::= ArrayBinding
     BindingIdentifier
     ObjectBinding
 */
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseBinding()
 {
     BinKind kind;
@@ -262,98 +172,16 @@ BinASTParser<Tok>::parseSumBinding(const
         break;
       default:
         return raiseInvalidKind("Binding", kind);
     }
     return result;
 }
 
 /*
-BindingOrBindingWithInitializer ::= ArrayBinding
-    BindingIdentifier
-    BindingWithInitializer
-    ObjectBinding
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseBindingOrBindingWithInitializer()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumBindingOrBindingWithInitializer(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::ArrayBinding:
-        MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
-        break;
-      case BinKind::BindingIdentifier:
-        MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
-        break;
-      case BinKind::BindingWithInitializer:
-        MOZ_TRY_VAR(result, parseInterfaceBindingWithInitializer(start, kind, fields));
-        break;
-      case BinKind::ObjectBinding:
-        MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("BindingOrBindingWithInitializer", kind);
-    }
-    return result;
-}
-
-/*
-BindingProperty ::= BindingPropertyIdentifier
-    BindingPropertyProperty
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseBindingProperty()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumBindingProperty(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::BindingPropertyIdentifier:
-        MOZ_TRY_VAR(result, parseInterfaceBindingPropertyIdentifier(start, kind, fields));
-        break;
-      case BinKind::BindingPropertyProperty:
-        MOZ_TRY_VAR(result, parseInterfaceBindingPropertyProperty(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("BindingProperty", kind);
-    }
-    return result;
-}
-
-/*
 Expression ::= ArrayExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
@@ -662,177 +490,16 @@ BinASTParser<Tok>::parseSumExpressionOrS
         break;
       default:
         return raiseInvalidKind("ExpressionOrSuper", kind);
     }
     return result;
 }
 
 /*
-ExpressionOrTemplateElement ::= ArrayExpression
-    AssignmentExpression
-    AwaitExpression
-    BinaryExpression
-    CallExpression
-    ClassExpression
-    CompoundAssignmentExpression
-    ComputedMemberExpression
-    ConditionalExpression
-    EagerArrowExpressionWithExpression
-    EagerArrowExpressionWithFunctionBody
-    EagerFunctionExpression
-    IdentifierExpression
-    LazyArrowExpressionWithExpression
-    LazyArrowExpressionWithFunctionBody
-    LazyFunctionExpression
-    LiteralBooleanExpression
-    LiteralInfinityExpression
-    LiteralNullExpression
-    LiteralNumericExpression
-    LiteralRegExpExpression
-    LiteralStringExpression
-    NewExpression
-    NewTargetExpression
-    ObjectExpression
-    StaticMemberExpression
-    TemplateElement
-    TemplateExpression
-    ThisExpression
-    UnaryExpression
-    UpdateExpression
-    YieldExpression
-    YieldStarExpression
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseExpressionOrTemplateElement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumExpressionOrTemplateElement(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::ArrayExpression:
-        MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
-        break;
-      case BinKind::AssignmentExpression:
-        MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields));
-        break;
-      case BinKind::AwaitExpression:
-        MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
-        break;
-      case BinKind::BinaryExpression:
-        MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
-        break;
-      case BinKind::CallExpression:
-        MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
-        break;
-      case BinKind::ClassExpression:
-        MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
-        break;
-      case BinKind::CompoundAssignmentExpression:
-        MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
-        break;
-      case BinKind::ComputedMemberExpression:
-        MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
-        break;
-      case BinKind::ConditionalExpression:
-        MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
-        break;
-      case BinKind::EagerArrowExpressionWithExpression:
-        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(start, kind, fields));
-        break;
-      case BinKind::EagerArrowExpressionWithFunctionBody:
-        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(start, kind, fields));
-        break;
-      case BinKind::EagerFunctionExpression:
-        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
-        break;
-      case BinKind::IdentifierExpression:
-        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
-        break;
-      case BinKind::LazyArrowExpressionWithExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
-        break;
-      case BinKind::LazyArrowExpressionWithFunctionBody:
-        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
-        break;
-      case BinKind::LazyFunctionExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralBooleanExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralInfinityExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralNullExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralNumericExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralRegExpExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralStringExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
-        break;
-      case BinKind::NewExpression:
-        MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
-        break;
-      case BinKind::NewTargetExpression:
-        MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
-        break;
-      case BinKind::ObjectExpression:
-        MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
-        break;
-      case BinKind::StaticMemberExpression:
-        MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
-        break;
-      case BinKind::TemplateElement:
-        MOZ_TRY_VAR(result, parseInterfaceTemplateElement(start, kind, fields));
-        break;
-      case BinKind::TemplateExpression:
-        MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
-        break;
-      case BinKind::ThisExpression:
-        MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
-        break;
-      case BinKind::UnaryExpression:
-        MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
-        break;
-      case BinKind::UpdateExpression:
-        MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
-        break;
-      case BinKind::YieldExpression:
-        MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
-        break;
-      case BinKind::YieldStarExpression:
-        MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("ExpressionOrTemplateElement", kind);
-    }
-    return result;
-}
-
-/*
 ForInOfBindingOrAssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ForInOfBinding
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template<typename Tok> JS::Result<ParseNode*>
@@ -876,436 +543,16 @@ BinASTParser<Tok>::parseSumForInOfBindin
         break;
       default:
         return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind);
     }
     return result;
 }
 
 /*
-FunctionDeclarationOrClassDeclarationOrExpression ::= ArrayExpression
-    AssignmentExpression
-    AwaitExpression
-    BinaryExpression
-    CallExpression
-    ClassDeclaration
-    ClassExpression
-    CompoundAssignmentExpression
-    ComputedMemberExpression
-    ConditionalExpression
-    EagerArrowExpressionWithExpression
-    EagerArrowExpressionWithFunctionBody
-    EagerFunctionDeclaration
-    EagerFunctionExpression
-    IdentifierExpression
-    LazyArrowExpressionWithExpression
-    LazyArrowExpressionWithFunctionBody
-    LazyFunctionDeclaration
-    LazyFunctionExpression
-    LiteralBooleanExpression
-    LiteralInfinityExpression
-    LiteralNullExpression
-    LiteralNumericExpression
-    LiteralRegExpExpression
-    LiteralStringExpression
-    NewExpression
-    NewTargetExpression
-    ObjectExpression
-    StaticMemberExpression
-    TemplateExpression
-    ThisExpression
-    UnaryExpression
-    UpdateExpression
-    YieldExpression
-    YieldStarExpression
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseFunctionDeclarationOrClassDeclarationOrExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumFunctionDeclarationOrClassDeclarationOrExpression(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::ArrayExpression:
-        MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
-        break;
-      case BinKind::AssignmentExpression:
-        MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields));
-        break;
-      case BinKind::AwaitExpression:
-        MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
-        break;
-      case BinKind::BinaryExpression:
-        MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
-        break;
-      case BinKind::CallExpression:
-        MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
-        break;
-      case BinKind::ClassDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
-        break;
-      case BinKind::ClassExpression:
-        MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
-        break;
-      case BinKind::CompoundAssignmentExpression:
-        MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
-        break;
-      case BinKind::ComputedMemberExpression:
-        MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
-        break;
-      case BinKind::ConditionalExpression:
-        MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
-        break;
-      case BinKind::EagerArrowExpressionWithExpression:
-        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(start, kind, fields));
-        break;
-      case BinKind::EagerArrowExpressionWithFunctionBody:
-        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(start, kind, fields));
-        break;
-      case BinKind::EagerFunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
-        break;
-      case BinKind::EagerFunctionExpression:
-        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
-        break;
-      case BinKind::IdentifierExpression:
-        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
-        break;
-      case BinKind::LazyArrowExpressionWithExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
-        break;
-      case BinKind::LazyArrowExpressionWithFunctionBody:
-        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
-        break;
-      case BinKind::LazyFunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(start, kind, fields));
-        break;
-      case BinKind::LazyFunctionExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralBooleanExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralInfinityExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralNullExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralNumericExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralRegExpExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
-        break;
-      case BinKind::LiteralStringExpression:
-        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
-        break;
-      case BinKind::NewExpression:
-        MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
-        break;
-      case BinKind::NewTargetExpression:
-        MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
-        break;
-      case BinKind::ObjectExpression:
-        MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
-        break;
-      case BinKind::StaticMemberExpression:
-        MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
-        break;
-      case BinKind::TemplateExpression:
-        MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
-        break;
-      case BinKind::ThisExpression:
-        MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
-        break;
-      case BinKind::UnaryExpression:
-        MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
-        break;
-      case BinKind::UpdateExpression:
-        MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
-        break;
-      case BinKind::YieldExpression:
-        MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
-        break;
-      case BinKind::YieldStarExpression:
-        MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrExpression", kind);
-    }
-    return result;
-}
-
-/*
-FunctionDeclarationOrClassDeclarationOrVariableDeclaration ::= ClassDeclaration
-    EagerFunctionDeclaration
-    LazyFunctionDeclaration
-    VariableDeclaration
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::ClassDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
-        break;
-      case BinKind::EagerFunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
-        break;
-      case BinKind::LazyFunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(start, kind, fields));
-        break;
-      case BinKind::VariableDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrVariableDeclaration", kind);
-    }
-    return result;
-}
-
-/*
-ImportDeclarationOrExportDeclarationOrStatement ::= Block
-    BreakStatement
-    ClassDeclaration
-    ContinueStatement
-    DebuggerStatement
-    DoWhileStatement
-    EagerFunctionDeclaration
-    EmptyStatement
-    Export
-    ExportAllFrom
-    ExportDefault
-    ExportFrom
-    ExportLocals
-    ExpressionStatement
-    ForInStatement
-    ForOfStatement
-    ForStatement
-    IfStatement
-    Import
-    ImportNamespace
-    LabelledStatement
-    LazyFunctionDeclaration
-    ReturnStatement
-    SwitchStatement
-    SwitchStatementWithDefault
-    ThrowStatement
-    TryCatchStatement
-    TryFinallyStatement
-    VariableDeclaration
-    WhileStatement
-    WithStatement
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseImportDeclarationOrExportDeclarationOrStatement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumImportDeclarationOrExportDeclarationOrStatement(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::Block:
-        MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields));
-        break;
-      case BinKind::BreakStatement:
-        MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields));
-        break;
-      case BinKind::ClassDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
-        break;
-      case BinKind::ContinueStatement:
-        MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields));
-        break;
-      case BinKind::DebuggerStatement:
-        MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields));
-        break;
-      case BinKind::DoWhileStatement:
-        MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
-        break;
-      case BinKind::EagerFunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
-        break;
-      case BinKind::EmptyStatement:
-        MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields));
-        break;
-      case BinKind::Export:
-        MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields));
-        break;
-      case BinKind::ExportAllFrom:
-        MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields));
-        break;
-      case BinKind::ExportDefault:
-        MOZ_TRY_VAR(result, parseInterfaceExportDefault(start, kind, fields));
-        break;
-      case BinKind::ExportFrom:
-        MOZ_TRY_VAR(result, parseInterfaceExportFrom(start, kind, fields));
-        break;
-      case BinKind::ExportLocals:
-        MOZ_TRY_VAR(result, parseInterfaceExportLocals(start, kind, fields));
-        break;
-      case BinKind::ExpressionStatement:
-        MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields));
-        break;
-      case BinKind::ForInStatement:
-        MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields));
-        break;
-      case BinKind::ForOfStatement:
-        MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields));
-        break;
-      case BinKind::ForStatement:
-        MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields));
-        break;
-      case BinKind::IfStatement:
-        MOZ_TRY_VAR(result, parseInterfaceIfStatement(start, kind, fields));
-        break;
-      case BinKind::Import:
-        MOZ_TRY_VAR(result, parseInterfaceImport(start, kind, fields));
-        break;
-      case BinKind::ImportNamespace:
-        MOZ_TRY_VAR(result, parseInterfaceImportNamespace(start, kind, fields));
-        break;
-      case BinKind::LabelledStatement:
-        MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields));
-        break;
-      case BinKind::LazyFunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(start, kind, fields));
-        break;
-      case BinKind::ReturnStatement:
-        MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields));
-        break;
-      case BinKind::SwitchStatement:
-        MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields));
-        break;
-      case BinKind::SwitchStatementWithDefault:
-        MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields));
-        break;
-      case BinKind::ThrowStatement:
-        MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields));
-        break;
-      case BinKind::TryCatchStatement:
-        MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields));
-        break;
-      case BinKind::TryFinallyStatement:
-        MOZ_TRY_VAR(result, parseInterfaceTryFinallyStatement(start, kind, fields));
-        break;
-      case BinKind::VariableDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
-        break;
-      case BinKind::WhileStatement:
-        MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields));
-        break;
-      case BinKind::WithStatement:
-        MOZ_TRY_VAR(result, parseInterfaceWithStatement(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("ImportDeclarationOrExportDeclarationOrStatement", kind);
-    }
-    return result;
-}
-
-/*
-MethodDefinition ::= EagerGetter
-    EagerMethod
-    EagerSetter
-    LazyGetter
-    LazyMethod
-    LazySetter
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseMethodDefinition()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-    BINJS_MOZ_TRY_DECL(result, parseSumMethodDefinition(start, kind, fields));
-
-    MOZ_TRY(guard.done());
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::EagerGetter:
-        MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
-        break;
-      case BinKind::EagerMethod:
-        MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
-        break;
-      case BinKind::EagerSetter:
-        MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
-        break;
-      case BinKind::LazyGetter:
-        MOZ_TRY_VAR(result, parseInterfaceLazyGetter(start, kind, fields));
-        break;
-      case BinKind::LazyMethod:
-        MOZ_TRY_VAR(result, parseInterfaceLazyMethod(start, kind, fields));
-        break;
-      case BinKind::LazySetter:
-        MOZ_TRY_VAR(result, parseInterfaceLazySetter(start, kind, fields));
-        break;
-      default:
-        return raiseInvalidKind("MethodDefinition", kind);
-    }
-    return result;
-}
-
-/*
 ObjectProperty ::= DataProperty
     EagerGetter
     EagerMethod
     EagerSetter
     LazyGetter
     LazyMethod
     LazySetter
     ShorthandProperty
@@ -1957,82 +1204,16 @@ BinASTParser<Tok>::parseInterfaceArrayEx
         elements->setHasNonConstInitializer();
     }
     auto result = elements;
     return result;
 }
 
 
 /*
- interface ArrowExpressionContentsWithExpression : Node {
-    AssertedParameterScope parameterScope;
-    FormalParameters params;
-    AssertedVarScope bodyScope;
-    Expression body;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseArrowExpressionContentsWithExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::ArrowExpressionContentsWithExpression) {
-        return raiseInvalidKind("ArrowExpressionContentsWithExpression", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceArrowExpressionContentsWithExpression(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceArrowExpressionContentsWithExpression(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ArrowExpressionContentsWithExpression)");
-}
-
-
-/*
- interface ArrowExpressionContentsWithFunctionBody : Node {
-    AssertedParameterScope parameterScope;
-    FormalParameters params;
-    AssertedVarScope bodyScope;
-    FunctionBody body;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseArrowExpressionContentsWithFunctionBody()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::ArrowExpressionContentsWithFunctionBody) {
-        return raiseInvalidKind("ArrowExpressionContentsWithFunctionBody", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceArrowExpressionContentsWithFunctionBody(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceArrowExpressionContentsWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ArrowExpressionContentsWithFunctionBody)");
-}
-
-
-/*
  interface AssertedBlockScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template<typename Tok> JS::Result<Ok>
 BinASTParser<Tok>::parseAssertedBlockScope()
 {
@@ -2236,22 +1417,16 @@ BinASTParser<Tok>::parseInterfaceAsserte
     ParseContext::Scope* scope;
     DeclarationKind declKind;
     MOZ_TRY(getDeclaredScope(scopeKind, kind_, scope, declKind));
     MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured, allowDuplicateName));
     auto result = Ok();
     return result;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceAssertedParameterName(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (AssertedParameterName)");
-}
-
 
 /*
  interface AssertedParameterScope : Node {
     FrozenArray<AssertedMaybePositionalParameterName> paramNames;
     bool hasDirectEval;
     bool isSimpleParameterList;
  }
 */
@@ -2349,22 +1524,16 @@ BinASTParser<Tok>::parseInterfaceAsserte
     ParseContext::Scope* scope;
     DeclarationKind declKind;
     MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
     MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured, allowDuplicateName));
     auto result = Ok();
     return result;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceAssertedRestParameterName(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (AssertedRestParameterName)");
-}
-
 
 /*
  interface AssertedScriptGlobalScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template<typename Tok> JS::Result<Ok>
@@ -2482,40 +1651,16 @@ BinASTParser<Tok>::parseInterfaceAssignm
     BINJS_MOZ_TRY_DECL(binding, parseAssignmentTarget());
 
     BINJS_MOZ_TRY_DECL(expression, parseExpression());
 
     BINJS_TRY_DECL(result, factory_.newAssignment(ParseNodeKind::Assign, binding, expression));
     return result;
 }
 
-
-/*
- interface AssignmentTargetIdentifier : Node {
-    [IdentifierName] string name;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseAssignmentTargetIdentifier()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::AssignmentTargetIdentifier) {
-        return raiseInvalidKind("AssignmentTargetIdentifier", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssignmentTargetIdentifier);
     BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
     const BinField expected_fields[1] = { BinField::Name };
@@ -2529,34 +1674,16 @@ BinASTParser<Tok>::parseInterfaceAssignm
         return raiseError("Invalid identifier");
     }
     BINJS_TRY(usedNames_.noteUse(cx_, name, parseContext_->scriptId(), parseContext_->innermostScope()->id()));
     BINJS_TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (AssignmentTargetPropertyIdentifier)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (AssignmentTargetPropertyProperty)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (AssignmentTargetWithInitializer)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet in this preview release (AwaitExpression)");
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
@@ -2711,28 +1838,16 @@ BinASTParser<Tok>::parseInterfaceBinding
     if (!IsIdentifier(name)) {
         return raiseError("Invalid identifier");
     }
     BINJS_TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (BindingPropertyIdentifier)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (BindingPropertyProperty)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet in this preview release (BindingWithInitializer)");
 }
 
 
 /*
  interface Block : Node {
@@ -2916,47 +2031,16 @@ BinASTParser<Tok>::parseInterfaceCatchCl
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet in this preview release (ClassDeclaration)");
 }
 
-
-/*
- interface ClassElement : Node {
-    bool isStatic;
-    MethodDefinition method;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseClassElement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::ClassElement) {
-        return raiseInvalidKind("ClassElement", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceClassElement(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ClassElement)");
-}
-
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet in this preview release (ClassExpression)");
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
@@ -3499,108 +2583,16 @@ BinASTParser<Tok>::parseInterfaceEmptySt
     BINJS_TRY(CheckRecursionLimit(cx_));
 MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
     BINJS_TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start)));
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (Export)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ExportAllFrom)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ExportDefault)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ExportFrom)");
-}
-
-
-/*
- interface ExportFromSpecifier : Node {
-    [IdentifierName] string name;
-    [IdentifierName] string? exportedName;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseExportFromSpecifier()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::ExportFromSpecifier) {
-        return raiseInvalidKind("ExportFromSpecifier", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceExportFromSpecifier(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ExportFromSpecifier)");
-}
-
-
-/*
- interface ExportLocalSpecifier : Node {
-    IdentifierExpression name;
-    [PropertyKey] string? exportedName;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseExportLocalSpecifier()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::ExportLocalSpecifier) {
-        return raiseInvalidKind("ExportLocalSpecifier", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceExportLocalSpecifier(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ExportLocalSpecifier)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ExportLocals)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ExpressionStatement);
     BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
     const BinField expected_fields[1] = { BinField::Expression };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
@@ -4028,59 +3020,16 @@ BinASTParser<Tok>::parseInterfaceIfState
 
     BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement());
 
     BINJS_TRY_DECL(result, factory_.newIfStatement(start, test, consequent, alternate));
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (Import)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ImportNamespace)");
-}
-
-
-/*
- interface ImportSpecifier : Node {
-    [PropertyKey] string? name;
-    BindingIdentifier binding;
- }
-*/
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseImportSpecifier()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::ImportSpecifier) {
-        return raiseInvalidKind("ImportSpecifier", kind);
-    }
-    const auto start = tokenizer_->offset();
-    BINJS_MOZ_TRY_DECL(result, parseInterfaceImportSpecifier(start, kind, fields));
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ImportSpecifier)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LabelledStatement);
     BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
     const BinField expected_fields[2] = { BinField::Label, BinField::Body };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
@@ -4770,22 +3719,16 @@ BinASTParser<Tok>::parseInterfaceSwitchS
         iter = next;
     }
     BINJS_TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
     BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope, true));
     return result;
 }
 
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields)
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (TemplateElement)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet in this preview release (TemplateExpression)");
 }
 
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
@@ -5493,40 +4436,16 @@ BinASTParser<Tok>::parseListOfAssertedMa
             scopeKind, positionalParams));
         // Nothing to do here.
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfAssignmentTargetOrAssignmentTargetWithInitializer()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfAssignmentTargetOrAssignmentTargetWithInitializer)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfAssignmentTargetProperty()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfAssignmentTargetProperty)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfBindingProperty()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfBindingProperty)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfClassElement()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfClassElement)");
-}
-
 template<typename Tok> JS::Result<ListNode*>
 BinASTParser<Tok>::parseListOfDirective()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
@@ -5536,46 +4455,16 @@ BinASTParser<Tok>::parseListOfDirective(
         BINJS_MOZ_TRY_DECL(item, parseDirective());
         factory_.addStatementToList(result, item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfExportFromSpecifier()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfExportFromSpecifier)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfExportLocalSpecifier()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfExportLocalSpecifier)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfExpressionOrTemplateElement()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfExpressionOrTemplateElement)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfImportDeclarationOrExportDeclarationOrStatement()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfImportDeclarationOrExportDeclarationOrStatement)");
-}
-
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfImportSpecifier()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfImportSpecifier)");
-}
-
 template<typename Tok> JS::Result<ListNode*>
 BinASTParser<Tok>::parseListOfObjectProperty()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
@@ -5587,22 +4476,16 @@ BinASTParser<Tok>::parseListOfObjectProp
             result->setHasNonConstInitializer();
         result->appendWithoutOrderAssumption(item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseListOfOptionalBindingOrBindingWithInitializer()
-{
-    return raiseError("FIXME: Not implemented yet in this preview release (ListOfOptionalBindingOrBindingWithInitializer)");
-}
-
 template<typename Tok> JS::Result<ListNode*>
 BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
@@ -5696,36 +4579,16 @@ BinASTParser<Tok>::parseListOfVariableDe
 
     MOZ_TRY(guard.done());
     return result;
 }
 
 
     // ----- Default values (by lexicographical order)
 template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseOptionalAssignmentTarget()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result;
-    if (kind == BinKind::_Null) {
-        result = nullptr;
-    } else {
-        const auto start = tokenizer_->offset();
-        MOZ_TRY_VAR(result, parseSumAssignmentTarget(start, kind, fields));
-    }
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
-template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseOptionalBinding()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
@@ -5757,36 +4620,16 @@ BinASTParser<Tok>::parseOptionalBindingI
     } else {
         return raiseInvalidKind("BindingIdentifier", kind);
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-template<typename Tok> JS::Result<ParseNode*>
-BinASTParser<Tok>::parseOptionalBindingOrBindingWithInitializer()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result;
-    if (kind == BinKind::_Null) {
-        result = nullptr;
-    } else {
-        const auto start = tokenizer_->offset();
-        MOZ_TRY_VAR(result, parseSumBindingOrBindingWithInitializer(start, kind, fields));
-    }
-    MOZ_TRY(guard.done());
-
-    return result;
-}
-
 template<typename Tok> JS::Result<LexicalScopeNode*>
 BinASTParser<Tok>::parseOptionalCatchClause()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
--- a/js/src/frontend/BinSource-auto.h
+++ b/js/src/frontend/BinSource-auto.h
@@ -88,145 +88,110 @@ enum class VariableDeclarationKind {
 
 // ----- Sums of interfaces (by lexicographical order)
 // Implementations are autogenerated
 // `ParseNode*` may never be nullptr
 JS::Result<Ok> parseAssertedMaybePositionalParameterName(
     AssertedScopeKind scopeKind,
     MutableHandle<GCVector<JSAtom*>> positionalParams);
 JS::Result<ParseNode*> parseAssignmentTarget();
-JS::Result<ParseNode*> parseAssignmentTargetOrAssignmentTargetWithInitializer();
-JS::Result<ParseNode*> parseAssignmentTargetProperty();
 JS::Result<ParseNode*> parseBinding();
-JS::Result<ParseNode*> parseBindingOrBindingWithInitializer();
-JS::Result<ParseNode*> parseBindingProperty();
 JS::Result<ParseNode*> parseExpression();
 JS::Result<ParseNode*> parseExpressionOrSuper();
-JS::Result<ParseNode*> parseExpressionOrTemplateElement();
 JS::Result<ParseNode*> parseForInOfBindingOrAssignmentTarget();
-JS::Result<ParseNode*> parseFunctionDeclarationOrClassDeclarationOrExpression();
-JS::Result<ParseNode*> parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration();
-JS::Result<ParseNode*> parseImportDeclarationOrExportDeclarationOrStatement();
-JS::Result<ParseNode*> parseMethodDefinition();
 JS::Result<ParseNode*> parseObjectProperty();
 JS::Result<ParseNode*> parseParameter();
 JS::Result<ParseNode*> parseProgram();
 JS::Result<ParseNode*> parsePropertyName();
 JS::Result<ParseNode*> parseSimpleAssignmentTarget();
 JS::Result<ParseNode*> parseSpreadElementOrExpression();
 JS::Result<ParseNode*> parseStatement();
 JS::Result<Ok> parseSumAssertedMaybePositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
     AssertedScopeKind scopeKind,
     MutableHandle<GCVector<JSAtom*>> positionalParams);
 JS::Result<ParseNode*> parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
 
 
 // ----- Interfaces (by lexicographical order)
 // Implementations are autogenerated
 // `ParseNode*` may never be nullptr
-JS::Result<ParseNode*> parseArrowExpressionContentsWithExpression();
-JS::Result<ParseNode*> parseArrowExpressionContentsWithFunctionBody();
 JS::Result<Ok> parseAssertedBlockScope();
 JS::Result<Ok> parseAssertedBoundName(
     AssertedScopeKind scopeKind);
 JS::Result<Ok> parseAssertedBoundNamesScope();
 JS::Result<Ok> parseAssertedDeclaredName(
     AssertedScopeKind scopeKind);
 JS::Result<Ok> parseAssertedParameterScope(
     MutableHandle<GCVector<JSAtom*>> positionalParams);
 JS::Result<Ok> parseAssertedScriptGlobalScope();
 JS::Result<Ok> parseAssertedVarScope();
-JS::Result<ParseNode*> parseAssignmentTargetIdentifier();
 JS::Result<ParseNode*> parseBindingIdentifier();
 JS::Result<ParseNode*> parseBlock();
 JS::Result<LexicalScopeNode*> parseCatchClause();
-JS::Result<ParseNode*> parseClassElement();
 JS::Result<ParseNode*> parseDirective();
-JS::Result<ParseNode*> parseExportFromSpecifier();
-JS::Result<ParseNode*> parseExportLocalSpecifier();
 JS::Result<ListNode*> parseFormalParameters();
 JS::Result<Ok> parseFunctionExpressionContents(
     uint32_t funLength,
     ListNode** paramsOut,
     ListNode** bodyOut);
 JS::Result<Ok> parseFunctionOrMethodContents(
     uint32_t funLength,
     ListNode** paramsOut,
     ListNode** bodyOut);
 JS::Result<Ok> parseGetterContents(
     uint32_t funLength,
     ListNode** paramsOut,
     ListNode** bodyOut);
 JS::Result<ParseNode*> parseIdentifierExpression();
-JS::Result<ParseNode*> parseImportSpecifier();
 JS::Result<Ok> parseSetterContents(
     uint32_t funLength,
     ListNode** paramsOut,
     ListNode** bodyOut);
 JS::Result<CaseClause*> parseSwitchCase();
 JS::Result<ParseNode*> parseSwitchDefault();
 JS::Result<ParseNode*> parseVariableDeclarator();
 JS::Result<ParseNode*> parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceArrowExpressionContentsWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceArrowExpressionContentsWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceAssertedBoundName(const size_t start, const BinKind kind, const BinFields& fields,
     AssertedScopeKind scopeKind);
 JS::Result<Ok> parseInterfaceAssertedBoundNamesScope(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceAssertedDeclaredName(const size_t start, const BinKind kind, const BinFields& fields,
     AssertedScopeKind scopeKind);
-JS::Result<ParseNode*> parseInterfaceAssertedParameterName(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields,
     MutableHandle<GCVector<JSAtom*>> positionalParams);
 JS::Result<Ok> parseInterfaceAssertedPositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
     AssertedScopeKind scopeKind,
     MutableHandle<GCVector<JSAtom*>> positionalParams);
-JS::Result<ParseNode*> parseInterfaceAssertedRestParameterName(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceAssertedScriptGlobalScope(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<LexicalScopeNode*> parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields);
@@ -236,23 +201,16 @@ JS::Result<ParseNode*> parseInterfaceDoW
 JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEagerFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEagerFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEagerGetter(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEagerMethod(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEagerSetter(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ListNode*> parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<Ok> parseInterfaceFunctionExpressionContents(const size_t start, const BinKind kind, const BinFields& fields,
     uint32_t funLength,
@@ -263,19 +221,16 @@ JS::Result<Ok> parseInterfaceFunctionOrM
     ListNode** paramsOut,
     ListNode** bodyOut);
 JS::Result<Ok> parseInterfaceGetterContents(const size_t start, const BinKind kind, const BinFields& fields,
     uint32_t funLength,
     ListNode** paramsOut,
     ListNode** bodyOut);
 JS::Result<ParseNode*> parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazyFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazyFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazyGetter(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazyMethod(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceLazySetter(const size_t start, const BinKind kind, const BinFields& fields);
@@ -302,17 +257,16 @@ JS::Result<ParseNode*> parseInterfaceSho
 JS::Result<ParseNode*> parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<CaseClause*> parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields);
-JS::Result<ParseNode*> parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
@@ -339,39 +293,27 @@ JS::Result<ParseNode*> parseArguments();
 JS::Result<ListNode*> parseFunctionBody();
 JS::Result<Ok> parseListOfAssertedBoundName(
     AssertedScopeKind scopeKind);
 JS::Result<Ok> parseListOfAssertedDeclaredName(
     AssertedScopeKind scopeKind);
 JS::Result<Ok> parseListOfAssertedMaybePositionalParameterName(
     AssertedScopeKind scopeKind,
     MutableHandle<GCVector<JSAtom*>> positionalParams);
-JS::Result<ParseNode*> parseListOfAssignmentTargetOrAssignmentTargetWithInitializer();
-JS::Result<ParseNode*> parseListOfAssignmentTargetProperty();
-JS::Result<ParseNode*> parseListOfBindingProperty();
-JS::Result<ParseNode*> parseListOfClassElement();
 JS::Result<ListNode*> parseListOfDirective();
-JS::Result<ParseNode*> parseListOfExportFromSpecifier();
-JS::Result<ParseNode*> parseListOfExportLocalSpecifier();
-JS::Result<ParseNode*> parseListOfExpressionOrTemplateElement();
-JS::Result<ParseNode*> parseListOfImportDeclarationOrExportDeclarationOrStatement();
-JS::Result<ParseNode*> parseListOfImportSpecifier();
 JS::Result<ListNode*> parseListOfObjectProperty();
-JS::Result<ParseNode*> parseListOfOptionalBindingOrBindingWithInitializer();
 JS::Result<ListNode*> parseListOfOptionalSpreadElementOrExpression();
 JS::Result<ListNode*> parseListOfParameter();
 JS::Result<ListNode*> parseListOfStatement();
 JS::Result<ListNode*> parseListOfSwitchCase();
 JS::Result<ListNode*> parseListOfVariableDeclarator();
 
 
 // ----- Default values (by lexicographical order)
 // Implementations are autogenerated
-JS::Result<ParseNode*> parseOptionalAssignmentTarget();
 JS::Result<ParseNode*> parseOptionalBinding();
 JS::Result<ParseNode*> parseOptionalBindingIdentifier();
-JS::Result<ParseNode*> parseOptionalBindingOrBindingWithInitializer();
 JS::Result<LexicalScopeNode*> parseOptionalCatchClause();
 JS::Result<ParseNode*> parseOptionalExpression();
 JS::Result<ParseNode*> parseOptionalSpreadElementOrExpression();
 JS::Result<ParseNode*> parseOptionalStatement();
 JS::Result<ParseNode*> parseOptionalVariableDeclarationOrExpression();
 
--- a/js/src/frontend/binsource/src/main.rs
+++ b/js/src/frontend/binsource/src/main.rs
@@ -514,24 +514,16 @@ const INTERFACE_PARAMS: &str =
 /// Fixed arguments of interface method.
 const INTERFACE_ARGS: &str =
     "start, kind, fields";
 
 /// The name of the toplevel interface for the script.
 const TOPLEVEL_INTERFACE: &str =
     "Program";
 
-/// Get Rc<String> from NodeName.
-///
-/// FIXME: Do not clone the String itself, but just clone the Rc<String> inside
-///        NodeName (Bug 1504597).
-fn string_from_nodename(name: &NodeName) -> Rc<String> {
-    Rc::new(name.to_string().clone())
-}
-
 /// The actual exporter.
 struct CPPExporter {
     /// The syntax to export.
     syntax: Spec,
 
     /// Rules, as specified in yaml.
     rules: GlobalRules,
 
@@ -638,61 +630,95 @@ impl CPPExporter {
         let mut refgraph = ReferenceGraph::new();
 
         // FIXME: Reflect `replace` rule in yaml file for each interface to
         //        the reference (bug 1504595).
 
         // 1. Typesums
         let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name();
         for (name, nodes) in sums_of_interfaces {
+            let rules_for_this_sum = self.rules.get(name);
+
             let mut edges: HashSet<Rc<String>> = HashSet::new();
             edges.insert(Rc::new(format!("Sum{}", name)));
-            refgraph.insert(string_from_nodename(name), edges);
+            refgraph.insert(name.to_rc_string().clone(), edges);
 
             let mut sum_edges: HashSet<Rc<String>> = HashSet::new();
             for node in nodes {
+                let rule_for_this_arm = rules_for_this_sum.by_sum.get(&node)
+                    .cloned()
+                    .unwrap_or_default();
+
+                // If this arm is disabled, we emit raiseError instead of
+                // call to parseInterface*.  Do not add edge in that case.
+                if rule_for_this_arm.disabled {
+                    continue;
+                }
+
                 sum_edges.insert(Rc::new(format!("Interface{}", node.to_string())));
             }
             refgraph.insert(Rc::new(format!("Sum{}", name.to_string())), sum_edges);
         }
 
         // 2. Single interfaces
         let interfaces_by_name = self.syntax.interfaces_by_name();
         for (name, interface) in interfaces_by_name {
-            let mut edges: HashSet<Rc<String>> = HashSet::new();
-            edges.insert(Rc::new(format!("Interface{}", name)));
-            refgraph.insert(string_from_nodename(name), edges);
+            let rules_for_this_interface = self.rules.get(name);
+            let is_implemented = rules_for_this_interface.build_result.is_some();
+            // If this interafce is not implemented, parse* method should
+            // not be called nor referenced in the graph.
+            if is_implemented {
+                let mut edges: HashSet<Rc<String>> = HashSet::new();
+                edges.insert(Rc::new(format!("Interface{}", name)));
+                refgraph.insert(name.to_rc_string().clone(), edges);
+            }
 
             let mut interface_edges: HashSet<Rc<String>> = HashSet::new();
-            for field in interface.contents().fields() {
-                match field.type_().get_primitive(&self.syntax) {
-                    Some(IsNullable { is_nullable: _, content: Primitive::Interface(_) })
-                    | None => {
-                        let typename = TypeName::type_(field.type_());
-                        interface_edges.insert(Rc::new(typename.to_string()));
-                    },
+            // If this interface is not implemented, we emit raiseError in
+            // parseInterface* method, instead of parse* for each fields.
+            // There can be reference to parseInterface* of this interface
+            // from sum interface, and this node needs to be represented in
+            // the reference graph.
+            if is_implemented {
+                for field in interface.contents().fields() {
+                    match field.type_().get_primitive(&self.syntax) {
+                        Some(IsNullable { is_nullable: _, content: Primitive::Interface(_) })
+                            | None => {
+                                let typename = TypeName::type_(field.type_());
+                                interface_edges.insert(Rc::new(typename.to_string()));
+                            },
 
-                    // Don't have to handle other type of fields (string,
-                    // number, bool, etc).
-                    _ => {}
+                        // Don't have to handle other type of fields (string,
+                        // number, bool, etc).
+                        _ => {}
+                    }
                 }
             }
             refgraph.insert(Rc::new(format!("Interface{}", name)), interface_edges);
         }
 
         // 3. String Enums
         for (kind, _) in self.syntax.string_enums_by_name() {
-            refgraph.insert(string_from_nodename(kind), HashSet::new());
+            refgraph.insert(kind.to_rc_string().clone(), HashSet::new());
         }
 
         // 4. Lists
         for parser in &self.list_parsers_to_generate {
+            let name = &parser.name;
+            let rules_for_this_list = self.rules.get(name);
+            let is_implemented = rules_for_this_list.init.is_some();
+            // If this list is not implemented, this method should not be
+            // called nor referenced in the graph.
+            if !is_implemented {
+                continue;
+            }
+
             let mut edges: HashSet<Rc<String>> = HashSet::new();
-            edges.insert(string_from_nodename(&parser.elements));
-            refgraph.insert(string_from_nodename(&parser.name), edges);
+            edges.insert(parser.elements.to_rc_string().clone());
+            refgraph.insert(name.to_rc_string().clone(), edges);
         }
 
         // 5. Optional values
         for parser in &self.option_parsers_to_generate {
             let mut edges: HashSet<Rc<String>> = HashSet::new();
             let named_implementation =
                 if let Some(NamedType::Typedef(ref typedef)) = self.syntax.get_type_by_name(&parser.name) {
                     assert!(typedef.is_optional());
@@ -717,17 +743,17 @@ impl CPPExporter {
                         &TypeSpec::TypeSum(_) => {
                             edges.insert(Rc::new(format!("Sum{}", parser.elements.to_string())));
                         },
                         _ => {}
                     }
                 },
                 _ => {}
             }
-            refgraph.insert(string_from_nodename(&parser.name), edges);
+            refgraph.insert(parser.name.to_rc_string().clone(), edges);
         }
 
         // 6. Primitive values.
         refgraph.insert(Rc::new("IdentifierName".to_string()), HashSet::new());
         refgraph.insert(Rc::new("PropertyKey".to_string()), HashSet::new());
 
         self.refgraph = refgraph;
     }
@@ -978,17 +1004,17 @@ enum class BinVariant {
     fn export_declare_sums_of_interface_methods(&self, buffer: &mut String) {
         let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name()
             .iter()
             .sorted_by(|a, b| a.0.cmp(&b.0));
         buffer.push_str("\n\n// ----- Sums of interfaces (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
         buffer.push_str("// `ParseNode*` may never be nullptr\n");
         for &(ref name, _) in &sums_of_interfaces {
-            if !self.refgraph.is_used(string_from_nodename(&name)) {
+            if !self.refgraph.is_used(name.to_rc_string().clone()) {
                 continue;
             }
 
             let rules_for_this_sum = self.rules.get(name);
             let extra_params = rules_for_this_sum.extra_params;
             let rendered = self.get_method_signature(name, "", "",
                                                      &extra_params);
             buffer.push_str(&rendered.reindent("")
@@ -1020,17 +1046,17 @@ enum class BinVariant {
 
         let mut outer_parsers = Vec::with_capacity(interfaces_by_name.len());
         let mut inner_parsers = Vec::with_capacity(interfaces_by_name.len());
 
         for &(name, _) in &interfaces_by_name {
             let rules_for_this_interface = self.rules.get(name);
             let extra_params = rules_for_this_interface.extra_params;
 
-            if self.refgraph.is_used(string_from_nodename(name)) {
+            if self.refgraph.is_used(name.to_rc_string().clone()) {
                 let outer = self.get_method_signature(name, "", "", &extra_params);
                 outer_parsers.push(outer.reindent(""));
             }
 
             let inner_prefix = "Interface";
             if !self.refgraph.is_used(Rc::new(format!("{}{}", inner_prefix, name))) {
                 continue;
             }
@@ -1053,48 +1079,48 @@ enum class BinVariant {
 
     fn export_declare_string_enums_methods(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- String enums (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
         let string_enums_by_name = self.syntax.string_enums_by_name()
             .iter()
             .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
         for (kind, _) in string_enums_by_name {
-            if !self.refgraph.is_used(string_from_nodename(kind)) {
+            if !self.refgraph.is_used(kind.to_rc_string().clone()) {
                 continue;
             }
 
             let rendered = self.get_method_signature(kind, "", "", &None);
             buffer.push_str(&rendered.reindent(""));
             buffer.push_str("\n");
         }
     }
 
     fn export_declare_list_methods(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- Lists (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
         for parser in &self.list_parsers_to_generate {
-            if !self.refgraph.is_used(string_from_nodename(&parser.name)) {
+            if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
                 continue;
             }
 
             let rules_for_this_node = self.rules.get(&parser.name);
             let extra_params = rules_for_this_node.extra_params;
             let rendered = self.get_method_signature(&parser.name, "", "",
                                                      &extra_params);
             buffer.push_str(&rendered.reindent(""));
             buffer.push_str("\n");
         }
     }
 
     fn export_declare_option_methods(&self, buffer: &mut String) {
         buffer.push_str("\n\n// ----- Default values (by lexicographical order)\n");
         buffer.push_str("// Implementations are autogenerated\n");
         for parser in &self.option_parsers_to_generate {
-            if !self.refgraph.is_used(string_from_nodename(&parser.name)) {
+            if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
                 continue;
             }
 
             let rules_for_this_node = self.rules.get(&parser.name);
             let extra_params = rules_for_this_node.extra_params;
             let rendered = self.get_method_signature(&parser.name, "", "",
                                                      &extra_params);
             buffer.push_str(&rendered.reindent(""));
@@ -1146,17 +1172,17 @@ impl CPPExporter {
         // Generate comments (FIXME: We should use the actual webidl, not the resolved sum)
         let rules_for_this_sum = self.rules.get(name);
         let extra_params = rules_for_this_sum.extra_params;
         let extra_args = rules_for_this_sum.extra_args;
         let nodes = nodes.iter()
             .sorted();
         let kind = name.to_class_cases();
 
-        if self.refgraph.is_used(string_from_nodename(name)) {
+        if self.refgraph.is_used(name.to_rc_string().clone()) {
             let rendered_bnf = format!("/*\n{name} ::= {nodes}\n*/",
                 nodes = nodes.iter()
                     .format("\n    "),
                 name = name.to_str());
 
             // Generate outer method
             buffer.push_str(&format!("{bnf}
 {first_line}
@@ -1234,17 +1260,17 @@ impl CPPExporter {
                                                           INTERFACE_PARAMS,
                                                           &extra_params),
             type_ok = self.get_type_ok(name)
         ));
     }
 
     /// Generate the implementation of a single list parser
     fn generate_implement_list(&self, buffer: &mut String, parser: &ListParserData) {
-        if !self.refgraph.is_used(string_from_nodename(&parser.name)) {
+        if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
             return;
         }
 
         let rules_for_this_list = self.rules.get(&parser.name);
         let extra_params = rules_for_this_list.extra_params;
         let extra_args = rules_for_this_list.extra_args;
 
         // Warn if some rules are unused.
@@ -1327,17 +1353,17 @@ impl CPPExporter {
             append = append);
         buffer.push_str(&rendered);
     }
 
     fn generate_implement_option(&self, buffer: &mut String, parser: &OptionParserData) {
         debug!(target: "generate_spidermonkey", "Implementing optional value {} backed by {}",
             parser.name.to_str(), parser.elements.to_str());
 
-        if !self.refgraph.is_used(string_from_nodename(&parser.name)) {
+        if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
             return;
         }
 
         let rules_for_this_node = self.rules.get(&parser.name);
         let extra_params = rules_for_this_node.extra_params;
         let extra_args = rules_for_this_node.extra_args;
 
         // Warn if some rules are unused.
@@ -1578,17 +1604,17 @@ impl CPPExporter {
         for &(condition, rule_name) in &[
             (rules_for_this_interface.append.is_some(), "build:"),
         ] {
             if condition {
                 warn!("In {}, rule `{}` was specified but is ignored.", name, rule_name);
             }
         }
 
-        if self.refgraph.is_used(string_from_nodename(name)) {
+        if self.refgraph.is_used(name.to_rc_string().clone()) {
             // Generate comments
             let comment = format!("\n/*\n{}*/\n", ToWebidl::interface(interface, "", "    "));
             buffer.push_str(&comment);
 
             // Generate public method
             buffer.push_str(&format!("{first_line}
 {{
     BinKind kind;
@@ -1860,17 +1886,17 @@ impl CPPExporter {
 
         // 3. String Enums
         buffer.push_str("\n\n// ----- String enums (autogenerated, by lexicographical order)\n");
         {
             let string_enums_by_name = self.syntax.string_enums_by_name()
                 .iter()
                 .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str()));
             for (kind, enum_) in string_enums_by_name {
-                if !self.refgraph.is_used(string_from_nodename(kind)) {
+                if !self.refgraph.is_used(kind.to_rc_string().clone()) {
                     continue;
                 }
 
                 let convert = format!("    switch (variant) {{
 {cases}
       default:
         return raiseInvalidVariant(\"{kind}\", variant);
     }}",
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -8,17 +8,17 @@
  * rendering object for replaced elements that contain a document, such
  * as <frame>, <iframe>, and some <object>s
  */
 
 #include "nsSubDocumentFrame.h"
 
 #include "gfxPrefs.h"
 
-#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/layout/RenderFrame.h"
 
 #include "nsCOMPtr.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGenericHTMLFrameElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsIDocShell.h"
 #include "nsIContentViewer.h"
 #include "nsIContentInlines.h"
@@ -41,17 +41,17 @@
 #include "nsContentUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/HTMLFrameElement.h"
 #include "RetainedDisplayListBuilder.h"
 
 using namespace mozilla;
-using mozilla::layout::RenderFrameParent;
+using mozilla::layout::RenderFrame;
 
 static bool sShowPreviousPage = true;
 
 static nsIDocument*
 GetDocumentFromView(nsView* aView)
 {
   MOZ_ASSERT(aView, "null view");
 
@@ -328,28 +328,28 @@ WrapBackgroundColorInOwnLayer(nsDisplayL
 void
 nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                      const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
 
   nsFrameLoader* frameLoader = FrameLoader();
-  RenderFrameParent* rfp = nullptr;
+  RenderFrame* rf = nullptr;
   if (frameLoader) {
-    rfp = frameLoader->GetCurrentRenderFrame();
+    rf = frameLoader->GetCurrentRenderFrame();
   }
 
   // If we are pointer-events:none then we don't need to HitTest background
   bool pointerEventsNone =
     StyleUI()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE;
   if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
     nsDisplayListCollection decorations(aBuilder);
     DisplayBorderBackgroundOutline(aBuilder, decorations);
-    if (rfp) {
+    if (rf) {
       // Wrap background colors of <iframe>s with remote subdocuments in their
       // own layer so we generate a ColorLayer. This is helpful for optimizing
       // compositing; we can skip compositing the ColorLayer when the
       // remote content is opaque.
       WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground());
     }
     decorations.MoveTo(aLists);
   }
@@ -361,17 +361,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
   // If we're passing pointer events to children then we have to descend into
   // subdocuments no matter what, to determine which parts are transparent for
   // hit-testing or event regions.
   bool needToDescend = aBuilder->GetDescendIntoSubdocuments();
   if (!mInnerView || !needToDescend) {
     return;
   }
 
-  if (rfp) {
+  if (rf) {
     // We're the subdoc for <browser remote="true"> and it has
     // painted content.  Display its shadow layer tree.
     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 
     nsPoint offset = aBuilder->ToReferenceFrame(this);
     nsRect bounds = this->EnsureInnerView()->GetBounds() + offset;
     clipState.ClipContentDescendants(bounds);
 
@@ -1076,18 +1076,18 @@ nsSubDocumentFrame::FrameLoader() const
     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
     if (loaderOwner) {
       mFrameLoader = loaderOwner->GetFrameLoader();
     }
   }
   return mFrameLoader;
 }
 
-mozilla::layout::RenderFrameParent*
-nsSubDocumentFrame::GetRenderFrameParent() const
+mozilla::layout::RenderFrame*
+nsSubDocumentFrame::GetRenderFrame() const
 {
   return FrameLoader() ? FrameLoader()->GetCurrentRenderFrame() : nullptr;
 }
 
 // XXX this should be called ObtainDocShell or something like that,
 // to indicate that it could have side effects
 nsIDocShell*
 nsSubDocumentFrame::GetDocShell()
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -10,17 +10,17 @@
 #include "mozilla/Attributes.h"
 #include "nsAtomicContainerFrame.h"
 #include "nsIReflowCallback.h"
 #include "nsFrameLoader.h"
 #include "Units.h"
 
 namespace mozilla {
 namespace layout {
-class RenderFrameParent;
+class RenderFrame;
 }
 }
 
 /******************************************************************************
  * nsSubDocumentFrame
  *****************************************************************************/
 class nsSubDocumentFrame final
   : public nsAtomicContainerFrame
@@ -135,17 +135,17 @@ public:
 
   void MaybeShowViewer()
   {
     if (!mDidCreateDoc && !mCallingShow) {
       ShowViewer();
     }
   }
 
-  mozilla::layout::RenderFrameParent* GetRenderFrameParent() const;
+  mozilla::layout::RenderFrame* GetRenderFrame() const;
 
 protected:
   friend class AsyncFrameInit;
 
   // Helper method to look up the HTML marginwidth & marginheight attributes.
   mozilla::CSSIntSize GetMarginAttributes();
 
   nsFrameLoader* FrameLoader() const;
deleted file mode 100644
--- a/layout/ipc/PRenderFrame.ipdl
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: sw=2 ts=8 et :
- */
-/* 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 protocol PBrowser;
-include protocol PLayerTransaction;
-
-
-using class nsRegion from "nsRegion.h";
-
-namespace mozilla {
-namespace layout {
-
-/**
- * PRenderFrame (in the layout sense of "frame") represents one web
- * "page".  It's used to graft content processes' layer trees into
- * chrome's rendering path.  The lifetime of a PRenderFrame is tied to
- * its PresShell in the child process.
- *
- * The child process conceptually "owns" a PRenderFrame, because it
- * only makes sense wrt documents loaded by the child.
- */
-sync protocol PRenderFrame
-{
-    manager PBrowser;
-
-parent:
-    async NotifyCompositorTransaction();
-
-    async __delete__();
-};
-
-} // namespace layout
-} // namespace mozilla
rename from layout/ipc/RenderFrameParent.cpp
rename to layout/ipc/RenderFrame.cpp
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrame.cpp
@@ -1,85 +1,38 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
-#include "BasicLayers.h"
-#include "gfxPrefs.h"
-#include "mozilla/BrowserElementParent.h"
-#include "mozilla/EventForwards.h"  // for Modifiers
-#include "mozilla/ViewportFrame.h"
-#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
-#include "mozilla/dom/Element.h"
-#include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerTransactionParent.h"
-#include "nsContentUtils.h"
-#include "nsFocusManager.h"
 #include "nsFrameLoader.h"
-#include "nsIObserver.h"
 #include "nsStyleStructInlines.h"
 #include "nsSubDocumentFrame.h"
-#include "nsView.h"
-#include "RenderFrameParent.h"
+#include "RenderFrame.h"
 #include "mozilla/gfx/GPUProcessManager.h"
-#include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/webrender/WebRenderAPI.h"
-#include "ClientLayerManager.h"
-#include "FrameLayerBuilder.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace layout {
 
-typedef ScrollableLayerGuid::ViewID ViewID;
-
-/**
- * Gets the layer-pixel offset of aContainerFrame's content rect top-left
- * from the nearest display item reference frame (which we assume will be inducing
- * a ContainerLayer).
- */
-static LayoutDeviceIntPoint
-GetContentRectLayerOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder)
-{
-  nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
-
-  // Offset to the content rect in case we have borders or padding
-  // Note that aContainerFrame could be a reference frame itself, so
-  // we need to be careful here to ensure that we call ToReferenceFrame
-  // on aContainerFrame and not its parent.
-  nsPoint frameOffset = aBuilder->ToReferenceFrame(aContainerFrame) +
-    aContainerFrame->GetContentRectRelativeToSelf().TopLeft();
-
-  return LayoutDeviceIntPoint::FromAppUnitsToNearest(frameOffset, auPerDevPixel);
-}
-
-// Return true iff |aManager| is a "temporary layer manager".  They're
-// used for small software rendering tasks, like drawWindow.  That's
-// currently implemented by a BasicLayerManager without a backing
-// widget, and hence in non-retained mode.
-inline static bool
-IsTempLayerManager(LayerManager* aManager)
-{
-  return (mozilla::layers::LayersBackend::LAYERS_BASIC == aManager->GetBackendType() &&
-          !static_cast<BasicLayerManager*>(aManager)->IsRetained());
-}
-
 static already_AddRefed<LayerManager>
 GetLayerManager(nsFrameLoader* aFrameLoader)
 {
   if (nsIContent* content = aFrameLoader->GetOwnerContent()) {
     RefPtr<LayerManager> lm = nsContentUtils::LayerManagerForContent(content);
     if (lm) {
       return lm.forget();
     }
@@ -87,134 +40,87 @@ GetLayerManager(nsFrameLoader* aFrameLoa
 
   nsIDocument* doc = aFrameLoader->GetOwnerDoc();
   if (!doc) {
     return nullptr;
   }
   return nsContentUtils::LayerManagerForDocument(doc);
 }
 
-RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader)
+RenderFrame::RenderFrame()
   : mLayersId{0}
+  , mFrameLoader(nullptr)
+  , mLayerManager(nullptr)
+  , mInitialized(false)
   , mLayersConnected(false)
-  , mFrameLoader(aFrameLoader)
-  , mFrameLoaderDestroyed(false)
-  , mAsyncPanZoomEnabled(false)
-  , mInitted(false)
 {
-  mInitted = Init(aFrameLoader);
 }
 
-RenderFrameParent::~RenderFrameParent()
-{}
+RenderFrame::~RenderFrame()
+{
+}
 
 bool
-RenderFrameParent::Init(nsFrameLoader* aFrameLoader)
+RenderFrame::Initialize(nsFrameLoader* aFrameLoader)
 {
-  if (mInitted || !aFrameLoader) {
+  if (mInitialized || !aFrameLoader) {
     return false;
   }
 
   mFrameLoader = aFrameLoader;
-
   RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader);
-
-  mAsyncPanZoomEnabled = lm && lm->AsyncPanZoomEnabled();
+  PCompositorBridgeChild* compositor = lm
+    ? lm->GetCompositorBridgeChild()
+    : nullptr;
 
-  TabParent* browser = TabParent::GetFrom(mFrameLoader);
-  if (XRE_IsParentProcess()) {
-    PCompositorBridgeChild* compositor = nullptr;
-    if (lm) {
-      compositor = lm->GetCompositorBridgeChild();
-    }
+  TabParent* browser = TabParent::GetFrom(aFrameLoader);
+  mTabProcessId = browser->Manager()->AsContentParent()->OtherPid();
 
-    // Our remote frame will push layers updates to the compositor,
-    // and we'll keep an indirect reference to that tree.
-    GPUProcessManager* gpm = GPUProcessManager::Get();
-    mLayersConnected = gpm->AllocateAndConnectLayerTreeId(
-      compositor,
-      browser->Manager()->AsContentParent()->OtherPid(),
-      &mLayersId,
-      &mCompositorOptions);
-  } else if (XRE_IsContentProcess()) {
-    ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), &mLayersId);
-    mLayersConnected = CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId, &mCompositorOptions);
-  }
+  // Our remote frame will push layers updates to the compositor,
+  // and we'll keep an indirect reference to that tree.
+  GPUProcessManager* gpm = GPUProcessManager::Get();
+  mLayersConnected = gpm->AllocateAndConnectLayerTreeId(
+    compositor,
+    mTabProcessId,
+    &mLayersId,
+    &mCompositorOptions);
 
-  mInitted = true;
+  mInitialized = true;
   return true;
 }
 
-bool
-RenderFrameParent::IsInitted()
+void
+RenderFrame::Destroy()
 {
-  return mInitted;
-}
+  if (mLayersId.IsValid()) {
+    GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, mTabProcessId);
+  }
 
-void
-RenderFrameParent::Destroy()
-{
-  mFrameLoaderDestroyed = true;
+  mFrameLoader = nullptr;
   mLayerManager = nullptr;
 }
 
-already_AddRefed<Layer>
-RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
-                              nsIFrame* aFrame,
-                              LayerManager* aManager,
-                              nsDisplayItem* aItem,
-                              const ContainerLayerParameters& aContainerParameters)
+void
+RenderFrame::EnsureLayersConnected(CompositorOptions* aCompositorOptions)
 {
-  MOZ_ASSERT(aFrame,
-             "makes no sense to have a shadow tree without a frame");
-
-  if (IsTempLayerManager(aManager)) {
-    // This can happen if aManager is a "temporary" manager, or if the
-    // widget's layer manager changed out from under us.  We need to
-    // FIXME handle the former case somehow, probably with an API to
-    // draw a manager's subtree.  The latter is bad bad bad, but the the
-    // MOZ_ASSERT() above will flag it.  Returning nullptr here will just
-    // cause the shadow subtree not to be rendered.
-    if (!aContainerParameters.mForEventsAndPluginsOnly) {
-      NS_WARNING("Remote iframe not rendered");
-    }
-    return nullptr;
+  RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader);
+  if (!lm) {
+    return;
   }
 
-  if (!mLayersId.IsValid()) {
-    return nullptr;
+  if (!lm->GetCompositorBridgeChild()) {
+    return;
   }
 
-  RefPtr<Layer> layer =
-    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
-  if (!layer) {
-    layer = aManager->CreateRefLayer();
-  }
-  if (!layer) {
-    // Probably a temporary layer manager that doesn't know how to
-    // use ref layers.
-    return nullptr;
-  }
-  static_cast<RefLayer*>(layer.get())->SetReferentId(mLayersId);
-  LayoutDeviceIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder);
-  // We can only have an offset if we're a child of an inactive
-  // container, but our display item is LAYER_ACTIVE_FORCE which
-  // forces all layers above to be active.
-  MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
-  gfx::Matrix4x4 m = gfx::Matrix4x4::Translation(offset.x, offset.y, 0.0);
-  // Remote content can't be repainted by us, so we multiply down
-  // the resolution that our container expects onto our container.
-  m.PreScale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
-  layer->SetBaseTransform(m);
-
-  return layer.forget();
+  mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildRecreated(mLayersId, &mCompositorOptions);
+  *aCompositorOptions = mCompositorOptions;
 }
 
 LayerManager*
-RenderFrameParent::AttachLayerManager()
+RenderFrame::AttachLayerManager()
 {
   RefPtr<LayerManager> lm;
   if (mFrameLoader) {
     lm = GetLayerManager(mFrameLoader);
   }
 
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->GetCompositorBridgeChild() && lm != mLayerManager) {
@@ -222,167 +128,169 @@ RenderFrameParent::AttachLayerManager()
     FrameLayerBuilder::InvalidateAllLayers(lm);
   }
 
   mLayerManager = lm.forget();
   return mLayerManager;
 }
 
 void
-RenderFrameParent::OwnerContentChanged(nsIContent* aContent)
+RenderFrame::OwnerContentChanged(nsIContent* aContent)
 {
   MOZ_ASSERT(!mFrameLoader || mFrameLoader->GetOwnerContent() == aContent,
              "Don't build new map if owner is same!");
 
   Unused << AttachLayerManager();
 }
 
 void
-RenderFrameParent::ActorDestroy(ActorDestroyReason why)
-{
-  if (mLayersId.IsValid()) {
-    if (XRE_IsParentProcess()) {
-      GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, OtherPid());
-    } else if (XRE_IsContentProcess()) {
-      TabParent* browser = TabParent::GetFrom(mFrameLoader);
-      ContentChild::GetSingleton()->SendDeallocateLayerTreeId(browser->Manager()->ChildID(), mLayersId);
-    }
-  }
-
-  mFrameLoader = nullptr;
-  mLayerManager = nullptr;
-}
-
-mozilla::ipc::IPCResult
-RenderFrameParent::RecvNotifyCompositorTransaction()
-{
-  TriggerRepaint();
-  return IPC_OK();
-}
-
-void
-RenderFrameParent::TriggerRepaint()
-{
-  nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent();
-  if (!docFrame) {
-    // Bad, but nothing we can do about it (XXX/cjones: or is there?
-    // maybe bug 589337?).  When the new frame is created, we'll
-    // probably still be the current render frame and will get to draw
-    // our content then.  Or, we're shutting down and this update goes
-    // to /dev/null.
-    return;
-  }
-
-  docFrame->InvalidateLayer(DisplayItemType::TYPE_REMOTE);
-}
-
-void
-RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier)
+RenderFrame::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier) const
 {
   RefPtr<LayerManager> lm = mFrameLoader ? GetLayerManager(mFrameLoader) : nullptr;
   // Perhaps the document containing this frame currently has no presentation?
   if (lm) {
     *aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier();
   } else {
     *aTextureFactoryIdentifier = TextureFactoryIdentifier();
   }
 }
 
-void
-RenderFrameParent::TakeFocusForClickFromTap()
+} // namespace layout
+} // namespace mozilla
+
+/**
+ * Gets the layer-pixel offset of aContainerFrame's content rect top-left
+ * from the nearest display item reference frame (which we assume will be inducing
+ * a ContainerLayer).
+ */
+static mozilla::LayoutDeviceIntPoint
+GetContentRectLayerOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder)
 {
-  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-  if (!fm) {
-    return;
-  }
-  RefPtr<Element> element = mFrameLoader->GetOwnerContent();
-  if (!element) {
-    return;
-  }
-  fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
-                        nsIFocusManager::FLAG_BYTOUCH |
-                        nsIFocusManager::FLAG_NOSCROLL);
+  nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
+
+  // Offset to the content rect in case we have borders or padding
+  // Note that aContainerFrame could be a reference frame itself, so
+  // we need to be careful here to ensure that we call ToReferenceFrame
+  // on aContainerFrame and not its parent.
+  nsPoint frameOffset = aBuilder->ToReferenceFrame(aContainerFrame) +
+    aContainerFrame->GetContentRectRelativeToSelf().TopLeft();
+
+  return mozilla::LayoutDeviceIntPoint::FromAppUnitsToNearest(frameOffset, auPerDevPixel);
 }
 
-void
-RenderFrameParent::EnsureLayersConnected(CompositorOptions* aCompositorOptions)
+// Return true iff |aManager| is a "temporary layer manager".  They're
+// used for small software rendering tasks, like drawWindow.  That's
+// currently implemented by a BasicLayerManager without a backing
+// widget, and hence in non-retained mode.
+inline static bool
+IsTempLayerManager(mozilla::layers::LayerManager* aManager)
 {
-  RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader);
-  if (!lm) {
-    return;
-  }
-
-  if (!lm->GetCompositorBridgeChild()) {
-    return;
-  }
-
-  mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildRecreated(mLayersId, &mCompositorOptions);
-  *aCompositorOptions = mCompositorOptions;
+  return (mozilla::layers::LayersBackend::LAYERS_BASIC == aManager->GetBackendType() &&
+          !static_cast<BasicLayerManager*>(aManager)->IsRetained());
 }
 
-} // namespace layout
-} // namespace mozilla
-
 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
                                  nsSubDocumentFrame* aFrame)
   : nsDisplayItem(aBuilder, aFrame)
   , mTabId{0}
   , mEventRegionsOverride(EventRegionsOverride::NoOverride)
 {
   bool frameIsPointerEventsNone =
     aFrame->StyleUI()->GetEffectivePointerEvents(aFrame) ==
       NS_STYLE_POINTER_EVENTS_NONE;
   if (aBuilder->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone) {
     mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion;
   }
   if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresShell())) {
     mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
   }
 
-  nsFrameLoader* frameLoader = GetRenderFrameParent()->FrameLoader();
+  nsFrameLoader* frameLoader = GetRenderFrame()->GetFrameLoader();
   if (frameLoader) {
     TabParent* browser = TabParent::GetFrom(frameLoader);
     if (browser) {
       mTabId = browser->GetTabId();
     }
   }
 }
 
 mozilla::LayerState
 nsDisplayRemote::GetLayerState(nsDisplayListBuilder* aBuilder,
                                LayerManager* aManager,
                                const ContainerLayerParameters& aParameters)
 {
-  if (mozilla::layout::IsTempLayerManager(aManager)) {
+  if (IsTempLayerManager(aManager)) {
     return mozilla::LAYER_NONE;
   }
   return mozilla::LAYER_ACTIVE_FORCE;
 }
 
 bool
 nsDisplayRemote::HasDeletedFrame() const
 {
-  // RenderFrameParent might change without invalidating nsSubDocumentFrame.
-  return !GetRenderFrameParent() || nsDisplayItem::HasDeletedFrame();
+  // RenderFrame might change without invalidating nsSubDocumentFrame.
+  return !GetRenderFrame() || nsDisplayItem::HasDeletedFrame();
 }
 
 already_AddRefed<Layer>
 nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
                             LayerManager* aManager,
                             const ContainerLayerParameters& aContainerParameters)
 {
-  MOZ_ASSERT(GetRenderFrameParent());
+  MOZ_ASSERT(GetRenderFrame());
+  MOZ_ASSERT(mFrame, "Makes no sense to have a shadow tree without a frame");
+
+  if (IsTempLayerManager(aManager)) {
+    // This can happen if aManager is a "temporary" manager, or if the
+    // widget's layer manager changed out from under us.  We need to
+    // FIXME handle the former case somehow, probably with an API to
+    // draw a manager's subtree.  The latter is bad bad bad, but the the
+    // MOZ_ASSERT() above will flag it.  Returning nullptr here will just
+    // cause the shadow subtree not to be rendered.
+    if (!aContainerParameters.mForEventsAndPluginsOnly) {
+      NS_WARNING("Remote iframe not rendered");
+    }
+    return nullptr;
+  }
+
+  LayersId remoteId = GetRenderFrame()->GetLayersId();
+
+  if (!remoteId.IsValid()) {
+    return nullptr;
+  }
 
   RefPtr<Layer> layer =
-    GetRenderFrameParent()->BuildLayer(aBuilder, mFrame, aManager,
-                                       this, aContainerParameters);
+    aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this);
+
+  if (!layer) {
+    layer = aManager->CreateRefLayer();
+  }
+
+  if (!layer) {
+    // Probably a temporary layer manager that doesn't know how to
+    // use ref layers.
+    return nullptr;
+  }
 
-  if (layer && layer->AsRefLayer()) {
+  static_cast<RefLayer*>(layer.get())->SetReferentId(remoteId);
+  LayoutDeviceIntPoint offset = GetContentRectLayerOffset(Frame(), aBuilder);
+  // We can only have an offset if we're a child of an inactive
+  // container, but our display item is LAYER_ACTIVE_FORCE which
+  // forces all layers above to be active.
+  MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
+  Matrix4x4 m = Matrix4x4::Translation(offset.x, offset.y, 0.0);
+  // Remote content can't be repainted by us, so we multiply down
+  // the resolution that our container expects onto our container.
+  m.PreScale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
+  layer->SetBaseTransform(m);
+
+  if (layer->AsRefLayer()) {
     layer->AsRefLayer()->SetEventRegionsOverride(mEventRegionsOverride);
   }
+
   return layer.forget();
 }
 
 void
 nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx)
 {
   DrawTarget* target = aCtx->GetDrawTarget();
   if (!target->IsRecording() || mTabId == 0) {
@@ -398,19 +306,19 @@ nsDisplayRemote::Paint(nsDisplayListBuil
 
 bool
 nsDisplayRemote::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
-  mOffset = mozilla::layout::GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
+  mOffset = GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
 
-  mozilla::LayoutDeviceRect rect = mozilla::LayoutDeviceRect::FromAppUnits(
+  LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
     mFrame->GetContentRectRelativeToSelf(), mFrame->PresContext()->AppUnitsPerDevPixel());
   rect += mOffset;
 
   aBuilder.PushIFrame(mozilla::wr::ToRoundedLayoutRect(rect),
       !BackfaceIsHidden(),
       mozilla::wr::AsPipelineId(GetRemoteLayersId()),
       /*ignoreMissingPipelines*/ true);
 
@@ -427,19 +335,19 @@ nsDisplayRemote::UpdateScrollData(mozill
     aLayerData->SetEventRegionsOverride(mEventRegionsOverride);
   }
   return true;
 }
 
 LayersId
 nsDisplayRemote::GetRemoteLayersId() const
 {
-  MOZ_ASSERT(GetRenderFrameParent());
-  return GetRenderFrameParent()->GetLayersId();
+  MOZ_ASSERT(GetRenderFrame());
+  return GetRenderFrame()->GetLayersId();
 }
 
-mozilla::layout::RenderFrameParent*
-nsDisplayRemote::GetRenderFrameParent() const
+mozilla::layout::RenderFrame*
+nsDisplayRemote::GetRenderFrame() const
 {
   return mFrame
-    ? static_cast<nsSubDocumentFrame*>(mFrame)->GetRenderFrameParent()
+    ? static_cast<nsSubDocumentFrame*>(mFrame)->GetRenderFrame()
     : nullptr;
 }
rename from layout/ipc/RenderFrameParent.h
rename to layout/ipc/RenderFrame.h
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrame.h
@@ -1,159 +1,105 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_layout_RenderFrameParent_h
-#define mozilla_layout_RenderFrameParent_h
+#ifndef mozilla_layout_RenderFrame_h
+#define mozilla_layout_RenderFrame_h
+
+#include "base/process.h"
 
 #include "mozilla/Attributes.h"
-#include <map>
 
 #include "mozilla/dom/ipc/IdType.h"
-#include "mozilla/layers/APZUtils.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/LayersTypes.h"
-#include "mozilla/layout/PRenderFrameParent.h"
 #include "nsDisplayList.h"
 
 class nsFrameLoader;
 class nsSubDocumentFrame;
 
 namespace mozilla {
 
-class InputEvent;
 
 namespace layers {
-class AsyncDragMetrics;
-class TargetConfig;
 struct TextureFactoryIdentifier;
-struct ScrollableLayerGuid;
 } // namespace layers
 
 namespace layout {
 
-class RenderFrameParent final : public PRenderFrameParent
+class RenderFrame final
 {
-  typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics;
-  typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::CompositorOptions CompositorOptions;
-  typedef mozilla::layers::ContainerLayer ContainerLayer;
-  typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::LayersId LayersId;
-  typedef mozilla::layers::TargetConfig TargetConfig;
-  typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::layers::TextureFactoryIdentifier TextureFactoryIdentifier;
-  typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
-  typedef mozilla::layers::TouchBehaviorFlags TouchBehaviorFlags;
-  typedef mozilla::layers::ZoomConstraints ZoomConstraints;
-  typedef ScrollableLayerGuid::ViewID ViewID;
-
 public:
 
+  RenderFrame();
+  virtual ~RenderFrame();
 
-  /**
-   * Select the desired scrolling behavior.  If ASYNC_PAN_ZOOM is
-   * chosen, then RenderFrameParent will watch input events and use
-   * them to asynchronously pan and zoom.
-   */
-  explicit RenderFrameParent(nsFrameLoader* aFrameLoader);
-  virtual ~RenderFrameParent();
-
-  bool Init(nsFrameLoader* aFrameLoader);
-  bool IsInitted();
+  bool Initialize(nsFrameLoader* aFrameLoader);
   void Destroy();
 
-
-  already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
-                                     nsIFrame* aFrame,
-                                     LayerManager* aManager,
-                                     nsDisplayItem* aItem,
-                                     const ContainerLayerParameters& aContainerParameters);
-
+  void EnsureLayersConnected(CompositorOptions* aCompositorOptions);
+  LayerManager* AttachLayerManager();
   void OwnerContentChanged(nsIContent* aContent);
 
-  bool HitTest(const nsRect& aRect);
-
-  void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier);
-
-  inline LayersId GetLayersId() const { return mLayersId; }
-  inline bool IsLayersConnected() const { return mLayersConnected; }
-  inline CompositorOptions GetCompositorOptions() const { return mCompositorOptions; }
-
-  void TakeFocusForClickFromTap();
-
-  void EnsureLayersConnected(CompositorOptions* aCompositorOptions);
+  nsFrameLoader* GetFrameLoader() const { return mFrameLoader; }
+  LayersId GetLayersId() const { return mLayersId; }
+  CompositorOptions GetCompositorOptions() const { return mCompositorOptions; }
 
-  LayerManager* AttachLayerManager();
+  void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier) const;
 
-  nsFrameLoader* FrameLoader() const
-  {
-    return mFrameLoader;
-  }
-
-protected:
-  void ActorDestroy(ActorDestroyReason why) override;
-
-  virtual mozilla::ipc::IPCResult RecvNotifyCompositorTransaction() override;
+  bool IsInitialized() const { return mInitialized; }
+  bool IsLayersConnected() const { return mLayersConnected; }
 
 private:
-  void TriggerRepaint();
-  void DispatchEventForPanZoomController(const InputEvent& aEvent);
-
+  base::ProcessId mTabProcessId;
   // When our child frame is pushing transactions directly to the
   // compositor, this is the ID of its layer tree in the compositor's
   // context.
   LayersId mLayersId;
-  // A flag that indicates whether or not the compositor knows about the
-  // layers id. In some cases this RenderFrameParent is not connected to the
-  // compositor and so this flag is false.
-  bool mLayersConnected;
   // The compositor options for this layers id. This is only meaningful if
   // the compositor actually knows about this layers id (i.e. when mLayersConnected
   // is true).
   CompositorOptions mCompositorOptions;
 
   RefPtr<nsFrameLoader> mFrameLoader;
   RefPtr<LayerManager> mLayerManager;
 
-  // True after Destroy() has been called, which is triggered
-  // originally by nsFrameLoader::Destroy().  After this point, we can
-  // no longer safely ask the frame loader to find its nearest layer
-  // manager, because it may have been disconnected from the DOM.
-  // It's still OK to *tell* the frame loader that we've painted after
-  // it's destroyed; it'll just ignore us, and we won't be able to
-  // find an nsIFrame to invalidate.  See ShadowLayersUpdated().
-  //
-  // Prefer the extra bit of state to null'ing out mFrameLoader in
-  // Destroy() so that less code needs to be special-cased for after
-  // Destroy().
-  //
-  // It's possible for mFrameLoader==null and
-  // mFrameLoaderDestroyed==false.
-  bool mFrameLoaderDestroyed;
-
-  bool mAsyncPanZoomEnabled;
-  bool mInitted;
+  bool mInitialized;
+  // A flag that indicates whether or not the compositor knows about the
+  // layers id. In some cases this RenderFrame is not connected to the
+  // compositor and so this flag is false.
+  bool mLayersConnected;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 /**
  * A DisplayRemote exists solely to graft a child process's shadow
- * layer tree (for a given RenderFrameParent) into its parent
+ * layer tree (for a given RenderFrame) into its parent
  * process's layer tree.
  */
 class nsDisplayRemote final : public nsDisplayItem
 {
-  typedef mozilla::layout::RenderFrameParent RenderFrameParent;
+  typedef mozilla::dom::TabId TabId;
+  typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+  typedef mozilla::layers::EventRegionsOverride EventRegionsOverride;
+  typedef mozilla::layers::Layer Layer;
+  typedef mozilla::layers::LayersId LayersId;
+  typedef mozilla::layers::RefLayer RefLayer;
+  typedef mozilla::layout::RenderFrame RenderFrame;
+  typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
+  typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
 
 public:
   nsDisplayRemote(nsDisplayListBuilder* aBuilder,
                   nsSubDocumentFrame* aFrame);
 
   bool HasDeletedFrame() const override;
 
   LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@@ -172,18 +118,17 @@ public:
                                mozilla::layers::WebRenderLayerManager* aManager,
                                nsDisplayListBuilder* aDisplayListBuilder) override;
   bool UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                         mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
 
   NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
 
 private:
-  mozilla::layers::LayersId GetRemoteLayersId() const;
-  RenderFrameParent* GetRenderFrameParent() const;
+  LayersId GetRemoteLayersId() const;
+  RenderFrame* GetRenderFrame() const;
 
-  mozilla::dom::TabId mTabId;
-  mozilla::LayoutDeviceIntPoint mOffset;
-  mozilla::layers::EventRegionsOverride mEventRegionsOverride;
+  TabId mTabId;
+  LayoutDeviceIntPoint mOffset;
+  EventRegionsOverride mEventRegionsOverride;
 };
 
-
-#endif  // mozilla_layout_RenderFrameParent_h
+#endif  // mozilla_layout_RenderFrame_h
deleted file mode 100644
--- a/layout/ipc/RenderFrameChild.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "RenderFrameChild.h"
-#include "mozilla/layers/LayerTransactionChild.h"
-
-using mozilla::layers::PLayerTransactionChild;
-using mozilla::layers::LayerTransactionChild;
-
-namespace mozilla {
-namespace layout {
-
-void
-RenderFrameChild::ActorDestroy(ActorDestroyReason why)
-{
-  mWasDestroyed = true;
-}
-
-void
-RenderFrameChild::Destroy()
-{
-  if (mWasDestroyed) {
-    return;
-  }
-
-  Send__delete__(this);
-  // WARNING: |this| is dead, hands off
-}
-
-} // namespace layout
-} // namespace mozilla
deleted file mode 100644
--- a/layout/ipc/RenderFrameChild.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_RenderFrameChild_h
-#define mozilla_dom_RenderFrameChild_h
-
-#include "mozilla/layout/PRenderFrameChild.h"
-
-namespace mozilla {
-namespace layout {
-
-class RenderFrameChild : public PRenderFrameChild
-{
-public:
-  RenderFrameChild() : mWasDestroyed(false) {}
-  virtual ~RenderFrameChild() {}
-
-  void ActorDestroy(ActorDestroyReason why) override;
-
-  void Destroy();
-
-private:
-  bool mWasDestroyed;
-};
-
-} // namespace layout
-} // namespace mozilla
-
-#endif  // mozilla_dom_RenderFrameChild_h
--- a/layout/ipc/moz.build
+++ b/layout/ipc/moz.build
@@ -3,34 +3,31 @@
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Web Painting')
 
 EXPORTS.mozilla.layout += [
-    'RenderFrameChild.h',
-    'RenderFrameParent.h',
+    'RenderFrame.h',
     'VsyncChild.h',
     'VsyncParent.h',
 ]
 
 UNIFIED_SOURCES += [
-    'RenderFrameChild.cpp',
-    'RenderFrameParent.cpp',
+    'RenderFrame.cpp',
 ]
 
 SOURCES += [
     'VsyncChild.cpp',
     'VsyncParent.cpp',
 ]
 
 IPDL_SOURCES = [
-    'PRenderFrame.ipdl',
     'PVsync.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -434,16 +434,23 @@ VARCACHE_PREF(
 // Enable content type normalization of XHR uploads via MIME Sniffing standard
 // Disabled for now in bz1499136
 VARCACHE_PREF(
   "dom.xhr.standard_content_type_normalization",
    dom_xhr_standard_content_type_normalization,
   RelaxedAtomicBool, false
 )
 
+// Block multiple window.open() per single event.
+VARCACHE_PREF(
+  "dom.block_multiple_popups",
+   dom_block_multiple_popups,
+  bool, true
+)
+
 //---------------------------------------------------------------------------
 // Clear-Site-Data prefs
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
   "dom.clearSiteData.enabled",
    dom_clearSiteData_enabled,
   bool, true
old mode 100644
new mode 100755
--- a/mozilla-config.h.in
+++ b/mozilla-config.h.in
@@ -40,11 +40,26 @@
 /*
  * Force-include sdkdecls.h for building the chromium sandbox code.
  *
  * CHROMIUM_SANDBOX_BUILD is defined in security/sandbox/moz.build.
  * Note that this include path relies on the LOCAL_INCLUDES in that file.
  */
 #if defined(CHROMIUM_SANDBOX_BUILD) && defined(XP_WIN)
 #include "base/win/sdkdecls.h"
+
+#ifdef __MINGW32__
+/*
+ * MinGW doesn't support __try / __except. There are a few mechanisms available
+ * to hack around it and pseudo-support it, but these are untested in Firefox.
+ * What is tested (and works) is replacing them with if(true) and else.
+ */
+#define __try if(true)
+#define __except(x) else
+#ifdef GetExceptionCode
+#undef GetExceptionCode
+#endif
+#define GetExceptionCode() 0
+
+#endif /* __MINGW32__ */
 #endif /* defined(CHROMIUM_SANDBOX_BUILD) && defined(XP_WIN) */
 
 #endif /* MOZILLA_CONFIG_H */
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium-shim/patches/with_update/mingw_disable_one_try.patch
@@ -0,0 +1,51 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1516389982 21600
+#      Fri Jan 19 13:26:22 2018 -0600
+# Node ID 3ca7306d73ebc1ce47ccdc62ee8cbb69a9bfbb2c
+# Parent  6aa6c7d894609140ccde2e9e50eba8c25a9caeb5
+Bug 1431803 Disable a specific __try block on MinGW r?bobowen
+
+This function is a technique to name a thread for debugging purposes,
+and it always throws an exception (and then continues). On MinGW
+we don't want it to throw an exception, so we do nothing.
+
+This means on MinGW we won't get nice thread naming during debugging,
+but we'll limp along.
+
+MozReview-Commit-ID: JRKY4wp7sdu
+
+diff --git a/security/sandbox/chromium/base/threading/platform_thread_win.cc b/security/sandbox/chromium/base/threading/platform_thread_win.cc
+--- a/security/sandbox/chromium/base/threading/platform_thread_win.cc
++++ b/security/sandbox/chromium/base/threading/platform_thread_win.cc
+@@ -32,27 +32,30 @@ typedef struct tagTHREADNAME_INFO {
+ } THREADNAME_INFO;
+ 
+ // The SetThreadDescription API was brought in version 1607 of Windows 10.
+ typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread,
+                                               PCWSTR lpThreadDescription);
+ 
+ // This function has try handling, so it is separated out of its caller.
+ void SetNameInternal(PlatformThreadId thread_id, const char* name) {
++  //This function is only used for debugging purposes, as you can find by its caller
++#ifndef __MINGW32__
+   THREADNAME_INFO info;
+   info.dwType = 0x1000;
+   info.szName = name;
+   info.dwThreadID = thread_id;
+   info.dwFlags = 0;
+ 
+   __try {
+     RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
+                    reinterpret_cast<DWORD_PTR*>(&info));
+   } __except(EXCEPTION_CONTINUE_EXECUTION) {
+   }
++#endif
+ }
+ 
+ struct ThreadParams {
+   PlatformThread::Delegate* delegate;
+   bool joinable;
+   ThreadPriority priority;
+ };
+ 
--- a/security/sandbox/chromium-shim/patches/with_update/patch_order.txt
+++ b/security/sandbox/chromium-shim/patches/with_update/patch_order.txt
@@ -12,9 +12,10 @@ fix_Wcomma_warning_in_time_cc.patch
 allow_read_only_all_paths_rule.patch
 revert_TargetNtSetInformationThread_change.patch
 mingw_base_win_get_caller.patch
 mingw_duplicate_instatinations.patch
 mingw_copy_s.patch
 mingw_operator_new.patch
 mingw_cast_getprocaddress.patch
 mingw_capitalization.patch
+mingw_disable_one_try.patch
 mingw_offsetof.patch
--- a/security/sandbox/chromium/base/threading/platform_thread_win.cc
+++ b/security/sandbox/chromium/base/threading/platform_thread_win.cc
@@ -32,27 +32,30 @@ typedef struct tagTHREADNAME_INFO {
 } THREADNAME_INFO;
 
 // The SetThreadDescription API was brought in version 1607 of Windows 10.
 typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread,
                                               PCWSTR lpThreadDescription);
 
 // This function has try handling, so it is separated out of its caller.
 void SetNameInternal(PlatformThreadId thread_id, const char* name) {
+  //This function is only used for debugging purposes, as you can find by its caller
+#ifndef __MINGW32__
   THREADNAME_INFO info;
   info.dwType = 0x1000;
   info.szName = name;
   info.dwThreadID = thread_id;
   info.dwFlags = 0;
 
   __try {
     RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
                    reinterpret_cast<DWORD_PTR*>(&info));
   } __except(EXCEPTION_CONTINUE_EXECUTION) {
   }
+#endif
 }
 
 struct ThreadParams {
   PlatformThread::Delegate* delegate;
   bool joinable;
   ThreadPriority priority;
 };
 
--- a/testing/mozbase/mozrunner/mozrunner/base/device.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/device.py
@@ -50,52 +50,45 @@ class DeviceRunner(BaseRunner):
         kwargs['process_args'] = process_args
         BaseRunner.__init__(self, **kwargs)
 
         device_args = device_args or {}
         self.device = device_class(**device_args)
 
     @property
     def command(self):
-        cmd = [self.app_ctx.adb]
-        if self.app_ctx.device_serial:
-            cmd.extend(['-s', self.app_ctx.device_serial])
-        cmd.append('shell')
-        for k, v in self._device_env.iteritems():
-            cmd.append('%s=%s' % (k, v))
-        cmd.append(self.app_ctx.remote_binary)
-        return cmd
+        # command built by mozdevice -- see start() below
+        return None
 
     def start(self, *args, **kwargs):
         if isinstance(self.device, BaseEmulator) and not self.device.connected:
             self.device.start()
         self.device.connect()
         self.device.setup_profile(self.profile)
 
-        # TODO: this doesn't work well when the device is running but dropped
-        # wifi for some reason. It would be good to probe the state of the device
-        # to see if we have the homescreen running, or something, before waiting here
-        self.device.wait_for_net()
-
-        if not self.device.wait_for_net():
-            raise Exception("Network did not come up when starting device")
-
-        pid = BaseRunner.start(self, *args, **kwargs)
+        app = self.app_ctx.remote_process
+        args = ["-no-remote", "-profile", self.app_ctx.remote_profile]
+        args.extend(self.cmdargs)
+        env = self._device_env
+        url = None
+        if 'geckoview' in app:
+            activity = "TestRunnerActivity"
+            self.app_ctx.device.launch_activity(app, activity, e10s=True, moz_env=env,
+                                                extra_args=args, url=url)
+        else:
+            self.app_ctx.device.launch_fennec(
+                app, moz_env=env, extra_args=args, url=url)
 
         timeout = 10  # seconds
         end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
         while not self.is_running() and datetime.datetime.now() < end_time:
             time.sleep(.1)
         if not self.is_running():
             print("timed out waiting for '%s' process to start" % self.app_ctx.remote_process)
 
-        if not self.device.wait_for_net():
-            raise Exception("Failed to get a network connection")
-        return pid
-
     def stop(self, sig=None):
         if not sig and self.is_running():
             self.app_ctx.stop_application()
 
         if self.is_running():
             timeout = 10
 
             self.app_ctx.device.pkill(self.app_ctx.remote_process, sig=sig)
@@ -179,25 +172,8 @@ class DeviceRunner(BaseRunner):
         self.device.cleanup()
 
 
 class FennecRunner(DeviceRunner):
 
     def __init__(self, cmdargs=None, **kwargs):
         super(FennecRunner, self).__init__(**kwargs)
         self.cmdargs = cmdargs or []
-
-    @property
-    def command(self):
-        cmd = [self.app_ctx.adb]
-        if self.app_ctx.device_serial:
-            cmd.extend(["-s", self.app_ctx.device_serial])
-        cmd.append("shell")
-        app = "%s/org.mozilla.gecko.BrowserApp" % self.app_ctx.remote_process
-        am_subcommand = ["am", "start", "-a", "android.activity.MAIN", "-n", app]
-        app_params = ["-no-remote", "-profile", self.app_ctx.remote_profile]
-        app_params.extend(self.cmdargs)
-        am_subcommand.extend(["--es", "args", "'%s'" % " ".join(app_params)])
-        # Append env variables in the form |--es env0 MOZ_CRASHREPORTER=1|
-        for (count, (k, v)) in enumerate(self._device_env.iteritems()):
-            am_subcommand.extend(["--es", "env%d" % count, "%s=%s" % (k, v)])
-        cmd.append("%s" % " ".join(am_subcommand))
-        return cmd
--- a/testing/profiles/unittest/user.js
+++ b/testing/profiles/unittest/user.js
@@ -102,16 +102,17 @@ user_pref("dom.forms.datetime.others", t
 // Enable Gamepad
 user_pref("dom.gamepad.enabled", true);
 user_pref("dom.gamepad.non_standard_events.enabled", true);
 user_pref("dom.ipc.reportProcessHangs", false); // process hang monitor
 // Don't forceably kill content processes after a timeout
 user_pref("dom.ipc.tabs.shutdownTimeoutSecs", 0);
 user_pref("dom.min_background_timeout_value", 1000);
 user_pref("dom.popup_maximum", -1);
+user_pref("dom.block_multiple_popups", false);
 user_pref("dom.presentation.testing.simulate-receiver", false);
 // Prevent connection to the push server for tests.
 user_pref("dom.push.connection.enabled", false);
 user_pref("dom.successive_dialog_time_limit", 0);
 // In the default configuration, we bypass XBL scopes (a security feature) for
 // domains whitelisted for remote XUL, so that intranet apps and such continue
 // to work without major rewrites. However, we also use the whitelist mechanism
 // to run our XBL tests in automation, in which case we really want to be testing
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-origin.sub.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-origin.sub.html.ini
@@ -1,23 +1,4 @@
 [createImageBitmap-origin.sub.html]
   prefs: [network.http.send_window_size:0]
-  [cross-origin HTMLImageElement]
-    expected: FAIL
-
-  [cross-origin SVGImageElement]
-    expected: FAIL
-
-  [cross-origin HTMLVideoElement]
-    expected: FAIL
-
-  [unclean HTMLCanvasElement]
-    expected: FAIL
-
-  [unclean ImageBitmap]
-    expected: FAIL
-
-  [redirected to cross-origin HTMLVideoElement]
-    expected: FAIL
-
   [redirected to same-origin HTMLVideoElement]
     expected: FAIL
-
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/fennec.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/fennec.py
@@ -208,29 +208,29 @@ class FennecBrowser(FirefoxBrowser):
                                            env=env,
                                            symbols_path=self.symbols_path,
                                            serial=self.device_serial,
                                            # TODO - choose appropriate log dir
                                            logdir=os.getcwd(),
                                            process_class=ProcessHandler,
                                            process_args={"processOutputLine": [self.on_output]})
 
-        self.logger.debug("Starting Fennec")
+        self.logger.debug("Starting %s" % self.package_name)
         # connect to a running emulator
         self.runner.device.connect()
 
         write_hosts_file(self.config, self.runner.device.device)
 
         self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
 
         self.runner.device.device.forward(
             local="tcp:{}".format(self.marionette_port),
             remote="tcp:{}".format(self.marionette_port))
 
-        self.logger.debug("Fennec Started")
+        self.logger.debug("%s Started" % self.package_name)
 
     def stop(self, force=False):
         if self.runner is not None:
             try:
                 if self.runner.device.connected:
                     if len(self.runner.device.device.list_forwards()) > 0:
                         self.runner.device.device.remove_forwards(
                             "tcp:{}".format(self.marionette_port))
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -222,17 +222,19 @@ class XPCShellTestThread(Thread):
         with open(test_file + ".log", "w") as f:
             f.write(stdout)
 
     def getReturnCode(self, proc):
         """
           Simple wrapper to get the return code for a given process.
           On a remote system we overload this to work with the remote process management.
         """
-        return proc.returncode
+        if proc is not None and hasattr(proc, "returncode"):
+            return proc.returncode
+        return -1
 
     def communicate(self, proc):
         """
           Simple wrapper to communicate with a process.
           On a remote system, this is overloaded to handle remote process communication.
         """
         # Processing of incremental output put here to
         # sidestep issues on remote platforms, where what we know
@@ -279,17 +281,20 @@ class XPCShellTestThread(Thread):
         self.log.info("%s | current directory: %r" % (name, testdir))
         # Show only those environment variables that are changed from
         # the ambient environment.
         changedEnv = (set("%s=%s" % i for i in self.env.iteritems())
                       - set("%s=%s" % i for i in os.environ.iteritems()))
         self.log.info("%s | environment: %s" % (name, list(changedEnv)))
 
     def killTimeout(self, proc):
-        mozcrash.kill_and_get_minidump(proc.pid, self.tempDir, utility_path=self.utility_path)
+        if proc is not None and hasattr(proc, "pid"):
+            mozcrash.kill_and_get_minidump(proc.pid, self.tempDir, utility_path=self.utility_path)
+        else:
+            self.log.info("not killing -- proc or pid unknown")
 
     def postCheck(self, proc):
         """Checks for a still-running test process, kills it and fails the test if found.
         We can sometimes get here before the process has terminated, which would
         cause removeDir() to fail - so check for the process and kill it if needed.
         """
         if proc and self.poll(proc) is None:
             if HAVE_PSUTIL:
--- a/toolkit/recordreplay/Lock.cpp
+++ b/toolkit/recordreplay/Lock.cpp
@@ -142,17 +142,17 @@ Lock::Find(void* aNativeLock)
       Lock* lock = iter->second;
       if (AreThreadEventsPassedThrough()) {
         return nullptr;
       }
       if (HasDivergedFromRecording()) {
         // When diverged from the recording, don't allow uses of locks that are
         // held by idling threads that have not diverged from the recording.
         // This will cause the process to deadlock, so rewind instead.
-        if (lock->mOwner && Thread::GetById(lock->mOwner)->IsIdle()) {
+        if (lock->mOwner && Thread::GetById(lock->mOwner)->ShouldIdle()) {
           ex.reset();
           EnsureNotDivergedFromRecording();
           Unreachable();
         }
         return nullptr;
       }
       return lock;
     }
--- a/toolkit/recordreplay/Thread.h
+++ b/toolkit/recordreplay/Thread.h
@@ -297,19 +297,19 @@ public:
 
   // After WaitForIdleThreads(), the main thread will call this to allow
   // other threads to resume execution.
   static void ResumeIdleThreads();
 
   // Allow a single thread to resume execution.
   static void ResumeSingleIdleThread(size_t aId);
 
-  // Return whether this thread is in the idle state entered after
+  // Return whether this thread will remain in the idle state entered after
   // WaitForIdleThreads.
-  bool IsIdle() { return mIdle; }
+  bool ShouldIdle() { return mShouldIdle; }
 };
 
 // This uses a stack pointer instead of TLS to make sure events are passed
 // through, for avoiding thorny reentrance issues.
 class AutoEnsurePassThroughThreadEventsUseStackPointer
 {
   Thread* mThread;
   bool mPassedThrough;
--- a/toolkit/recordreplay/ipc/Channel.cpp
+++ b/toolkit/recordreplay/ipc/Channel.cpp
@@ -146,16 +146,17 @@ Channel::ThreadMain(void* aChannelArg)
     channel->mHandler(msg);
   }
 }
 
 void
 Channel::SendMessage(const Message& aMsg)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread() ||
+                     aMsg.mType == MessageType::BeginFatalError ||
                      aMsg.mType == MessageType::FatalError ||
                      aMsg.mType == MessageType::MiddlemanCallRequest);
 
   // Block until the channel is initialized.
   if (!mInitialized) {
     MonitorAutoLock lock(mMonitor);
     while (!mInitialized) {
       mMonitor.Wait();
--- a/toolkit/recordreplay/ipc/Channel.h
+++ b/toolkit/recordreplay/ipc/Channel.h
@@ -104,18 +104,23 @@ namespace recordreplay {
   /* Messages sent from the child process to the middleman. */ \
                                                                \
   /* Sent in response to a FlushRecording, telling the middleman that the flush */ \
   /* has finished. */                                          \
   _Macro(RecordingFlushed)                                     \
                                                                \
   /* A critical error occurred and execution cannot continue. The child will */ \
   /* stop executing after sending this message and will wait to be terminated. */ \
+  /* A minidump for the child has been generated. */           \
   _Macro(FatalError)                                           \
                                                                \
+  /* Sent when a fatal error has occurred, but before the minidump has been */ \
+  /* generated. */                                             \
+  _Macro(BeginFatalError)                                      \
+                                                               \
   /* The child's graphics were repainted. */                   \
   _Macro(Paint)                                                \
                                                                \
   /* Notify the middleman that a checkpoint or breakpoint was hit. */ \
   /* The child will pause after sending these messages. */     \
   _Macro(HitCheckpoint)                                        \
   _Macro(HitBreakpoint)                                        \
                                                                \
@@ -366,16 +371,18 @@ struct FatalErrorMessage : public Messag
 {
   explicit FatalErrorMessage(uint32_t aSize)
     : Message(MessageType::FatalError, aSize)
   {}
 
   const char* Error() const { return Data<FatalErrorMessage, const char>(); }
 };
 
+typedef EmptyMessage<MessageType::BeginFatalError> BeginFatalErrorMessage;
+
 // The format for graphics data which will be sent to the middleman process.
 // This needs to match the format expected for canvas image data, to avoid
 // transforming the data before rendering it in the middleman process.
 static const gfx::SurfaceFormat gSurfaceFormat = gfx::SurfaceFormat::R8G8B8X8;
 
 struct PaintMessage : public Message
 {
   // Checkpoint whose state is being painted.
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp
+++ b/toolkit/recordreplay/ipc/ChildIPC.cpp
@@ -103,18 +103,19 @@ ChannelMessageHandler(Message* aMsg)
     // processes. When sent to a recording process (which the middleman manages
     // directly) they signal that a clean shutdown is needed, while when sent
     // to a replaying process (which the UI process manages) they signal that
     // the process should crash, since it seems to be hanged.
     if (IsRecording()) {
       PrintSpew("Terminate message received, exiting...\n");
       _exit(0);
     } else {
-      MOZ_CRASH("Hanged replaying process");
+      ReportFatalError(Nothing(), "Hung replaying process");
     }
+    break;
   }
   case MessageType::SetIsActive: {
     const SetIsActiveMessage& nmsg = (const SetIsActiveMessage&) *aMsg;
     PauseMainThreadAndInvokeCallback([=]() { SetIsActiveChild(nmsg.mActive); });
     break;
   }
   case MessageType::SetAllowIntentionalCrashes: {
     const SetAllowIntentionalCrashesMessage& nmsg = (const SetAllowIntentionalCrashesMessage&) *aMsg;
@@ -345,16 +346,20 @@ CreateCheckpoint()
   if (!HasDivergedFromRecording()) {
     NewCheckpoint(/* aTemporary = */ false);
   }
 }
 
 void
 ReportFatalError(const Maybe<MinidumpInfo>& aMinidump, const char* aFormat, ...)
 {
+  // Notify the middleman that we are crashing and are going to try to write a
+  // minidump.
+  gChannel->SendMessage(BeginFatalErrorMessage());
+
   // Unprotect any memory which might be written while producing the minidump.
   UnrecoverableSnapshotFailure();
 
   AutoEnsurePassThroughThreadEvents pt;
 
 #ifdef MOZ_CRASHREPORTER
   MinidumpInfo info = aMinidump.isSome()
                       ? aMinidump.ref()
--- a/toolkit/recordreplay/ipc/ChildProcess.cpp
+++ b/toolkit/recordreplay/ipc/ChildProcess.cpp
@@ -35,16 +35,18 @@ ChildProcessInfo::ChildProcessInfo(Uniqu
   , mRecording(aRecordingProcessData.isSome())
   , mRecoveryStage(RecoveryStage::None)
   , mPaused(false)
   , mPausedMessage(nullptr)
   , mLastCheckpoint(CheckpointId::Invalid)
   , mNumRecoveredMessages(0)
   , mRole(std::move(aRole))
   , mPauseNeeded(false)
+  , mHasBegunFatalError(false)
+  , mHasFatalError(false)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   static bool gFirst = false;
   if (!gFirst) {
     gFirst = true;
     gChildrenAreDebugging = !!getenv("WAIT_AT_START");
   }
@@ -194,17 +196,21 @@ ChildProcessInfo::OnIncomingMessage(size
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   // Ignore messages from channels for subprocesses we terminated already.
   if (aChannelId != mChannel->GetId()) {
     return;
   }
 
   // Always handle fatal errors in the same way.
-  if (aMsg.mType == MessageType::FatalError) {
+  if (aMsg.mType == MessageType::BeginFatalError) {
+    mHasBegunFatalError = true;
+    return;
+  } else if (aMsg.mType == MessageType::FatalError) {
+    mHasFatalError = true;
     const FatalErrorMessage& nmsg = static_cast<const FatalErrorMessage&>(aMsg);
     OnCrash(nmsg.Error());
     return;
   }
 
   mLastMessageTime = TimeStamp::Now();
 
   if (IsRecovering()) {
@@ -522,22 +528,33 @@ ChildProcessInfo::LaunchSubprocess(const
   SendMessage(*gIntroductionMessage);
 }
 
 void
 ChildProcessInfo::OnCrash(const char* aWhy)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
-  // If a child process crashes or hangs then annotate the crash report and
-  // shut down cleanly so that we don't mask the report with our own crash.
-  // We want the crash to happen quickly so the user doesn't get a hanged tab.
+  // If a child process crashes or hangs then annotate the crash report.
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::RecordReplayError,
                                      nsAutoCString(aWhy));
-  Shutdown();
+
+  // If we received a FatalError message then the child generated a minidump.
+  // Shut down cleanly so that we don't mask the report with our own crash.
+  if (mHasFatalError) {
+    Shutdown();
+  }
+
+  // Indicate when we crash if the child tried to send us a fatal error message
+  // but had a problem either unprotecting system memory or generating the
+  // minidump.
+  MOZ_RELEASE_ASSERT(!mHasBegunFatalError);
+
+  // The child crashed without producing a minidump, produce one ourselves.
+  MOZ_CRASH("Unexpected child crash");
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Handling Channel Messages
 ///////////////////////////////////////////////////////////////////////////////
 
 // When messages are received from child processes, we want their handler to
 // execute on the main thread. The main thread might be blocked in WaitUntil,
@@ -608,17 +625,17 @@ ChildProcessInfo::WaitUntil(const std::f
             // wait another HangSeconds before hitting the restart case below.
             // Use SendMessageRaw to avoid problems if we are recovering.
             CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::RecordReplayHang,
                                                true);
             SendMessageRaw(TerminateMessage());
             sentTerminateMessage = true;
           } else {
             // The child is still non-responsive after sending the terminate
-            // message, fail without producing a minidump.
+            // message.
             OnCrash("Child process non-responsive");
           }
         }
         gMonitor->WaitUntil(deadline);
       }
     }
   }
 }
--- a/toolkit/recordreplay/ipc/ParentForwarding.cpp
+++ b/toolkit/recordreplay/ipc/ParentForwarding.cpp
@@ -33,17 +33,16 @@ HandleMessageInMiddleman(ipc::Side aSide
       type == dom::PContent::Msg_PBrowserConstructor__ID ||
       type == dom::PContent::Msg_RegisterChrome__ID ||
       type == dom::PContent::Msg_SetXPCOMProcessAttributes__ID ||
       type == dom::PContent::Msg_UpdateSharedData__ID ||
       type == dom::PContent::Msg_SetProcessSandbox__ID ||
       // Graphics messages that affect both processes.
       type == dom::PBrowser::Msg_InitRendering__ID ||
       type == dom::PBrowser::Msg_SetDocShellIsActive__ID ||
-      type == dom::PBrowser::Msg_PRenderFrameConstructor__ID ||
       type == dom::PBrowser::Msg_RenderLayers__ID ||
       type == dom::PBrowser::Msg_UpdateDimensions__ID ||
       // These messages perform some graphics related initialization.
       type == dom::PBrowser::Msg_LoadURL__ID ||
       type == dom::PBrowser::Msg_Show__ID ||
       // May be loading devtools code that runs in the middleman process.
       type == dom::PBrowser::Msg_LoadRemoteScript__ID ||
       // May be sending a message for receipt by devtools code.
--- a/toolkit/recordreplay/ipc/ParentGraphics.cpp
+++ b/toolkit/recordreplay/ipc/ParentGraphics.cpp
@@ -196,33 +196,16 @@ UpdateGraphicsInUIProcess(const PaintMes
 
   // Call into the graphics module to update the canvas it manages.
   RootedValue rval(cx);
   if (!JS_CallFunctionName(cx, *gGraphicsSandbox, "UpdateCanvas", args, &rval)) {
     MOZ_CRASH("UpdateGraphicsInUIProcess");
   }
 }
 
-void
-UpdateGraphicsOverlay()
-{
-  if (!gLastPaintWidth || !gLastPaintHeight) {
-    return;
-  }
-
-  AutoSafeJSContext cx;
-  JSAutoRealm ar(cx, *gGraphicsSandbox);
-
-  RootedValue rval(cx);
-  if (!JS_CallFunctionName(cx, *gGraphicsSandbox, "UpdateOverlay",
-                           JS::HandleValueArray::empty(), &rval)) {
-    MOZ_CRASH("UpdateGraphicsOverlay");
-  }
-}
-
 static void
 MaybeTriggerExplicitPaint()
 {
   if (gLastExplicitPaint && gLastExplicitPaint->mCheckpointId == gLastCheckpoint) {
     UpdateGraphicsInUIProcess(gLastExplicitPaint.get());
   }
 }
 
--- a/toolkit/recordreplay/ipc/ParentIPC.cpp
+++ b/toolkit/recordreplay/ipc/ParentIPC.cpp
@@ -606,22 +606,16 @@ SwitchActiveChild(ChildProcessInfo* aChi
   }
   aChild->SetRole(MakeUnique<ChildRoleActive>());
   if (oldActiveChild->IsRecording()) {
     oldActiveChild->SetRole(MakeUnique<ChildRoleInert>());
   } else {
     oldActiveChild->RecoverToCheckpoint(oldActiveChild->MostRecentSavedCheckpoint());
     oldActiveChild->SetRole(MakeUnique<ChildRoleStandby>());
   }
-
-  // The graphics overlay is affected when we switch between recording and
-  // replaying children.
-  if (aChild->IsRecording() != oldActiveChild->IsRecording()) {
-    UpdateGraphicsOverlay();
-  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Preferences
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool gPreferencesLoaded;
 static bool gRewindingEnabled;
@@ -1182,20 +1176,16 @@ ResumeBeforeWaitingForIPDLReply()
 }
 
 static void
 RecvHitCheckpoint(const HitCheckpointMessage& aMsg)
 {
   UpdateCheckpointTimes(aMsg);
   MaybeUpdateGraphicsAtCheckpoint(aMsg.mCheckpointId);
 
-  if (!gActiveChild->IsRecording()) {
-    UpdateGraphicsOverlay();
-  }
-
   // Resume either forwards or backwards. Break the resume off into a separate
   // runnable, to avoid starving any code already on the stack and waiting for
   // the process to pause. Immediately resume if the main thread is blocked.
   if (MainThreadIsWaitingForIPDLReply()) {
     MOZ_RELEASE_ASSERT(gChildExecuteForward);
     Resume(true);
   } else if (!gResumeForwardOrBackward) {
     gResumeForwardOrBackward = true;
--- a/toolkit/recordreplay/ipc/ParentInternal.h
+++ b/toolkit/recordreplay/ipc/ParentInternal.h
@@ -89,19 +89,16 @@ extern void* gGraphicsMemory;
 void InitializeGraphicsMemory();
 void SendGraphicsMemoryToChild();
 
 // Update the graphics painted in the UI process, per painting data received
 // from a child process, or null if a repaint was triggered and failed due to
 // an unhandled recording divergence.
 void UpdateGraphicsInUIProcess(const PaintMessage* aMsg);
 
-// Update the overlay shown over the tab's graphics.
-void UpdateGraphicsOverlay();
-
 // If necessary, update graphics after the active child sends a paint message
 // or reaches a checkpoint.
 void MaybeUpdateGraphicsAtPaint(const PaintMessage& aMsg);
 void MaybeUpdateGraphicsAtCheckpoint(size_t aCheckpointId);
 
 // ID for the mach message sent from a child process to the middleman to
 // request a port for the graphics shmem.
 static const int32_t GraphicsHandshakeMessageId = 42;
@@ -269,16 +266,21 @@ class ChildProcessInfo
   InfallibleVector<size_t> mShouldSaveCheckpoints;
 
   // Sorted major checkpoints for this process. See ParentIPC.cpp.
   InfallibleVector<size_t> mMajorCheckpoints;
 
   // Whether we need this child to pause while the recording is updated.
   bool mPauseNeeded;
 
+  // Flags for whether we have received messages from the child indicating it
+  // is crashing.
+  bool mHasBegunFatalError;
+  bool mHasFatalError;
+
   void OnIncomingMessage(size_t aChannelId, const Message& aMsg);
   void OnIncomingRecoveryMessage(const Message& aMsg);
   void SendNextRecoveryMessage();
   void SendMessageRaw(const Message& aMsg);
 
   static void MaybeProcessPendingMessageRunnable();
   void ReceiveChildMessageOnMainThread(size_t aChannelId, Message* aMsg);
 
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2753,19 +2753,22 @@ public:
       }
       aObject.mParticipant->DeleteCycleCollectable(aObject.mPointer);
     }
   }
 
   bool
   Visit(nsPurpleBuffer& aBuffer, nsPurpleBufferEntry* aEntry)
   {
-    // Ignore any slice budget we have when recording/replaying, as it behaves
-    // non-deterministically.
-    if (mBudget && !recordreplay::IsRecordingOrReplaying()) {
+    // The cycle collector does not collect anything when recording/replaying.
+    if (recordreplay::IsRecordingOrReplaying()) {
+      return true;
+    }
+
+    if (mBudget) {
       if (mBudget->isOverBudget()) {
         return false;
       }
       mBudget->step();
     }
 
     MOZ_ASSERT(aEntry->mObject, "Null object in purple buffer");
     if (!aEntry->mRefCnt->get()) {