Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 26 Sep 2017 15:54:51 -0700
changeset 670859 b7d8ae4a03c62e549b9d82595b1d1964f0af70cd
parent 670812 7d15bc419c6cd7e9f3b4d41370c3b0e5990c8d1b (current diff)
parent 670787 fa27d9bd71e6cc46914185252047e2171460bed2 (diff)
child 670875 70158e4e215d784d1391db5e517b18727f4b3683
child 670888 d5e14a3beda6bae75aa1bcc1ad6dd1bb6f6f3e3f
child 671748 1be28f4113715723d42967b3c73114777f7e8ff6
push id81742
push userbmo:ralin@mozilla.com
push dateWed, 27 Sep 2017 00:28:20 +0000
reviewersmerge
milestone58.0a1
Merge inbound to m-c a=merge MozReview-Commit-ID: 6viJ4wRxLa8
devtools/client/inspector/inspector.js
dom/interfaces/html/nsIDOMHTMLAnchorElement.idl
js/xpconnect/wrappers/XrayWrapper.cpp
testing/web-platform/meta/custom-elements/reactions/HTMLOptionsCollection.html.ini
testing/web-platform/meta/custom-elements/reactions/HTMLSelectElement.html.ini
testing/web-platform/meta/custom-elements/reactions/HTMLTitleElement.html.ini
testing/web-platform/meta/custom-elements/reactions/Selection.html.ini
testing/web-platform/meta/custom-elements/upgrading/upgrading-enqueue-reactions.html.ini
toolkit/mozapps/downloads/DownloadPaths.jsm
toolkit/mozapps/downloads/tests/unit/test_DownloadPaths.js
xpcom/threads/Scheduler.h
xpcom/threads/nsThreadUtils.cpp
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -308,34 +308,22 @@ nsAccessibilityService::ListenersChanged
     nsCOMPtr<nsIEventListenerChange> change = do_QueryElementAt(aEventChanges, i);
 
     nsCOMPtr<nsIDOMEventTarget> target;
     change->GetTarget(getter_AddRefs(target));
     nsCOMPtr<nsIContent> node(do_QueryInterface(target));
     if (!node || !node->IsHTMLElement()) {
       continue;
     }
-    nsCOMPtr<nsIArray> listenerNames;
-    change->GetChangedListenerNames(getter_AddRefs(listenerNames));
 
     uint32_t changeCount;
-    rv = listenerNames->GetLength(&changeCount);
+    change->GetCountOfEventListenerChangesAffectingAccessibility(&changeCount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     for (uint32_t i = 0 ; i < changeCount ; i++) {
-      nsCOMPtr<nsIAtom> listenerName = do_QueryElementAt(listenerNames, i);
-
-      // We are only interested in event listener changes which may
-      // make an element accessible or inaccessible.
-      if (listenerName != nsGkAtoms::onclick &&
-          listenerName != nsGkAtoms::onmousedown &&
-          listenerName != nsGkAtoms::onmouseup) {
-        continue;
-      }
-
       nsIDocument* ownerDoc = node->OwnerDoc();
       DocAccessible* document = GetExistingDocAccessible(ownerDoc);
 
       // Create an accessible for a inaccessible element having click event
       // handler.
       if (document && !document->HasAccessible(node) &&
           nsCoreUtils::HasClickListener(node)) {
         nsIContent* parentEl = node->GetFlattenedTreeParent();
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -844,16 +844,19 @@ function makePreview(row) {
 
     var isProtocolAllowed = checkProtocol(gImageView.data[row]);
 
     var newImage = new Image;
     newImage.id = "thepreviewimage";
     var physWidth = 0, physHeight = 0;
     var width = 0, height = 0;
 
+    let serial = Components.classes["@mozilla.org/network/serialization-helper;1"]
+                           .getService(Components.interfaces.nsISerializationHelper);
+    let loadingPrincipalStr = serial.serializeToString(gDocInfo.principal);
     if ((item.HTMLLinkElement || item.HTMLInputElement ||
          item.HTMLImageElement || item.SVGImageElement ||
          (item.HTMLObjectElement && mimeType && mimeType.startsWith("image/")) ||
          isBG) && isProtocolAllowed) {
       // We need to wait for the image to finish loading before using width & height
       newImage.addEventListener("loadend", function() {
         physWidth = newImage.width || 0;
         physHeight = newImage.height || 0;
@@ -902,32 +905,35 @@ function makePreview(row) {
             imageSize = gBundle.getFormattedString("mediaDimensions",
                                                    [formatNumber(width),
                                                     formatNumber(height)]);
           }
         }
         setItemValue("imagedimensiontext", imageSize);
       }, {once: true});
 
+      newImage.setAttribute("loadingprincipal", loadingPrincipalStr);
       newImage.setAttribute("src", url);
     } else {
       // Handle the case where newImage is not used for width & height
       if (item.HTMLVideoElement && isProtocolAllowed) {
         newImage = document.createElementNS("http://www.w3.org/1999/xhtml", "video");
         newImage.id = "thepreviewimage";
+        newImage.setAttribute("loadingprincipal", loadingPrincipalStr);
         newImage.src = url;
         newImage.controls = true;
         width = physWidth = item.videoWidth;
         height = physHeight = item.videoHeight;
 
         document.getElementById("theimagecontainer").collapsed = false;
         document.getElementById("brokenimagecontainer").collapsed = true;
       } else if (item.HTMLAudioElement && isProtocolAllowed) {
         newImage = new Audio;
         newImage.id = "thepreviewimage";
+        newImage.setAttribute("loadingprincipal", loadingPrincipalStr);
         newImage.src = url;
         newImage.controls = true;
         isAudio = true;
 
         document.getElementById("theimagecontainer").collapsed = false;
         document.getElementById("brokenimagecontainer").collapsed = true;
       } else {
         // fallback image for protocols not allowed (e.g., javascript:)
--- a/browser/base/content/test/pageinfo/browser.ini
+++ b/browser/base/content/test/pageinfo/browser.ini
@@ -1,12 +1,18 @@
 [DEFAULT]
 
 [browser_pageInfo.js]
 support-files =
   ../general/feed_tab.html
+[browser_pageinfo_firstPartyIsolation.js]
+support-files =
+  image.html
+  ../general/audio.ogg
+  ../general/moz.png
+  ../general/video.ogg
 [browser_pageinfo_images.js]
 [browser_pageinfo_image_info.js]
 skip-if = (os == 'linux' && e10s) # bug 1161699
 [browser_pageinfo_svg_image.js]
 support-files =
   svg_image.html
   ../general/title_test.svg
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js
@@ -0,0 +1,89 @@
+const {classes: Cc, interfaces: Ci, manager: Cm} = Components;
+
+function waitForEvent(elem, event) {
+  return new Promise(resolve => {
+    elem.addEventListener(event, resolve, {capture: true, once: true});
+  });
+}
+
+function testFirstPartyDomain(pageInfo) {
+  return new Promise(resolve => {
+    const EXPECTED_DOMAIN = "example.com";
+    info("pageInfo load");
+    pageInfo.onFinished.push(async function() {
+      info("pageInfo onfinished");
+      let tree = pageInfo.document.getElementById("imagetree");
+      Assert.ok(!!tree, "should have imagetree element");
+
+      // i=0: <img>
+      // i=1: <video>
+      // i=2: <audio>
+      for (let i = 0; i < 3; i++) {
+        info("imagetree select " + i);
+        tree.view.selection.select(i);
+        tree.treeBoxObject.ensureRowIsVisible(i);
+        tree.focus();
+
+        let preview = pageInfo.document.getElementById("thepreviewimage");
+        info("preview.src=" + preview.src);
+
+        // For <img>, we will query imgIRequest.imagePrincipal later, so we wait
+        // for loadend event. For <audio> and <video>, so far we only can get
+        // the loadingprincipal attribute on the node, so we simply wait for
+        // loadstart.
+        if (i == 0) {
+          await waitForEvent(preview, "loadend");
+        } else {
+          await waitForEvent(preview, "loadstart");
+        }
+
+        info("preview load " + i);
+
+        // Originally thepreviewimage is loaded with SystemPrincipal, therefore
+        // it won't have origin attributes, now we've changed to loadingPrincipal
+        // to the content in bug 1376971, it should have firstPartyDomain set.
+        if (i == 0) {
+          let req = preview.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
+          Assert.equal(req.imagePrincipal.originAttributes.firstPartyDomain, EXPECTED_DOMAIN,
+                       "imagePrincipal should have firstPartyDomain set to " + EXPECTED_DOMAIN);
+        }
+
+        // Check the node has the attribute 'loadingprincipal'.
+        let serial = Components.classes["@mozilla.org/network/serialization-helper;1"]
+                               .getService(Components.interfaces.nsISerializationHelper);
+        let loadingPrincipalStr = preview.getAttribute("loadingprincipal");
+        let loadingPrincipal = serial.deserializeObject(loadingPrincipalStr);
+        Assert.equal(loadingPrincipal.originAttributes.firstPartyDomain, EXPECTED_DOMAIN,
+                     "loadingPrincipal should have firstPartyDomain set to " + EXPECTED_DOMAIN);
+
+      }
+
+      resolve();
+    });
+  });
+}
+
+async function test() {
+  waitForExplicitFinish();
+
+  Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref("privacy.firstparty.isolate");
+  });
+
+  gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
+  content.location = "https://example.com/browser/browser/base/content/test/pageinfo/image.html";
+  await waitForEvent(gBrowser.selectedBrowser, "load");
+
+  let spec = gBrowser.selectedBrowser.currentURI.spec;
+  let pageInfo = BrowserPageInfo(spec, "mediaTab");
+  info("waitForEvent pageInfo");
+  await waitForEvent(pageInfo, "load");
+
+  info("calling testFirstPartyDomain");
+  await testFirstPartyDomain(pageInfo);
+
+  pageInfo.close();
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/pageinfo/image.html
@@ -0,0 +1,5 @@
+<html>
+  <img src='moz.png' height=100 width=150 id='test-image'>
+  <video src='video.ogg' id='test-video'></video>
+  <audio src='audio.ogg' id='test-audio'></audio>
+</html>
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -48,17 +48,18 @@ BasePrincipal::GetOrigin(nsACString& aOr
   aOrigin.Append(suffix);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetOriginNoSuffix(nsACString& aOrigin)
 {
   MOZ_ASSERT(mInitialized);
-  return mOriginNoSuffix->ToUTF8String(aOrigin);
+  mOriginNoSuffix->ToUTF8String(aOrigin);
+  return NS_OK;
 }
 
 bool
 BasePrincipal::Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration)
 {
   MOZ_ASSERT(aOther);
   MOZ_ASSERT_IF(Kind() == eCodebasePrincipal, mOriginSuffix);
 
@@ -288,17 +289,18 @@ BasePrincipal::GetOriginAttributes(JSCon
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetOriginSuffix(nsACString& aOriginAttributes)
 {
   MOZ_ASSERT(mOriginSuffix);
-  return mOriginSuffix->ToUTF8String(aOriginAttributes);
+  mOriginSuffix->ToUTF8String(aOriginAttributes);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetAppId(uint32_t* aAppId)
 {
   if (AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     MOZ_ASSERT(false);
     *aAppId = nsIScriptSecurityManager::NO_APP_ID;
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -448,23 +448,22 @@ Toolbox.prototype = {
       this.textBoxContextMenuPopup =
         this.doc.getElementById("toolbox-textbox-context-popup");
       this.textBoxContextMenuPopup.addEventListener("popupshowing",
         this._updateTextBoxMenuItems, true);
       this.doc.addEventListener("contextmenu", (e) => {
         if (e.originalTarget.closest("input[type=text]") ||
             e.originalTarget.closest("input[type=search]") ||
             e.originalTarget.closest("input:not([type])") ||
-            e.originalTarget.closest("textarea")
-        ) {
+            e.originalTarget.closest("textarea")) {
           e.stopPropagation();
           e.preventDefault();
           this.openTextBoxContextMenu(e.screenX, e.screenY);
         }
-      }, true);
+      });
 
       this.shortcuts = new KeyShortcuts({
         window: this.doc.defaultView
       });
       // Get the DOM element to mount the ToolboxController to.
       this._componentMount = this.doc.getElementById("toolbox-toolbar-mount");
 
       this._mountReactComponent();
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -1119,17 +1119,25 @@ Inspector.prototype = {
     let content = clipboardHelper.getText();
     if (content && content.trim().length > 0) {
       return content;
     }
     return null;
   },
 
   _onContextMenu: function (e) {
+    if (e.originalTarget.closest("input[type=text]") ||
+        e.originalTarget.closest("input:not([type])") ||
+        e.originalTarget.closest("textarea")) {
+      return;
+    }
+
+    e.stopPropagation();
     e.preventDefault();
+
     this._openMenu({
       screenX: e.screenX,
       screenY: e.screenY,
       target: e.target,
     });
   },
 
   _openMenu: function ({ target, screenX = 0, screenY = 0 } = { }) {
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -392,16 +392,25 @@ CssRuleView.prototype = {
     }
     return node.offsetParent._ruleEditor;
   },
 
   /**
    * Context menu handler.
    */
   _onContextMenu: function (event) {
+    if (event.originalTarget.closest("input[type=text]") ||
+        event.originalTarget.closest("input:not([type])") ||
+        event.originalTarget.closest("textarea")) {
+      return;
+    }
+
+    event.stopPropagation();
+    event.preventDefault();
+
     this._contextmenu.show(event);
   },
 
   /**
    * Callback for copy event. Copy the selected text.
    *
    * @param {Event} event
    *        copy event object.
--- a/devtools/client/shared/test/browser_html_tooltip_xul-wrapper.js
+++ b/devtools/client/shared/test/browser_html_tooltip_xul-wrapper.js
@@ -21,20 +21,29 @@ const TOOLTIP_HEIGHT = 160;
 const TOOLTIP_WIDTH = 200;
 
 add_task(function* () {
   // Force the toolbox to be 200px high;
   yield pushPref("devtools.toolbox.footer.height", 200);
 
   let [, win, doc] = yield createHost("bottom", TEST_URI);
 
-  info("Resizing window to have some space below the window.");
+  info("Resize and move the window to have space below.");
   let originalWidth = win.top.outerWidth;
   let originalHeight = win.top.outerHeight;
-  win.top.resizeBy(0, -100);
+  win.top.resizeBy(-100, -200);
+  let originalTop = win.top.screenTop;
+  let originalLeft = win.top.screenLeft;
+  win.top.moveTo(100, 100);
+
+  registerCleanupFunction(() => {
+    info("Restore original window dimensions and position.");
+    win.top.resizeTo(originalWidth, originalHeight);
+    win.top.moveTo(originalTop, originalLeft);
+  });
 
   info("Create HTML tooltip");
   let tooltip = new HTMLTooltip(doc, {useXulWrapper: true});
   let div = doc.createElementNS(HTML_NS, "div");
   div.style.height = "200px";
   div.style.background = "red";
   tooltip.setContent(div, {width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT});
 
@@ -50,19 +59,16 @@ add_task(function* () {
   info("Display the tooltip below box1.");
   yield showTooltip(tooltip, box1, {position: "bottom"});
   checkTooltip(tooltip, "bottom", TOOLTIP_HEIGHT);
   yield hideTooltip(tooltip);
 
   is(tooltip.isVisible(), false, "Tooltip is not visible");
 
   tooltip.destroy();
-
-  info("Restore original window dimensions.");
-  win.top.resizeTo(originalWidth, originalHeight);
 });
 
 function checkTooltip(tooltip, position, height) {
   is(tooltip.position, position, "Actual tooltip position is " + position);
   let rect = tooltip.container.getBoundingClientRect();
   is(rect.height, height, "Actual tooltip height is " + height);
   // Testing the actual left/top offsets is not relevant here as it is handled by the XUL
   // panel.
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -351,22 +351,23 @@ Editor.prototype = {
         deltaX *= cm.getWrapperElement().clientWidth;
         deltaY *= cm.getWrapperElement().clientHeight;
       }
 
       cm.getScrollerElement().scrollBy(deltaX, deltaY);
     });
 
     cm.getWrapperElement().addEventListener("contextmenu", ev => {
-      ev.preventDefault();
-
       if (!this.config.contextMenu) {
         return;
       }
 
+      ev.stopPropagation();
+      ev.preventDefault();
+
       let popup = this.config.contextMenu;
       if (typeof popup == "string") {
         popup = doc.getElementById(this.config.contextMenu);
       }
 
       this.emit("popupOpen", ev, popup);
       popup.openPopupAtScreen(ev.screenX, ev.screenY, true);
     });
--- a/devtools/client/themes/markup.css
+++ b/devtools/client/themes/markup.css
@@ -1,21 +1,17 @@
 /* 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/. */
 
 :root {
-  --markup-hidden-attr-color: var(--theme-comment);
-  --markup-hidden-tag-color: #A1A1A4;
   --markup-outline: var(--theme-splitter-color);
 }
 
 .theme-dark:root {
-  --markup-hidden-attr-color: var(--theme-body-color-inactive);
-  --markup-hidden-tag-color: var(--theme-content-color1);
   --markup-outline: var(--theme-selection-background);
 }
 
 * {
   padding: 0;
   margin: 0;
 }
 
@@ -331,26 +327,16 @@ ul.children + .tag-line::before {
   width: .8em;
   height: .8em;
   margin-top: .3em;
   left: 1px;
   position: absolute;
   z-index: 1;
 }
 
-
-.not-displayed .attr-name,
-.not-displayed .attr-value {
-  color: var(--markup-hidden-attr-color);
-}
-
-.not-displayed .theme-fg-color3 {
-  color: var(--markup-hidden-tag-color);
-}
-
 /* Firebug Theme */
 
 .theme-firebug .theme-fg-color3 {
   color: var(--theme-graphs-full-blue);
   font-weight: normal;
 }
 
 .theme-firebug .open,
@@ -362,22 +348,16 @@ ul.children + .tag-line::before {
 .theme-firebug .attr-value.theme-fg-color6 {
   color: var(--theme-highlight-red);
 }
 
 .theme-firebug .markupview-events {
   font-size: var(--theme-toolbar-font-size);
 }
 
-/* In case a node isn't displayed in the page, we fade the syntax highlighting */
-.theme-firebug .not-displayed .open,
-.theme-firebug .not-displayed .close {
-  opacity: .5;
-}
-
 /* Selected nodes in the tree should have light selected text.
    theme-selected doesn't work in this case since the text is a
    sibling of the class, not a child. */
 .theme-selected ~ .editor,
 .theme-selected ~ .editor .theme-fg-color1,
 .theme-selected ~ .editor .theme-fg-color2,
 .theme-selected ~ .editor .theme-fg-color3,
 .theme-selected ~ .editor .theme-fg-color4,
@@ -398,16 +378,22 @@ ul.children + .tag-line::before {
 .doctype {
   font-style: italic;
 }
 
 .theme-firebug .doctype {
   color: #787878;
 }
 
+/* In case a node isn't displayed in the page, we fade the syntax highlighting */
+.not-displayed .open,
+.not-displayed .close {
+  opacity: .5;
+}
+
 /* Events */
 .markupview-events {
   font-size: 8px;
   font-weight: bold;
   line-height: 10px;
   border-radius: 3px;
   padding: 0px 2px;
   margin-inline-start: 5px;
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -23,49 +23,48 @@ CustomElementCallback::Call()
   switch (mType) {
     case nsIDocument::eCreated:
     {
       // For the duration of this callback invocation, the element is being created
       // flag must be set to true.
       mOwnerData->mElementIsBeingCreated = true;
 
       // The callback hasn't actually been invoked yet, but we need to flip
-      // this now in order to enqueue the attached callback. This is a spec
+      // this now in order to enqueue the connected callback. This is a spec
       // bug (w3c bug 27437).
       mOwnerData->mCreatedCallbackInvoked = true;
 
-      // If ELEMENT is in a document and this document has a browsing context,
-      // enqueue attached callback for ELEMENT.
+      // If ELEMENT is connected, enqueue connected callback for ELEMENT.
       nsIDocument* document = mThisObject->GetComposedDoc();
-      if (document && document->GetDocShell()) {
+      if (document) {
         NodeInfo* ni = mThisObject->NodeInfo();
         nsDependentAtomString extType(mOwnerData->mType);
 
         // We need to do this because at this point, CustomElementDefinition is
         // not set to CustomElementData yet, so EnqueueLifecycleCallback will
         // fail to find the CE definition for this custom element.
         // This will go away eventually since there is no created callback in v1.
         CustomElementDefinition* definition =
           nsContentUtils::LookupCustomElementDefinition(document,
             ni->LocalName(), ni->NamespaceID(),
             extType.IsEmpty() ? nullptr : &extType);
 
         nsContentUtils::EnqueueLifecycleCallback(
-          document, nsIDocument::eAttached, mThisObject, nullptr, definition);
+          nsIDocument::eConnected, mThisObject, nullptr, definition);
       }
 
       static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
       mOwnerData->mElementIsBeingCreated = false;
       break;
     }
-    case nsIDocument::eAttached:
-      static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv);
+    case nsIDocument::eConnected:
+      static_cast<LifecycleConnectedCallback *>(mCallback.get())->Call(mThisObject, rv);
       break;
-    case nsIDocument::eDetached:
-      static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv);
+    case nsIDocument::eDisconnected:
+      static_cast<LifecycleDisconnectedCallback *>(mCallback.get())->Call(mThisObject, rv);
       break;
     case nsIDocument::eAttributeChanged:
       static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject,
         mArgs.name, mArgs.oldValue, mArgs.newValue, mArgs.namespaceURI, rv);
       break;
   }
 }
 
@@ -316,17 +315,17 @@ CustomElementRegistry::SetupCustomElemen
 
   // Enqueuing the created callback will set the CustomElementData on the
   // element, causing prototype swizzling to occur in Element::WrapObject.
   // We make it synchronously for createElement/createElementNS in order to
   // pass tests. It'll be removed when we deprecate custom elements v0.
   SyncInvokeReactions(nsIDocument::eCreated, aElement, definition);
 }
 
-UniquePtr<CustomElementCallback>
+/* static */ UniquePtr<CustomElementCallback>
 CustomElementRegistry::CreateCustomElementCallback(
   nsIDocument::ElementCallbackType aType, Element* aCustomElement,
   LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition)
 {
   MOZ_ASSERT(aDefinition, "CustomElementDefinition should not be null");
 
   RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
   MOZ_ASSERT(elementData, "CustomElementData should exist");
@@ -335,25 +334,25 @@ CustomElementRegistry::CreateCustomEleme
   CallbackFunction* func = nullptr;
   switch (aType) {
     case nsIDocument::eCreated:
       if (aDefinition->mCallbacks->mCreatedCallback.WasPassed()) {
         func = aDefinition->mCallbacks->mCreatedCallback.Value();
       }
       break;
 
-    case nsIDocument::eAttached:
-      if (aDefinition->mCallbacks->mAttachedCallback.WasPassed()) {
-        func = aDefinition->mCallbacks->mAttachedCallback.Value();
+    case nsIDocument::eConnected:
+      if (aDefinition->mCallbacks->mConnectedCallback.WasPassed()) {
+        func = aDefinition->mCallbacks->mConnectedCallback.Value();
       }
       break;
 
-    case nsIDocument::eDetached:
-      if (aDefinition->mCallbacks->mDetachedCallback.WasPassed()) {
-        func = aDefinition->mCallbacks->mDetachedCallback.Value();
+    case nsIDocument::eDisconnected:
+      if (aDefinition->mCallbacks->mDisconnectedCallback.WasPassed()) {
+        func = aDefinition->mCallbacks->mDisconnectedCallback.Value();
       }
       break;
 
     case nsIDocument::eAttributeChanged:
       if (aDefinition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
         func = aDefinition->mCallbacks->mAttributeChangedCallback.Value();
       }
       break;
@@ -390,26 +389,26 @@ CustomElementRegistry::SyncInvokeReactio
 {
   auto callback = CreateCustomElementCallback(aType, aCustomElement, nullptr,
                                               aDefinition);
   if (!callback) {
     return;
   }
 
   UniquePtr<CustomElementReaction> reaction(Move(
-    MakeUnique<CustomElementCallbackReaction>(this, aDefinition,
+    MakeUnique<CustomElementCallbackReaction>(aDefinition,
                                               Move(callback))));
 
   RefPtr<SyncInvokeReactionRunnable> runnable =
     new SyncInvokeReactionRunnable(Move(reaction), aCustomElement);
 
   nsContentUtils::AddScriptRunner(runnable);
 }
 
-void
+/* static */ void
 CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                                 Element* aCustomElement,
                                                 LifecycleCallbackArgs* aArgs,
                                                 CustomElementDefinition* aDefinition)
 {
   CustomElementDefinition* definition = aDefinition;
   if (!definition) {
     definition = aCustomElement->GetCustomElementDefinition();
@@ -420,32 +419,32 @@ CustomElementRegistry::EnqueueLifecycleC
   }
 
   auto callback =
     CreateCustomElementCallback(aType, aCustomElement, aArgs, definition);
   if (!callback) {
     return;
   }
 
-  DocGroup* docGroup = mWindow->GetDocGroup();
+  DocGroup* docGroup = aCustomElement->OwnerDoc()->GetDocGroup();
   if (!docGroup) {
     return;
   }
 
   if (aType == nsIDocument::eAttributeChanged) {
     nsCOMPtr<nsIAtom> attrName = NS_Atomize(aArgs->name);
     if (definition->mObservedAttributes.IsEmpty() ||
         !definition->mObservedAttributes.Contains(attrName)) {
       return;
     }
   }
 
   CustomElementReactionsStack* reactionsStack =
     docGroup->CustomElementReactionsStack();
-  reactionsStack->EnqueueCallbackReaction(this, aCustomElement, definition,
+  reactionsStack->EnqueueCallbackReaction(aCustomElement, definition,
                                           Move(callback));
 }
 
 void
 CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
                                           JS::MutableHandle<JSObject*> aPrototype)
 {
   mozilla::dom::CustomElementDefinition* definition =
@@ -475,17 +474,17 @@ CustomElementRegistry::UpgradeCandidates
     CustomElementReactionsStack* reactionsStack =
       docGroup->CustomElementReactionsStack();
     for (size_t i = 0; i < candidates->Length(); ++i) {
       nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
       if (!elem) {
         continue;
       }
 
-      reactionsStack->EnqueueUpgradeReaction(this, elem, aDefinition);
+      reactionsStack->EnqueueUpgradeReaction(elem, aDefinition);
     }
   }
 }
 
 JSObject*
 CustomElementRegistry::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CustomElementRegistryBinding::Wrap(aCx, this, aGivenProto);
@@ -929,26 +928,28 @@ CustomElementRegistry::Upgrade(Element* 
                                                             namespaceURI);
 
         LifecycleCallbackArgs args = {
           nsDependentAtomString(attrName),
           VoidString(),
           (attrValue.IsEmpty() ? VoidString() : attrValue),
           (namespaceURI.IsEmpty() ? VoidString() : namespaceURI)
         };
-        nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
-                                                 nsIDocument::eAttributeChanged,
+        nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged,
                                                  aElement,
                                                  &args, aDefinition);
       }
     }
   }
 
   // Step 4.
-  // TODO: Bug 1334043 - Implement connected lifecycle callbacks for custom elements
+  if (aElement->IsInComposedDoc()) {
+    nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, aElement,
+                                             nullptr, aDefinition);
+  }
 
   // Step 5.
   AutoConstructionStackEntry acs(aDefinition->mConstructionStack,
                                  nsGenericHTMLElement::FromContent(aElement));
 
   // Step 6 and step 7.
   DoUpgrade(aElement, aDefinition->mConstructor, aRv);
   if (aRv.Failed()) {
@@ -960,18 +961,17 @@ CustomElementRegistry::Upgrade(Element* 
 
   // Step 8.
   data->mState = CustomElementData::State::eCustom;
 
   // Step 9.
   aElement->SetCustomElementDefinition(aDefinition);
 
   // This is for old spec.
-  nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
-                                           nsIDocument::eCreated,
+  nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eCreated,
                                            aElement, nullptr, aDefinition);
 }
 
 //-----------------------------------------------------
 // CustomElementReactionsStack
 
 void
 CustomElementReactionsStack::CreateAndPushElementQueue()
@@ -1005,50 +1005,48 @@ CustomElementReactionsStack::PopAndInvok
   // new reactions should be already consumed and removed at this point.
   MOZ_ASSERT(lastIndex == mReactionsStack.Length() - 1,
              "reactions created by InvokeReactions() should be consumed and removed");
 
   mReactionsStack.RemoveElementAt(lastIndex);
 }
 
 void
-CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
-                                                    Element* aElement,
+CustomElementReactionsStack::EnqueueUpgradeReaction(Element* aElement,
                                                     CustomElementDefinition* aDefinition)
 {
-  Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
+  Enqueue(aElement, new CustomElementUpgradeReaction(aDefinition));
 }
 
 void
-CustomElementReactionsStack::EnqueueCallbackReaction(CustomElementRegistry* aRegistry,
-                                                     Element* aElement,
+CustomElementReactionsStack::EnqueueCallbackReaction(Element* aElement,
                                                      CustomElementDefinition* aDefinition,
                                                      UniquePtr<CustomElementCallback> aCustomElementCallback)
 {
-  Enqueue(aElement, new CustomElementCallbackReaction(aRegistry, aDefinition,
+  Enqueue(aElement, new CustomElementCallbackReaction(aDefinition,
                                                       Move(aCustomElementCallback)));
 }
 
 void
 CustomElementReactionsStack::Enqueue(Element* aElement,
                                      CustomElementReaction* aReaction)
 {
   RefPtr<CustomElementData> elementData = aElement->GetCustomElementData();
   MOZ_ASSERT(elementData, "CustomElementData should exist");
 
   // Add element to the current element queue.
   if (!mReactionsStack.IsEmpty()) {
-    mReactionsStack.LastElement()->AppendElement(do_GetWeakReference(aElement));
+    mReactionsStack.LastElement()->AppendElement(aElement);
     elementData->mReactionQueue.AppendElement(aReaction);
     return;
   }
 
   // If the custom element reactions stack is empty, then:
   // Add element to the backup element queue.
-  mBackupQueue.AppendElement(do_GetWeakReference(aElement));
+  mBackupQueue.AppendElement(aElement);
   elementData->mReactionQueue.AppendElement(aReaction);
 
   if (mIsBackupQueueProcessing) {
     return;
   }
 
   CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
   RefPtr<ProcessBackupQueueRunnable> processBackupQueueRunnable =
@@ -1076,24 +1074,28 @@ CustomElementReactionsStack::InvokeReact
   // This is used for error reporting.
   Maybe<AutoEntryScript> aes;
   if (aGlobal) {
     aes.emplace(aGlobal, "custom elements reaction invocation");
   }
 
   // Note: It's possible to re-enter this method.
   for (uint32_t i = 0; i < aElementQueue->Length(); ++i) {
-    nsCOMPtr<Element> element = do_QueryReferent(aElementQueue->ElementAt(i));
+    Element* element = aElementQueue->ElementAt(i);
 
     if (!element) {
       continue;
     }
 
     RefPtr<CustomElementData> elementData = element->GetCustomElementData();
-    MOZ_ASSERT(elementData, "CustomElementData should exist");
+    if (!elementData) {
+      // This happens when the document is destroyed and the element is already
+      // unlinked, no need to fire the callbacks in this case.
+      return;
+    }
 
     auto& reactions = elementData->mReactionQueue;
     for (uint32_t j = 0; j < reactions.Length(); ++j) {
       // Transfer the ownership of the entry due to reentrant invocation of
       // this funciton. The entry will be removed when bug 1379573 is landed.
       auto reaction(Move(reactions.ElementAt(j)));
       if (reaction) {
         ErrorResult rv;
@@ -1133,24 +1135,24 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
     cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
   }
 
   if (callbacks->mCreatedCallback.WasPassed()) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mCreatedCallback");
     cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
   }
 
-  if (callbacks->mAttachedCallback.WasPassed()) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mAttachedCallback");
-    cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
+  if (callbacks->mConnectedCallback.WasPassed()) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mConnectedCallback");
+    cb.NoteXPCOMChild(callbacks->mConnectedCallback.Value());
   }
 
-  if (callbacks->mDetachedCallback.WasPassed()) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mDetachedCallback");
-    cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
+  if (callbacks->mDisconnectedCallback.WasPassed()) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mDisconnectedCallback");
+    cb.NoteXPCOMChild(callbacks->mDisconnectedCallback.Value());
   }
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mConstructor");
   cb.NoteXPCOMChild(tmp->mConstructor);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementDefinition)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPrototype)
@@ -1179,17 +1181,17 @@ CustomElementDefinition::CustomElementDe
 
 
 //-----------------------------------------------------
 // CustomElementUpgradeReaction
 
 /* virtual */ void
 CustomElementUpgradeReaction::Invoke(Element* aElement, ErrorResult& aRv)
 {
-  mRegistry->Upgrade(aElement, mDefinition, aRv);
+  CustomElementRegistry::Upgrade(aElement, mDefinition, aRv);
 }
 
 //-----------------------------------------------------
 // CustomElementCallbackReaction
 
 /* virtual */ void
 CustomElementCallbackReaction::Invoke(Element* aElement, ErrorResult& aRv)
 {
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -195,54 +195,49 @@ struct CustomElementDefinition
 
 private:
   ~CustomElementDefinition() {}
 };
 
 class CustomElementReaction
 {
 public:
-  explicit CustomElementReaction(CustomElementRegistry* aRegistry,
-                                 CustomElementDefinition* aDefinition)
-    : mRegistry(aRegistry)
-    , mDefinition(aDefinition)
+  explicit CustomElementReaction(CustomElementDefinition* aDefinition)
+    : mDefinition(aDefinition)
   {
   }
 
   virtual ~CustomElementReaction() = default;
   virtual void Invoke(Element* aElement, ErrorResult& aRv) = 0;
   virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const
   {
   }
 
 protected:
-  CustomElementRegistry* mRegistry;
   CustomElementDefinition* mDefinition;
 };
 
 class CustomElementUpgradeReaction final : public CustomElementReaction
 {
 public:
-  explicit CustomElementUpgradeReaction(CustomElementRegistry* aRegistry,
-                                        CustomElementDefinition* aDefinition)
-    : CustomElementReaction(aRegistry, aDefinition)
+  explicit CustomElementUpgradeReaction(CustomElementDefinition* aDefinition)
+    : CustomElementReaction(aDefinition)
   {
   }
 
 private:
    virtual void Invoke(Element* aElement, ErrorResult& aRv) override;
 };
 
 class CustomElementCallbackReaction final : public CustomElementReaction
 {
   public:
-    CustomElementCallbackReaction(CustomElementRegistry* aRegistry,
-                                  CustomElementDefinition* aDefinition,
+    CustomElementCallbackReaction(CustomElementDefinition* aDefinition,
                                   UniquePtr<CustomElementCallback> aCustomElementCallback)
-      : CustomElementReaction(aRegistry, aDefinition)
+      : CustomElementReaction(aDefinition)
       , mCustomElementCallback(Move(aCustomElementCallback))
     {
     }
 
     virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
     {
       mCustomElementCallback->Traverse(aCb);
     }
@@ -258,36 +253,35 @@ class CustomElementReactionsStack
 public:
   NS_INLINE_DECL_REFCOUNTING(CustomElementReactionsStack)
 
   CustomElementReactionsStack()
     : mIsBackupQueueProcessing(false)
   {
   }
 
-  // nsWeakPtr is a weak pointer of Element
+  // Hold a strong reference of Element so that it does not get cycle collected
+  // before the reactions in its reaction queue are invoked.
   // The element reaction queues are stored in CustomElementData.
   // We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
   // The choice of 1 for the auto size here is based on gut feeling.
-  typedef AutoTArray<nsWeakPtr, 1> ElementQueue;
+  typedef AutoTArray<RefPtr<Element>, 1> ElementQueue;
 
   /**
    * Enqueue a custom element upgrade reaction
    * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
    */
-  void EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
-                              Element* aElement,
+  void EnqueueUpgradeReaction(Element* aElement,
                               CustomElementDefinition* aDefinition);
 
   /**
    * Enqueue a custom element callback reaction
    * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-callback-reaction
    */
-  void EnqueueCallbackReaction(CustomElementRegistry* aRegistry,
-                               Element* aElement,
+  void EnqueueCallbackReaction(Element* aElement,
                                CustomElementDefinition* aDefinition,
                                UniquePtr<CustomElementCallback> aCustomElementCallback);
 
   // [CEReactions] Before executing the algorithm's steps
   // Push a new element queue onto the custom element reactions stack.
   void CreateAndPushElementQueue();
 
   // [CEReactions] After executing the algorithm's steps
@@ -372,20 +366,20 @@ public:
 
   /**
    * Enqueue created callback or register upgrade candidate for
    * newly created custom elements, possibly extending an existing type.
    * ex. <x-button>, <button is="x-button> (type extension)
    */
   void SetupCustomElement(Element* aElement, const nsAString* aTypeExtension);
 
-  void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
-                                Element* aCustomElement,
-                                LifecycleCallbackArgs* aArgs,
-                                CustomElementDefinition* aDefinition);
+  static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
+                                       Element* aCustomElement,
+                                       LifecycleCallbackArgs* aArgs,
+                                       CustomElementDefinition* aDefinition);
 
   void GetCustomPrototype(nsIAtom* aAtom,
                           JS::MutableHandle<JSObject*> aPrototype);
 
   void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
                            Element* aCustomElement,
                            CustomElementDefinition* aDefinition);
 
@@ -393,17 +387,17 @@ public:
    * Upgrade an element.
    * https://html.spec.whatwg.org/multipage/scripting.html#upgrades
    */
   static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
 
 private:
   ~CustomElementRegistry();
 
-  UniquePtr<CustomElementCallback> CreateCustomElementCallback(
+  static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
     nsIDocument::ElementCallbackType aType, Element* aCustomElement,
     LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition);
 
   /**
    * Registers an unresolved custom element that is a candidate for
    * upgrade when the definition is registered via registerElement.
    * |aTypeName| is the name of the custom element type, if it is not
    * provided, then element name is used. |aTypeName| should be provided
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1615,24 +1615,21 @@ Element::BindToTree(nsIDocument* aDocume
     UnsetFlags(NODE_FORCE_XBL_BINDINGS | NODE_NEEDS_FRAME |
                NODE_DESCENDANTS_NEED_FRAMES | ELEMENT_ALL_RESTYLE_FLAGS);
   } else {
     // If we're not in the doc and not in a shadow tree,
     // update our subtree pointer.
     SetSubtreeRootPointer(aParent->SubtreeRoot());
   }
 
-  nsIDocument* composedDoc = GetComposedDoc();
-  if (composedDoc) {
-    // Attached callback must be enqueued whenever custom element is inserted into a
-    // document and this document has a browsing context.
-    if (GetCustomElementData() && composedDoc->GetDocShell()) {
-      // Enqueue an attached callback for the custom element.
-      nsContentUtils::EnqueueLifecycleCallback(
-        composedDoc, nsIDocument::eAttached, this);
+  if (CustomElementRegistry::IsCustomElementEnabled() && IsInComposedDoc()) {
+    // Connected callback must be enqueued whenever a custom element becomes
+    // connected.
+    if (GetCustomElementData()) {
+      nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this);
     }
   }
 
   // Propagate scoped style sheet tracking bit.
   if (mParent->IsContent()) {
     nsIContent* parent;
     ShadowRoot* shadowRootParent = ShadowRoot::FromNode(mParent);
     if (shadowRootParent) {
@@ -1946,22 +1943,22 @@ Element::UnbindFromTree(bool aDeep, bool
           document,
           binding->GetAnonymousContent(),
           /* aNullParent */ false);
       }
     }
 
     document->ClearBoxObjectFor(this);
 
-    // Detached must be enqueued whenever custom element is removed from
-    // the document and this document has a browsing context.
-    if (GetCustomElementData() && document->GetDocShell()) {
-      // Enqueue a detached callback for the custom element.
-      nsContentUtils::EnqueueLifecycleCallback(
-        document, nsIDocument::eDetached, this);
+     // Disconnected must be enqueued whenever a connected custom element becomes
+     // disconnected.
+    if (CustomElementRegistry::IsCustomElementEnabled() &&
+        GetCustomElementData()) {
+      nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eDisconnected,
+                                               this);
     }
   }
 
   // This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
   //  because it has to happen after unsetting the parent pointer, but before
   //  recursively unbinding the kids.
   if (IsHTMLElement()) {
     ResetDir(this);
@@ -2620,17 +2617,17 @@ Element::SetAttrAndNotify(int32_t aNames
 
   if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
     RefPtr<nsXBLBinding> binding = GetXBLBinding();
     if (binding) {
       binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
     }
   }
 
-  if (nsContentUtils::IsWebComponentsEnabled()) {
+  if (CustomElementRegistry::IsCustomElementEnabled()) {
     if (CustomElementData* data = GetCustomElementData()) {
       if (CustomElementDefinition* definition =
             nsContentUtils::GetElementDefinitionIfObservingAttr(this,
                                                                 data->mType,
                                                                 aName)) {
         nsCOMPtr<nsIAtom> oldValueAtom;
         if (oldValue) {
           oldValueAtom = oldValue->GetAsAtom();
@@ -2647,17 +2644,17 @@ Element::SetAttrAndNotify(int32_t aNames
           nsDependentAtomString(aName),
           aModType == nsIDOMMutationEvent::ADDITION ?
             VoidString() : nsDependentAtomString(oldValueAtom),
           nsDependentAtomString(newValueAtom),
           (ns.IsEmpty() ? VoidString() : ns)
         };
 
         nsContentUtils::EnqueueLifecycleCallback(
-          OwnerDoc(), nsIDocument::eAttributeChanged, this, &args, definition);
+          nsIDocument::eAttributeChanged, this, &args, definition);
       }
     }
   }
 
   if (aCallAfterSetAttr) {
     rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
                       aNotify);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -2924,17 +2921,17 @@ Element::UnsetAttr(int32_t aNameSpaceID,
 
   if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
     RefPtr<nsXBLBinding> binding = GetXBLBinding();
     if (binding) {
       binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
     }
   }
 
-  if (nsContentUtils::IsWebComponentsEnabled()) {
+  if (CustomElementRegistry::IsCustomElementEnabled()) {
     if (CustomElementData* data = GetCustomElementData()) {
       if (CustomElementDefinition* definition =
             nsContentUtils::GetElementDefinitionIfObservingAttr(this,
                                                                 data->mType,
                                                                 aName)) {
         nsAutoString ns;
         nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
 
@@ -2942,17 +2939,17 @@ Element::UnsetAttr(int32_t aNameSpaceID,
         LifecycleCallbackArgs args = {
           nsDependentAtomString(aName),
           nsDependentAtomString(oldValueAtom),
           VoidString(),
           (ns.IsEmpty() ? VoidString() : ns)
         };
 
         nsContentUtils::EnqueueLifecycleCallback(
-          OwnerDoc(), nsIDocument::eAttributeChanged, this, &args, definition);
+          nsIDocument::eAttributeChanged, this, &args, definition);
       }
     }
   }
 
   rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UpdateState(aNotify);
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -10157,55 +10157,40 @@ nsContentUtils::SyncInvokeReactions(nsID
 
 /* static */ void
 nsContentUtils::EnqueueUpgradeReaction(Element* aElement,
                                        CustomElementDefinition* aDefinition)
 {
   MOZ_ASSERT(aElement);
 
   nsIDocument* doc = aElement->OwnerDoc();
-  nsPIDOMWindowInner* window(doc->GetInnerWindow());
-  if (!window) {
-    return;
-  }
-
-  RefPtr<CustomElementRegistry> registry(window->CustomElements());
-  if (!registry) {
+
+  // No DocGroup means no custom element reactions stack.
+  if (!doc->GetDocGroup()) {
     return;
   }
 
   CustomElementReactionsStack* stack =
     doc->GetDocGroup()->CustomElementReactionsStack();
-  stack->EnqueueUpgradeReaction(registry, aElement, aDefinition);
+  stack->EnqueueUpgradeReaction(aElement, aDefinition);
 }
 
 /* static */ void
-nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc,
-                                         nsIDocument::ElementCallbackType aType,
+nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                          Element* aCustomElement,
                                          LifecycleCallbackArgs* aArgs,
                                          CustomElementDefinition* aDefinition)
 {
-  MOZ_ASSERT(aDoc);
-
-  if (!aDoc->GetDocShell()) {
-    return;
-  }
-
-  nsCOMPtr<nsPIDOMWindowInner> window(aDoc->GetInnerWindow());
-  if (!window) {
+  // No DocGroup means no custom element reactions stack.
+  if (!aCustomElement->OwnerDoc()->GetDocGroup()) {
     return;
   }
 
-  RefPtr<CustomElementRegistry> registry(window->CustomElements());
-  if (!registry) {
-    return;
-  }
-
-  registry->EnqueueLifecycleCallback(aType, aCustomElement, aArgs, aDefinition);
+  CustomElementRegistry::EnqueueLifecycleCallback(aType, aCustomElement, aArgs,
+                                                  aDefinition);
 }
 
 /* static */ void
 nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
                                    int32_t aNamespaceID,
                                    nsIAtom* aAtom,
                                    JS::MutableHandle<JSObject*> aPrototype)
 {
@@ -10439,57 +10424,80 @@ nsContentUtils::AppendNativeAnonymousChi
   // The root scroll frame is not the primary frame of the root element.
   // Detect and handle this case.
   if (!(aFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
       aContent == aContent->OwnerDoc()->GetRootElement()) {
     AppendDocumentLevelNativeAnonymousContentTo(aContent->OwnerDoc(), aKids);
   }
 }
 
+/* static */ bool
+nsContentUtils::GetLoadingPrincipalForXULNode(nsIContent* aLoadingNode,
+                                              nsIPrincipal** aLoadingPrincipal)
+{
+  MOZ_ASSERT(aLoadingNode);
+  MOZ_ASSERT(aLoadingPrincipal);
+
+  bool result = false;
+  nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadingNode->NodePrincipal();
+  nsAutoString loadingStr;
+  aLoadingNode->GetAttr(kNameSpaceID_None, nsGkAtoms::loadingprincipal,
+                        loadingStr);
+  if (loadingStr.IsEmpty()) {
+    // Fall back to mContent's principal (SystemPrincipal) if 'loadingprincipal'
+    // isn't specified.
+    loadingPrincipal.forget(aLoadingPrincipal);
+    return result;
+  }
+
+  nsCOMPtr<nsISupports> serializedPrincipal;
+  NS_DeserializeObject(NS_ConvertUTF16toUTF8(loadingStr),
+                       getter_AddRefs(serializedPrincipal));
+  loadingPrincipal = do_QueryInterface(serializedPrincipal);
+  if (loadingPrincipal) {
+    // We only allow specifying loadingprincipal attribute on a node loaded by
+    // SystemPrincipal.
+    MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(aLoadingNode->NodePrincipal()),
+               "aLoadingNode Should be loaded with SystemPrincipal");
+
+    result = true;
+  } else {
+    // Fallback if the deserialization is failed.
+    loadingPrincipal = aLoadingNode->NodePrincipal();
+  }
+
+  loadingPrincipal.forget(aLoadingPrincipal);
+  return result;
+}
 
 /* static */ void
 nsContentUtils::GetContentPolicyTypeForUIImageLoading(nsIContent* aLoadingNode,
                                                       nsIPrincipal** aLoadingPrincipal,
                                                       nsContentPolicyType& aContentPolicyType,
                                                       uint64_t* aRequestContextID)
 {
   MOZ_ASSERT(aRequestContextID);
 
-  // Use the serialized loadingPrincipal from the image element. Fall back
-  // to mContent's principal (SystemPrincipal) if not available.
-  aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
-  nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadingNode->NodePrincipal();
-  nsAutoString imageLoadingPrincipal;
-  aLoadingNode->GetAttr(kNameSpaceID_None, nsGkAtoms::loadingprincipal,
-                        imageLoadingPrincipal);
-  if (!imageLoadingPrincipal.IsEmpty()) {
-    nsCOMPtr<nsISupports> serializedPrincipal;
-    NS_DeserializeObject(NS_ConvertUTF16toUTF8(imageLoadingPrincipal),
-                         getter_AddRefs(serializedPrincipal));
-    loadingPrincipal = do_QueryInterface(serializedPrincipal);
-
-    if (loadingPrincipal) {
-      // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for
-      // indicating it's a favicon loading.
-      aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON;
-
-      nsAutoString requestContextID;
-      aLoadingNode->GetAttr(kNameSpaceID_None, nsGkAtoms::requestcontextid,
-                            requestContextID);
-      nsresult rv;
-      int64_t val  = requestContextID.ToInteger64(&rv);
-      *aRequestContextID = NS_SUCCEEDED(rv)
-        ? val
-        : 0;
-    } else {
-      // Fallback if the deserialization is failed.
-      loadingPrincipal = aLoadingNode->NodePrincipal();
-    }
-  }
-  loadingPrincipal.forget(aLoadingPrincipal);
+  bool result = GetLoadingPrincipalForXULNode(aLoadingNode, aLoadingPrincipal);
+  if (result) {
+    // Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for
+    // indicating it's a favicon loading.
+    aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON;
+
+    nsAutoString requestContextID;
+    aLoadingNode->GetAttr(kNameSpaceID_None, nsGkAtoms::requestcontextid,
+                          requestContextID);
+    nsresult rv;
+    int64_t val  = requestContextID.ToInteger64(&rv);
+    *aRequestContextID = NS_SUCCEEDED(rv)
+      ? val
+      : 0;
+  } else {
+    aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
+  }
 }
 
 /* static */ nsresult
 nsContentUtils::CreateJSValueFromSequenceOfObject(JSContext* aCx,
                                                   const Sequence<JSObject*>& aTransfer,
                                                   JS::MutableHandle<JS::Value> aValue)
 {
   if (aTransfer.IsEmpty()) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3000,18 +3000,17 @@ public:
 
   static void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
                                   Element* aCustomElement,
                                   mozilla::dom::CustomElementDefinition* aDefinition);
 
   static void EnqueueUpgradeReaction(Element* aElement,
                                      mozilla::dom::CustomElementDefinition* aDefinition);
 
-  static void EnqueueLifecycleCallback(nsIDocument* aDoc,
-                                       nsIDocument::ElementCallbackType aType,
+  static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                        Element* aCustomElement,
                                        mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
                                        mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
 
   static void GetCustomPrototype(nsIDocument* aDoc,
                                  int32_t aNamespaceID,
                                  nsIAtom* aAtom,
                                  JS::MutableHandle<JSObject*> prototype);
@@ -3034,16 +3033,29 @@ public:
    *
    * See `AllChildrenIterator` for the description of the `aFlags` parameter.
    */
   static void AppendNativeAnonymousChildren(const nsIContent* aContent,
                                             nsTArray<nsIContent*>& aKids,
                                             uint32_t aFlags);
 
   /**
+   * Query loadingPrincipal if it is specified as 'loadingprincipal' attribute on
+   * aLoadingNode, otherwise the NodePrincipal of aLoadingNode is returned
+   * (which is System Principal).
+   *
+   * Return true if aLoadingPrincipal has 'loadingprincipal' attributes, and
+   * the value 'loadingprincipal' is also successfully deserialized, otherwise
+   * return false.
+   */
+  static bool
+  GetLoadingPrincipalForXULNode(nsIContent* aLoadingNode,
+                                nsIPrincipal** aLoadingPrincipal);
+
+  /**
    * Returns the content policy type that should be used for loading images
    * for displaying in the UI.  The sources of such images can be <xul:image>,
    * <xul:menuitem> on OSX where we load the image through nsMenuItemIconX, etc.
    */
   static void
   GetContentPolicyTypeForUIImageLoading(nsIContent* aLoadingNode,
                                         nsIPrincipal** aLoadingPrincipal,
                                         nsContentPolicyType& aContentPolicyType,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -356,41 +356,16 @@ static uint32_t gThrottledIdlePeriodLeng
                  "No outer window available!");                               \
       return;                                                                 \
     }                                                                         \
     outer->method args;                                                       \
     return;                                                                   \
   }                                                                           \
   PR_END_MACRO
 
-#define FORWARD_TO_OUTER_CHROME(method, args, err_rval)                       \
-  PR_BEGIN_MACRO                                                              \
-  if (IsInnerWindow()) {                                                      \
-    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
-    if (!AsInner()->HasActiveDocument()) {                                    \
-      NS_WARNING(outer ?                                                      \
-                 "Inner window does not have active document." :              \
-                 "No outer window available!");                               \
-      return err_rval;                                                        \
-    }                                                                         \
-    return ((nsGlobalChromeWindow *)outer)->method args;                      \
-  }                                                                           \
-  PR_END_MACRO
-
-#define FORWARD_TO_INNER_CHROME(method, args, err_rval)                       \
-  PR_BEGIN_MACRO                                                              \
-  if (IsOuterWindow()) {                                                      \
-    if (!mInnerWindow) {                                                      \
-      NS_WARNING("No inner window available!");                               \
-      return err_rval;                                                        \
-    }                                                                         \
-    return ((nsGlobalChromeWindow *)nsGlobalWindow::Cast(mInnerWindow))->method args; \
-  }                                                                           \
-  PR_END_MACRO
-
 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   PR_BEGIN_MACRO                                                              \
   if (IsInnerWindow()) {                                                      \
     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
     if (!AsInner()->HasActiveDocument()) {                                    \
       NS_WARNING(outer ?                                                      \
                  "Inner window does not have active document." :              \
                  "No outer window available!");                               \
@@ -1748,16 +1723,30 @@ nsGlobalWindow::Init()
 
   sWindowsById = new WindowByIdTable();
 }
 
 nsGlobalWindow::~nsGlobalWindow()
 {
   AssertIsOnMainThread();
 
+  if (IsChromeWindow()) {
+    MOZ_ASSERT(mCleanMessageManager,
+              "chrome windows may always disconnect the msg manager");
+
+    DisconnectAndClearGroupMessageManagers();
+
+    if (mChromeFields.mMessageManager) {
+      static_cast<nsFrameMessageManager *>(
+        mChromeFields.mMessageManager.get())->Disconnect();
+    }
+
+    mCleanMessageManager = false;
+  }
+
   DisconnectEventTargetObjects();
 
   // We have to check if sWindowsById isn't null because ::Shutdown might have
   // been called.
   if (sWindowsById) {
     NS_ASSERTION(sWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
     sWindowsById->Remove(mWindowID);
@@ -2035,20 +2024,19 @@ nsGlobalWindow::CleanUp()
   } else {
     MOZ_ASSERT(!mHasGamepad);
     MOZ_ASSERT(!mHasVREvents);
     MOZ_ASSERT(!mHasVRDisplayActivateEvents);
   }
 
   if (mCleanMessageManager) {
     MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
-    nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
-    if (asChrome->mMessageManager) {
+    if (mChromeFields.mMessageManager) {
       static_cast<nsFrameMessageManager*>(
-        asChrome->mMessageManager.get())->Disconnect();
+        mChromeFields.mMessageManager.get())->Disconnect();
     }
   }
 
   mArguments = nullptr;
 
   CleanupCachedXBLHandlers(this);
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
@@ -2210,16 +2198,19 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
     foundInterface = AsInner();
   } else
   if (aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter))) {
     foundInterface = AsOuter();
   } else
   if (aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) && IsOuterWindow()) {
     foundInterface = AsOuter();
   } else
+  if (aIID.Equals(NS_GET_IID(nsIDOMChromeWindow)) && IsChromeWindow()) {
+    foundInterface = static_cast<nsIDOMChromeWindow*>(this);
+  } else
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
 
@@ -2350,16 +2341,21 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioWorklet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
 
   tmp->TraverseHostObjectURIs(cb);
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mMessageManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mGroupMessageManagers)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mOpenerForInitialContentBrowser)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
   nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
@@ -2432,16 +2428,28 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
 
   tmp->UnlinkHostObjectURIs();
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
   tmp->DisableIdleCallbackRequests();
 
+  if (tmp->IsChromeWindow()) {
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)
+    if (tmp->mChromeFields.mMessageManager) {
+      static_cast<nsFrameMessageManager*>(
+        tmp->mChromeFields.mMessageManager.get())->Disconnect();
+      NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mMessageManager)
+    }
+    tmp->DisconnectAndClearGroupMessageManagers();
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mGroupMessageManagers)
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mOpenerForInitialContentBrowser)
+  }
+
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 #ifdef DEBUG
 void
 nsGlobalWindow::RiskyUnlink()
 {
   NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
@@ -3120,17 +3128,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       xpc::ClearContentXBLScope(newInnerGlobal);
     }
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
     } else {
       if (thisChrome) {
-        newInnerWindow = nsGlobalChromeWindow::Create(this);
+        newInnerWindow = nsGlobalWindow::CreateChrome(this);
       } else {
         newInnerWindow = nsGlobalWindow::Create(this);
       }
 
       // The outer window is automatically treated as frozen when we
       // null out the inner window. As a result, initializing classes
       // on the new inner won't end up reaching into the old inner
       // window for classes etc.
@@ -7304,22 +7312,21 @@ nsGlobalWindow::SetWidgetFullscreen(Full
                                     nsIWidget* aWidget, nsIScreen* aScreen)
 {
   MOZ_ASSERT(IsOuterWindow());
   MOZ_ASSERT(this == GetTopInternal(), "Only topmost window should call this");
   MOZ_ASSERT(!AsOuter()->GetFrameElementInternal(), "Content window should not call this");
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
   if (!NS_WARN_IF(!IsChromeWindow())) {
-    auto chromeWin = static_cast<nsGlobalChromeWindow*>(this);
-    if (!NS_WARN_IF(chromeWin->mFullscreenPresShell)) {
+    if (!NS_WARN_IF(mChromeFields.mFullscreenPresShell)) {
       if (nsIPresShell* shell = mDocShell->GetPresShell()) {
         if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
-          chromeWin->mFullscreenPresShell = do_GetWeakReference(shell);
-          MOZ_ASSERT(chromeWin->mFullscreenPresShell);
+          mChromeFields.mFullscreenPresShell = do_GetWeakReference(shell);
+          MOZ_ASSERT(mChromeFields.mFullscreenPresShell);
           rd->SetIsResizeSuppressed();
           rd->Freeze();
         }
       }
     }
   }
   nsresult rv = aReason == FullscreenReason::ForFullscreenMode ?
     // If we enter fullscreen for fullscreen mode, we want
@@ -7357,23 +7364,22 @@ nsGlobalWindow::FinishFullscreenChange(b
   // and DOM fullscreen.
   FinishDOMFullscreenChange(mDoc, mFullScreen);
 
   // dispatch a "fullscreen" DOM event so that XUL apps can
   // respond visually if we are kicked into full screen mode
   DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
 
   if (!NS_WARN_IF(!IsChromeWindow())) {
-    auto chromeWin = static_cast<nsGlobalChromeWindow*>(this);
     if (nsCOMPtr<nsIPresShell> shell =
-        do_QueryReferent(chromeWin->mFullscreenPresShell)) {
+        do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
       if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
         rd->Thaw();
       }
-      chromeWin->mFullscreenPresShell = nullptr;
+      mChromeFields.mFullscreenPresShell = nullptr;
     }
   }
 
   if (!mWakeLock && mFullScreen) {
     RefPtr<power::PowerManagerService> pmService =
       power::PowerManagerService::GetInstance();
     if (!pmService) {
       return;
@@ -9357,18 +9363,17 @@ public:
 
 bool
 nsGlobalWindow::CanClose()
 {
   MOZ_ASSERT(IsOuterWindow());
 
   if (mIsChrome) {
     nsCOMPtr<nsIBrowserDOMWindow> bwin;
-    nsIDOMChromeWindow* chromeWin = static_cast<nsGlobalChromeWindow*>(this);
-    chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
+    GetBrowserDOMWindow(getter_AddRefs(bwin));
 
     bool canClose = true;
     if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))) {
       return canClose;
     }
   }
 
   if (!mDocShell) {
@@ -14010,54 +14015,23 @@ nsGlobalWindow::DispatchVRDisplayPresent
       Unused << DispatchEvent(event, &defaultActionEnabled);
       // Once we dispatch the event, we must not access any members as an event
       // listener can do anything, including closing windows.
       return;
     }
   }
 }
 
-// nsGlobalChromeWindow implementation
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
-                                                  nsGlobalWindow)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGroupMessageManagers)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerForInitialContentBrowser)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
-                                                nsGlobalWindow)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)
-  if (tmp->mMessageManager) {
-    static_cast<nsFrameMessageManager*>(
-      tmp->mMessageManager.get())->Disconnect();
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
-  }
-  tmp->DisconnectAndClearGroupMessageManagers();
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroupMessageManagers)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerForInitialContentBrowser)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-// QueryInterface implementation for nsGlobalChromeWindow
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalChromeWindow)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
-NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
-
-NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
-NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
-
-/* static */ already_AddRefed<nsGlobalChromeWindow>
-nsGlobalChromeWindow::Create(nsGlobalWindow *aOuterWindow)
-{
-  RefPtr<nsGlobalChromeWindow> window = new nsGlobalChromeWindow(aOuterWindow);
+/* static */ already_AddRefed<nsGlobalWindow>
+nsGlobalWindow::CreateChrome(nsGlobalWindow *aOuterWindow)
+{
+  RefPtr<nsGlobalWindow> window = new nsGlobalWindow(aOuterWindow);
+  window->mIsChrome = true;
+  window->mCleanMessageManager = true;
+
   window->InitWasOffline();
   return window.forget();
 }
 
 enum WindowState {
   // These constants need to match the constants in Window.webidl
   STATE_MAXIMIZED = 1,
   STATE_MINIMIZED = 2,
@@ -14097,41 +14071,41 @@ nsGlobalWindow::IsFullyOccluded()
 
   nsCOMPtr<nsIWidget> widget = GetMainWidget();
   return widget && widget->IsFullyOccluded();
 }
 
 void
 nsGlobalWindow::Maximize()
 {
-  MOZ_ASSERT(IsInnerWindow());
+  MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 
   if (widget) {
     widget->SetSizeMode(nsSizeMode_Maximized);
   }
 }
 
 void
 nsGlobalWindow::Minimize()
 {
-  MOZ_ASSERT(IsInnerWindow());
+  MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 
   if (widget) {
     widget->SetSizeMode(nsSizeMode_Minimized);
   }
 }
 
 void
 nsGlobalWindow::Restore()
 {
-  MOZ_ASSERT(IsInnerWindow());
+  MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 
   if (widget) {
     widget->SetSizeMode(nsSizeMode_Normal);
   }
 }
 
@@ -14266,45 +14240,46 @@ nsGlobalWindow::SetCursorOuter(const nsA
 
 void
 nsGlobalWindow::SetCursor(const nsAString& aCursor, ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(SetCursorOuter, (aCursor, aError), aError, );
 }
 
 NS_IMETHODIMP
-nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
-{
-  FORWARD_TO_INNER_CHROME(GetBrowserDOMWindow, (aBrowserWindow), NS_ERROR_UNEXPECTED);
+nsGlobalWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
+{
+  MOZ_RELEASE_ASSERT(IsChromeWindow());
+  FORWARD_TO_INNER(GetBrowserDOMWindow, (aBrowserWindow), NS_ERROR_UNEXPECTED);
 
   ErrorResult rv;
   NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv));
   return rv.StealNSResult();
 }
 
 nsIBrowserDOMWindow*
 nsGlobalWindow::GetBrowserDOMWindowOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
   MOZ_ASSERT(IsChromeWindow());
-  return static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow;
+  return mChromeFields.mBrowserDOMWindow;
 }
 
 nsIBrowserDOMWindow*
 nsGlobalWindow::GetBrowserDOMWindow(ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindowOuter, (), aError, nullptr);
 }
 
 void
 nsGlobalWindow::SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow)
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
   MOZ_ASSERT(IsChromeWindow());
-  static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow = aBrowserWindow;
+  mChromeFields.mBrowserDOMWindow = aBrowserWindow;
 }
 
 void
 nsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
                                     ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter, (aBrowserWindow), aError, );
 }
@@ -14354,89 +14329,90 @@ nsGlobalWindow::NotifyDefaultButtonLoade
     aError.Throw(rv);
   }
 #else
   aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
 #endif
 }
 
 NS_IMETHODIMP
-nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
-{
-  FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_UNEXPECTED);
+nsGlobalWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
+{
+  FORWARD_TO_INNER(GetMessageManager, (aManager), NS_ERROR_UNEXPECTED);
 
   ErrorResult rv;
   NS_IF_ADDREF(*aManager = GetMessageManager(rv));
   return rv.StealNSResult();
 }
 
 nsIMessageBroadcaster*
 nsGlobalWindow::GetMessageManager(ErrorResult& aError)
 {
   MOZ_ASSERT(IsChromeWindow());
   MOZ_RELEASE_ASSERT(IsInnerWindow());
-  nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
-  if (!myself->mMessageManager) {
+  if (!mChromeFields.mMessageManager) {
     nsCOMPtr<nsIMessageBroadcaster> globalMM =
       do_GetService("@mozilla.org/globalmessagemanager;1");
-    myself->mMessageManager =
+    mChromeFields.mMessageManager =
       new nsFrameMessageManager(nullptr,
                                 static_cast<nsFrameMessageManager*>(globalMM.get()),
                                 MM_CHROME | MM_BROADCASTER);
   }
-  return myself->mMessageManager;
+  return mChromeFields.mMessageManager;
 }
 
 NS_IMETHODIMP
-nsGlobalChromeWindow::GetGroupMessageManager(const nsAString& aGroup,
-                                             nsIMessageBroadcaster** aManager)
-{
-  FORWARD_TO_INNER_CHROME(GetGroupMessageManager, (aGroup, aManager), NS_ERROR_UNEXPECTED);
+nsGlobalWindow::GetGroupMessageManager(const nsAString& aGroup,
+                                       nsIMessageBroadcaster** aManager)
+{
+  MOZ_RELEASE_ASSERT(IsChromeWindow());
+  FORWARD_TO_INNER(GetGroupMessageManager, (aGroup, aManager), NS_ERROR_UNEXPECTED);
 
   ErrorResult rv;
   NS_IF_ADDREF(*aManager = GetGroupMessageManager(aGroup, rv));
   return rv.StealNSResult();
 }
 
 nsIMessageBroadcaster*
 nsGlobalWindow::GetGroupMessageManager(const nsAString& aGroup,
                                        ErrorResult& aError)
 {
   MOZ_ASSERT(IsChromeWindow());
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
-  nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
   nsCOMPtr<nsIMessageBroadcaster> messageManager =
-    myself->mGroupMessageManagers.LookupForAdd(aGroup).OrInsert(
+    mChromeFields.mGroupMessageManagers.LookupForAdd(aGroup).OrInsert(
       [this, &aError] () {
         nsFrameMessageManager* parent =
           static_cast<nsFrameMessageManager*>(GetMessageManager(aError));
 
         return new nsFrameMessageManager(nullptr,
                                          parent,
                                          MM_CHROME | MM_BROADCASTER);
       });
   return messageManager;
 }
 
 nsresult
-nsGlobalChromeWindow::SetOpenerForInitialContentBrowser(mozIDOMWindowProxy* aOpenerWindow)
-{
+nsGlobalWindow::SetOpenerForInitialContentBrowser(mozIDOMWindowProxy* aOpenerWindow)
+{
+  MOZ_RELEASE_ASSERT(IsChromeWindow());
   MOZ_RELEASE_ASSERT(IsOuterWindow());
-  MOZ_ASSERT(!mOpenerForInitialContentBrowser);
-  mOpenerForInitialContentBrowser = aOpenerWindow;
+  MOZ_ASSERT(!mChromeFields.mOpenerForInitialContentBrowser);
+  mChromeFields.mOpenerForInitialContentBrowser = aOpenerWindow;
   return NS_OK;
 }
 
 nsresult
-nsGlobalChromeWindow::TakeOpenerForInitialContentBrowser(mozIDOMWindowProxy** aOpenerWindow)
-{
+nsGlobalWindow::TakeOpenerForInitialContentBrowser(mozIDOMWindowProxy** aOpenerWindow)
+{
+  MOZ_RELEASE_ASSERT(IsChromeWindow());
   MOZ_RELEASE_ASSERT(IsOuterWindow());
   // Intentionally forget our own member
-  mOpenerForInitialContentBrowser.forget(aOpenerWindow);
+  mChromeFields.mOpenerForInitialContentBrowser.forget(aOpenerWindow);
   return NS_OK;
 }
 
 /* static */ already_AddRefed<nsGlobalWindow>
 nsGlobalWindow::Create(nsGlobalWindow *aOuterWindow)
 {
   RefPtr<nsGlobalWindow> window = new nsGlobalWindow(aOuterWindow);
   window->InitWasOffline();
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -255,16 +255,19 @@ private:
 // instead of our accessor methods (AsInner and AsOuter) that do dynamic
 // checking. So we inherit from nsPIDOMWindow<nsISupports>, which is also
 // identical to both nsPIDOMWindowInner and nsPIDOMWindowOuter, but not
 // convertible to either.
 
 class nsGlobalWindow : public mozilla::dom::EventTarget,
                        public nsPIDOMWindow<nsISupports>,
                        private nsIDOMWindow,
+                       // NOTE: This interface is private, as it's only
+                       // implemented on chrome windows.
+                       private nsIDOMChromeWindow,
                        public nsIScriptGlobalObject,
                        public nsIScriptObjectPrincipal,
                        public nsSupportsWeakReference,
                        public nsIInterfaceRequestor,
                        public PRCListStr
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
@@ -337,16 +340,19 @@ public:
   virtual bool IsBlackForCC(bool aTracingNeeded = true) override;
 
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal() override;
 
   // nsIDOMWindow
   NS_DECL_NSIDOMWINDOW
 
+  // nsIDOMChromeWindow (only implemented on chrome windows)
+  NS_DECL_NSIDOMCHROMEWINDOW
+
   nsresult
   OpenJS(const nsAString& aUrl, const nsAString& aName,
          const nsAString& aOptions, nsPIDOMWindowOuter **_retval);
   void CaptureEvents();
   void ReleaseEvents();
   void Dump(const nsAString& aStr);
   void SetResizable(bool aResizable) const;
 
@@ -481,16 +487,17 @@ public:
   // If in doubt, return true.
   static bool MayResolve(jsid aId);
 
   void GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames,
                            bool aEnumerableOnly, mozilla::ErrorResult& aRv);
 
   // Object Management
   static already_AddRefed<nsGlobalWindow> Create(nsGlobalWindow *aOuterWindow);
+  static already_AddRefed<nsGlobalWindow> CreateChrome(nsGlobalWindow *aOuterWindow);
 
   static nsGlobalWindow *FromSupports(nsISupports *supports)
   {
     // Make sure this matches the casts we do in QueryInterface().
     return (nsGlobalWindow *)(mozilla::dom::EventTarget *)supports;
   }
   static nsGlobalWindow *FromWrapper(nsIXPConnectWrappedNative *wrapper)
   {
@@ -1246,17 +1253,17 @@ public:
                     const mozilla::dom::ImageBitmapSource& aImage,
                     int32_t aOffset, int32_t aLength,
                     mozilla::dom::ImageBitmapFormat aFormat,
                     const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
                     mozilla::ErrorResult& aRv);
 
 
   // ChromeWindow bits.  Do NOT call these unless your window is in
-  // fact an nsGlobalChromeWindow.
+  // fact chrome.
   uint16_t WindowState();
   bool IsFullyOccluded();
   nsIBrowserDOMWindow* GetBrowserDOMWindowOuter();
   nsIBrowserDOMWindow* GetBrowserDOMWindow(mozilla::ErrorResult& aError);
   void SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow);
   void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
                            mozilla::ErrorResult& aError);
   void GetAttention(mozilla::ErrorResult& aError);
@@ -1778,16 +1785,29 @@ private:
 
   mozilla::dom::TabGroup* TabGroupInner();
   mozilla::dom::TabGroup* TabGroupOuter();
 
   bool IsBackgroundInternal() const;
 
   void SetIsBackgroundInternal(bool aIsBackground);
 
+  // NOTE: Chrome Only
+  void DisconnectAndClearGroupMessageManagers()
+  {
+    MOZ_RELEASE_ASSERT(IsChromeWindow());
+    for (auto iter = mChromeFields.mGroupMessageManagers.Iter(); !iter.Done(); iter.Next()) {
+      nsIMessageBroadcaster* mm = iter.UserData();
+      if (mm) {
+        static_cast<nsFrameMessageManager*>(mm)->Disconnect();
+      }
+    }
+    mChromeFields.mGroupMessageManagers.Clear();
+  }
+
 public:
   // Dispatch a runnable related to the global.
   virtual nsresult Dispatch(mozilla::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsISerialEventTarget*
   EventTargetFor(mozilla::TaskCategory aCategory) const override;
 
@@ -2020,16 +2040,33 @@ protected:
   // When non-zero, the document should receive a vrdisplayactivate event
   // after loading.  The value is the ID of the VRDisplay that content should
   // begin presentation on.
   uint32_t mAutoActivateVRDisplayID; // Outer windows only
   int64_t mBeforeUnloadListenerCount; // Inner windows only
 
   RefPtr<mozilla::dom::IntlUtils> mIntlUtils;
 
+  // Members in the mChromeFields member should only be used in chrome windows.
+  // All accesses to this field should be guarded by a check of mIsChrome.
+  struct ChromeFields {
+    ChromeFields()
+      : mGroupMessageManagers(1)
+    {}
+
+    nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
+    nsCOMPtr<nsIMessageBroadcaster> mMessageManager;
+    nsInterfaceHashtable<nsStringHashKey, nsIMessageBroadcaster> mGroupMessageManagers;
+    // A weak pointer to the nsPresShell that we are doing fullscreen for.
+    // The pointer being set indicates we've set the IsInFullscreenChange
+    // flag on this pres shell.
+    nsWeakPtr mFullscreenPresShell;
+    nsCOMPtr<mozIDOMWindowProxy> mOpenerForInitialContentBrowser;
+  } mChromeFields;
+
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class mozilla::dom::PostMessageEvent;
   friend class DesktopNotification;
   friend class mozilla::dom::TimeoutManager;
   friend class IdleRequestExecutor;
 
   static WindowByIdTable* sWindowsById;
@@ -2042,102 +2079,24 @@ ToSupports(nsGlobalWindow *p)
 }
 
 inline nsISupports*
 ToCanonicalSupports(nsGlobalWindow *p)
 {
     return static_cast<nsIDOMEventTarget*>(p);
 }
 
-/*
- * nsGlobalChromeWindow inherits from nsGlobalWindow. It is the global
- * object created for a Chrome Window only.
- */
-class nsGlobalChromeWindow : public nsGlobalWindow,
-                             public nsIDOMChromeWindow
-{
-public:
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIDOMChromeWindow interface
-  NS_DECL_NSIDOMCHROMEWINDOW
-
-  static already_AddRefed<nsGlobalChromeWindow> Create(nsGlobalWindow *aOuterWindow);
-
-  void DisconnectAndClearGroupMessageManagers()
-  {
-    for (auto iter = mGroupMessageManagers.Iter(); !iter.Done(); iter.Next()) {
-      nsIMessageBroadcaster* mm = iter.UserData();
-      if (mm) {
-        static_cast<nsFrameMessageManager*>(mm)->Disconnect();
-      }
-    }
-    mGroupMessageManagers.Clear();
-  }
-
-protected:
-  explicit nsGlobalChromeWindow(nsGlobalWindow *aOuterWindow)
-    : nsGlobalWindow(aOuterWindow),
-      mGroupMessageManagers(1)
-  {
-    mIsChrome = true;
-    mCleanMessageManager = true;
-  }
-
-  ~nsGlobalChromeWindow()
-  {
-    MOZ_ASSERT(mCleanMessageManager,
-               "chrome windows may always disconnect the msg manager");
-
-    DisconnectAndClearGroupMessageManagers();
-
-    if (mMessageManager) {
-      static_cast<nsFrameMessageManager *>(
-        mMessageManager.get())->Disconnect();
-    }
-
-    mCleanMessageManager = false;
-  }
-
-public:
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalChromeWindow,
-                                           nsGlobalWindow)
-
-  using nsGlobalWindow::GetBrowserDOMWindow;
-  using nsGlobalWindow::SetBrowserDOMWindow;
-  using nsGlobalWindow::GetAttention;
-  using nsGlobalWindow::GetAttentionWithCycleCount;
-  using nsGlobalWindow::SetCursor;
-  using nsGlobalWindow::Maximize;
-  using nsGlobalWindow::Minimize;
-  using nsGlobalWindow::Restore;
-  using nsGlobalWindow::NotifyDefaultButtonLoaded;
-  using nsGlobalWindow::GetMessageManager;
-  using nsGlobalWindow::GetGroupMessageManager;
-  using nsGlobalWindow::BeginWindowMove;
-
-  nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
-  nsCOMPtr<nsIMessageBroadcaster> mMessageManager;
-  nsInterfaceHashtable<nsStringHashKey, nsIMessageBroadcaster> mGroupMessageManagers;
-  // A weak pointer to the nsPresShell that we are doing fullscreen for.
-  // The pointer being set indicates we've set the IsInFullscreenChange
-  // flag on this pres shell.
-  nsWeakPtr mFullscreenPresShell;
-  nsCOMPtr<mozIDOMWindowProxy> mOpenerForInitialContentBrowser;
-};
-
 /* factory function */
 inline already_AddRefed<nsGlobalWindow>
 NS_NewScriptGlobalObject(bool aIsChrome)
 {
   RefPtr<nsGlobalWindow> global;
 
   if (aIsChrome) {
-    global = nsGlobalChromeWindow::Create(nullptr);
+    global = nsGlobalWindow::CreateChrome(nullptr);
   } else {
     global = nsGlobalWindow::Create(nullptr);
   }
 
   return global.forget();
 }
 
 #endif /* nsGlobalWindow_h___ */
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2737,18 +2737,18 @@ public:
   // GetDoctype defined above
   Element* GetDocumentElement() const
   {
     return GetRootElement();
   }
 
   enum ElementCallbackType {
     eCreated,
-    eAttached,
-    eDetached,
+    eConnected,
+    eDisconnected,
     eAttributeChanged
   };
 
   nsIDocument* GetTopLevelContentDocument();
 
   virtual void
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -1013,18 +1013,16 @@ nsImageLoadingContent::LoadImage(nsIURI*
   // We use the principal of aDocument to avoid having to QI |this| an extra
   // time. It should always be the same as the principal of this node.
 #ifdef DEBUG
   nsIContent* thisContent = AsContent();
   MOZ_ASSERT(thisContent->NodePrincipal() == aDocument->NodePrincipal(),
              "Principal mismatch?");
 #endif
 
-  nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType);
-
   nsLoadFlags loadFlags = aLoadFlags;
   int32_t corsmode = GetCORSMode();
   if (corsmode == CORS_ANONYMOUS) {
     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
   } else if (corsmode == CORS_USE_CREDENTIALS) {
     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
   }
 
@@ -1035,22 +1033,34 @@ nsImageLoadingContent::LoadImage(nsIURI*
   net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
   if (imgReferrerPolicy != net::RP_Unset) {
     referrerPolicy = imgReferrerPolicy;
   }
 
   RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
   nsCOMPtr<nsIContent> content =
       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+
+  nsCOMPtr<nsIPrincipal> loadingPrincipal;
+  bool result =
+    nsContentUtils::GetLoadingPrincipalForXULNode(content,
+                                                  getter_AddRefs(loadingPrincipal));
+
+  // If result is true, which means this node has specified 'loadingprincipal'
+  // attribute on it, so we use favicon as the policy type.
+  nsContentPolicyType policyType = result ?
+                                     nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON:
+                                     PolicyTypeForLoad(aImageLoadType);
+
   nsCOMPtr<nsINode> thisNode =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   nsresult rv = nsContentUtils::LoadImage(aNewURI,
                                           thisNode,
                                           aDocument,
-                                          aDocument->NodePrincipal(),
+                                          loadingPrincipal,
                                           0,
                                           aDocument->GetDocumentURI(),
                                           referrerPolicy,
                                           this, loadFlags,
                                           content->LocalName(),
                                           getter_AddRefs(req),
                                           policyType,
                                           mUseUrgentStartForChannel);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2727,18 +2727,17 @@ class AttrDefiner(PropertyDefiner):
                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
 
     def generateArray(self, array, name):
         if len(array) == 0:
             return ""
 
         def flags(attr):
             unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
-            enumerable = " | %s" % EnumerabilityFlags(attr)
-            return ("JSPROP_SHARED" + enumerable + unforgeable)
+            return EnumerabilityFlags(attr) + unforgeable
 
         def getter(attr):
             if self.static:
                 if attr.type.isPromise():
                     raise TypeError("Don't know how to handle "
                                     "static Promise-returning "
                                     "attribute %s.%s" %
                                     (self.descriptor.name,
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2394,17 +2394,16 @@ WebGLContext::StartVRPresentation()
         return false;
     }
     gl::SurfaceCaps caps = screen->mCaps;
 
     UniquePtr<gl::SurfaceFactory> factory =
         gl::GLScreenBuffer::CreateFactory(gl,
             caps,
             vrmc,
-            vrmc->GetBackendType(),
             TextureFlags::ORIGIN_BOTTOM_LEFT);
 
     if (factory) {
         screen->Morph(Move(factory));
     }
     return true;
 }
 
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -1655,17 +1655,17 @@ Console::PopulateConsoleNotificationInTh
 
       js::SetFunctionNativeReserved(funObj, SLOT_STACKOBJ, stackVal);
       js::SetFunctionNativeReserved(funObj, SLOT_RAW_STACK,
                                     JS::PrivateValue(aData->mStack.get()));
 
       if (NS_WARN_IF(!JS_DefineProperty(aCx, eventObj, "stacktrace",
                                         JS_DATA_TO_FUNC_PTR(JSNative, funObj.get()),
                                         nullptr,
-                                        JSPROP_ENUMERATE | JSPROP_SHARED |
+                                        JSPROP_ENUMERATE |
                                         JSPROP_GETTER | JSPROP_SETTER))) {
         return false;
       }
     }
   }
 
   return true;
 }
--- a/dom/events/EventListenerService.cpp
+++ b/dom/events/EventListenerService.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EventListenerService.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/JSEventHandler.h"
 #include "mozilla/Maybe.h"
+#include "nsArrayUtils.h"
 #include "nsCOMArray.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsMemory.h"
 #include "nsServiceManagerUtils.h"
 #include "nsArray.h"
 #include "nsThreadUtils.h"
@@ -49,20 +50,38 @@ NS_IMETHODIMP
 EventListenerChange::GetTarget(nsIDOMEventTarget** aTarget)
 {
   NS_ENSURE_ARG_POINTER(aTarget);
   NS_ADDREF(*aTarget = mTarget);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-EventListenerChange::GetChangedListenerNames(nsIArray** aEventNames)
+EventListenerChange::GetCountOfEventListenerChangesAffectingAccessibility(
+  uint32_t* aCount)
 {
-  NS_ENSURE_ARG_POINTER(aEventNames);
-  NS_ADDREF(*aEventNames = mChangedListenerNames);
+  *aCount = 0;
+
+  uint32_t length;
+  nsresult rv = mChangedListenerNames->GetLength(&length);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  for (size_t i = 0; i < length; i++) {
+    nsCOMPtr<nsIAtom> listenerName =
+      do_QueryElementAt(mChangedListenerNames, i);
+
+    // These are the event listener changes which may make an element
+    // accessible or inaccessible.
+    if (listenerName == nsGkAtoms::onclick ||
+        listenerName == nsGkAtoms::onmousedown ||
+        listenerName == nsGkAtoms::onmouseup) {
+      *aCount += 1;
+    }
+  }
+
   return NS_OK;
 }
 
 /******************************************************************************
  * mozilla::EventListenerInfo
  ******************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION(EventListenerInfo, mListener)
--- a/dom/events/nsIEventListenerService.idl
+++ b/dom/events/nsIEventListenerService.idl
@@ -5,24 +5,26 @@
 
 #include "nsISupports.idl"
 
 interface nsIDOMEventListener;
 interface nsIDOMEventTarget;
 interface nsIArray;
 
 /**
- * Contains an event target along with an array of nsIAtom in form "oneventname"
- * representing changed event listener names.
+ * Contains an event target along with a count of event listener changes
+ * affecting accessibility.
  */
 [scriptable, uuid(07222b02-da12-4cf4-b2f7-761da007a8d8)]
 interface nsIEventListenerChange : nsISupports
 {
   readonly attribute nsIDOMEventTarget target;
-  [noscript] readonly attribute nsIArray changedListenerNames;
+
+  [noscript]
+  readonly attribute uint32_t countOfEventListenerChangesAffectingAccessibility;
 };
 
 [scriptable, function, uuid(aa7c95f6-d3b5-44b3-9597-1d9f19b9c5f2)]
 interface nsIListenerChangeListener : nsISupports
 {
   void listenersChanged(in nsIArray aEventListenerChanges);
 };
 
--- a/dom/fetch/FetchConsumer.cpp
+++ b/dom/fetch/FetchConsumer.cpp
@@ -467,17 +467,17 @@ FetchBodyConsumer<Derived>::BeginConsume
   if (mShuttingDown) {
     // We haven't started yet, but we have been terminated. AutoFailConsumeBody
     // will dispatch a runnable to release resources.
     return;
   }
 
   nsCOMPtr<nsIInputStreamPump> pump;
   nsresult rv = NS_NewInputStreamPump(getter_AddRefs(pump),
-                                      mBodyStream, -1, -1, 0, 0, false,
+                                      mBodyStream, 0, 0, false,
                                       mMainThreadEventTarget);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   RefPtr<ConsumeBodyDoneObserver<Derived>> p =
    new ConsumeBodyDoneObserver<Derived>(this);
 
--- a/dom/fetch/FetchStream.cpp
+++ b/dom/fetch/FetchStream.cpp
@@ -219,18 +219,16 @@ FetchStream::RequestDataCallback(JSConte
         do_GetService(kStreamTransportServiceCID, &rv);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         stream->ErrorPropagation(aCx, aStream, rv);
         return;
       }
 
       nsCOMPtr<nsITransport> transport;
       rv = sts->CreateInputTransport(stream->mOriginalInputStream,
-                                     /* aStartOffset */ 0,
-                                     /* aReadLimit */ -1,
                                      /* aCloseWhenDone */ true,
                                      getter_AddRefs(transport));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         stream->ErrorPropagation(aCx, aStream, rv);
         return;
       }
 
       nsCOMPtr<nsIInputStream> wrapper;
--- a/dom/file/FileReader.cpp
+++ b/dom/file/FileReader.cpp
@@ -395,18 +395,16 @@ FileReader::ReadFileContent(Blob& aBlob,
       do_GetService(kStreamTransportServiceCID, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aRv.Throw(rv);
       return;
     }
 
     nsCOMPtr<nsITransport> transport;
     aRv = sts->CreateInputTransport(stream,
-                                    /* aStartOffset */ 0,
-                                    /* aReadLimit */ -1,
                                     /* aCloseWhenDone */ true,
                                     getter_AddRefs(transport));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     nsCOMPtr<nsIInputStream> wrapper;
     aRv = transport->OpenInputStream(/* aFlags */ 0,
--- a/dom/file/ipc/IPCBlobInputStream.cpp
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -646,18 +646,16 @@ IPCBlobInputStream::EnsureAsyncRemoteStr
     nsCOMPtr<nsIStreamTransportService> sts =
       do_GetService(kStreamTransportServiceCID, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsCOMPtr<nsITransport> transport;
     rv = sts->CreateInputTransport(mRemoteStream,
-                                   /* aStartOffset */ 0,
-                                   /* aReadLimit */ -1,
                                    /* aCloseWhenDone */ true,
                                    getter_AddRefs(transport));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsCOMPtr<nsIInputStream> wrapper;
     rv = transport->OpenInputStream(/* aFlags */ 0,
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1186,36 +1186,56 @@ public:
       securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
     }
 
     MOZ_ASSERT(aElement->IsAnyOfHTMLElements(nsGkAtoms::audio, nsGkAtoms::video));
     nsContentPolicyType contentPolicyType = aElement->IsHTMLElement(nsGkAtoms::audio)
       ? nsIContentPolicy::TYPE_INTERNAL_AUDIO :
         nsIContentPolicy::TYPE_INTERNAL_VIDEO;
 
+    // If aElement has 'loadingprincipal' attribute, we will use the value as
+    // loadingPrincipal for the channel, otherwise it will default to use
+    // aElement->NodePrincipal().
+    // This function returns true when aElement has 'loadingprincipal', so if
+    // setAttrs is true we will override the origin attributes on the channel
+    // later.
+    nsCOMPtr<nsIPrincipal> loadingPrincipal;
+    bool setAttrs = nsContentUtils::GetLoadingPrincipalForXULNode(aElement,
+                                    getter_AddRefs(loadingPrincipal));
+
     nsCOMPtr<nsILoadGroup> loadGroup = aElement->GetDocumentLoadGroup();
     nsCOMPtr<nsIChannel> channel;
-    nsresult rv = NS_NewChannel(getter_AddRefs(channel),
-                                aElement->mLoadingSrc,
-                                static_cast<Element*>(aElement),
-                                securityFlags,
-                                contentPolicyType,
-                                loadGroup,
-                                nullptr,   // aCallbacks
-                                nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
-                                nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
-                                nsIChannel::LOAD_CLASSIFY_URI |
-                                nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
+    nsresult rv =
+      NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
+                                           aElement->mLoadingSrc,
+                                           static_cast<Element*>(aElement),
+                                           loadingPrincipal,
+                                           securityFlags,
+                                           contentPolicyType,
+                                           loadGroup,
+                                           nullptr,   // aCallbacks
+                                           nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
+                                           nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
+                                           nsIChannel::LOAD_CLASSIFY_URI |
+                                           nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
 
     if (NS_FAILED(rv)) {
       // Notify load error so the element will try next resource candidate.
       aElement->NotifyLoadError();
       return;
     }
 
+    if (setAttrs) {
+      nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+      if (loadInfo) {
+        // The function simply returns NS_OK, so we ignore the return value.
+        Unused << loadInfo->SetOriginAttributes(loadingPrincipal->OriginAttributesRef());
+      }
+    }
+
     nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
     if (cos) {
       if (aElement->mUseUrgentStartForChannel) {
         cos->AddClassFlags(nsIClassOfService::UrgentStart);
 
         // Reset the flag to avoid loading again without initiated by user
         // interaction.
         aElement->mUseUrgentStartForChannel = false;
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -312,17 +312,17 @@ nsGenericHTMLElement::GetOffsetRect(CSSI
       if (parent->IsAbsPosContainingBlock()) {
         offsetParent = content;
         break;
       }
 
       // Add the parent's origin to our own to get to the
       // right coordinate system.
       const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
-      if (!isAbsolutelyPositioned && !isOffsetParent) {
+      if (!isOffsetParent) {
         origin += parent->GetPositionIgnoringScrolling();
       }
 
       if (content) {
         // If we've hit the document element, break here.
         if (content == docElement) {
           break;
         }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -83,18 +83,20 @@
 #include "nsCDefaultURIFixup.h"
 #include "nsIWebBrowser.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIWebBrowserSetup.h"
 #include "nsIWebProgress.h"
 #include "nsIXULRuntime.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
+#include "nsPointerHashKeys.h"
 #include "nsLayoutUtils.h"
 #include "nsPrintfCString.h"
+#include "nsTHashtable.h"
 #include "nsThreadManager.h"
 #include "nsThreadUtils.h"
 #include "nsViewManager.h"
 #include "nsWeakReference.h"
 #include "nsWindowWatcher.h"
 #include "PermissionMessageUtils.h"
 #include "PuppetWidget.h"
 #include "StructuredCloneData.h"
@@ -159,17 +161,17 @@ using mozilla::layers::GeckoContentContr
 NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
 NS_IMPL_ISUPPORTS(TabChildSHistoryListener,
                   nsISHistoryListener,
                   nsIPartialSHistoryListener,
                   nsISupportsWeakReference)
 
 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
 
-nsTArray<TabChild*>* TabChild::sActiveTabs;
+nsTHashtable<nsPtrHashKey<TabChild>>* TabChild::sActiveTabs;
 
 typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
 static TabChildMap* sTabChildren;
 StaticMutex sTabChildrenMutex;
 
 TabChildBase::TabChildBase()
   : mTabChildGlobal(nullptr)
 {
@@ -1115,17 +1117,17 @@ TabChild::ActorDestroy(ActorDestroyReaso
   if (GetTabId() != 0) {
     NestedTabChildMap().erase(GetTabId());
   }
 }
 
 TabChild::~TabChild()
 {
   if (sActiveTabs) {
-    sActiveTabs->RemoveElement(this);
+    sActiveTabs->RemoveEntry(this);
     if (sActiveTabs->IsEmpty()) {
       delete sActiveTabs;
       sActiveTabs = nullptr;
     }
   }
 
   DestroyWindow();
 
@@ -2584,22 +2586,22 @@ TabChild::InternalSetDocShellIsActive(bo
       }
     }
 
     docShell->SetIsActive(aIsActive);
   }
 
   if (aIsActive) {
     if (!sActiveTabs) {
-      sActiveTabs = new nsTArray<TabChild*>();
+      sActiveTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
     }
-    sActiveTabs->AppendElement(this);
+    sActiveTabs->PutEntry(this);
   } else {
     if (sActiveTabs) {
-      sActiveTabs->RemoveElement(this);
+      sActiveTabs->RemoveEntry(this);
       // We don't delete sActiveTabs here when it's empty since that
       // could cause a lot of churn. Instead, we wait until ~TabChild.
     }
   }
 
   if (aIsActive) {
     MakeVisible();
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -43,16 +43,19 @@
 #include "mozilla/layers/GeckoContentController.h"
 #include "nsISHistoryListener.h"
 #include "nsIPartialSHistoryListener.h"
 
 class nsIDOMWindowUtils;
 class nsIHttpChannel;
 class nsISerialEventTarget;
 
+template<typename T> class nsTHashtable;
+template<typename T> class nsPtrHashKey;
+
 namespace mozilla {
 class AbstractThread;
 namespace layout {
 class RenderFrameChild;
 } // namespace layout
 
 namespace layers {
 class APZChild;
@@ -757,17 +760,17 @@ public:
     return sActiveTabs && !sActiveTabs->IsEmpty();
   }
 
   // Returns the set of TabChilds that are currently in the foreground. There
   // can be multiple foreground TabChilds if Firefox has multiple windows
   // open. There can also be zero foreground TabChilds if the foreground tab is
   // in a different content process. Note that this function should only be
   // called if HasActiveTabs() returns true.
-  static const nsTArray<TabChild*>& GetActiveTabs()
+  static const nsTHashtable<nsPtrHashKey<TabChild>>& GetActiveTabs()
   {
     MOZ_ASSERT(HasActiveTabs());
     return *sActiveTabs;
   }
 
 protected:
   virtual ~TabChild();
 
@@ -959,17 +962,17 @@ private:
   uint32_t mPendingDocShellBlockers;
 
   WindowsHandle mWidgetNativeData;
 
   // This state is used to keep track of the current active tabs (the ones in
   // the foreground). There may be more than one if there are multiple browser
   // windows open. There may be none if this process does not host any
   // foreground tabs.
-  static nsTArray<TabChild*>* sActiveTabs;
+  static nsTHashtable<nsPtrHashKey<TabChild>>* sActiveTabs;
 
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/media/ChannelMediaResource.cpp
+++ b/dom/media/ChannelMediaResource.cpp
@@ -745,26 +745,46 @@ ChannelMediaResource::RecreateChannel()
   nsSecurityFlags securityFlags = element->ShouldCheckAllowOrigin()
                                   ? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
                                   : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
 
   MOZ_ASSERT(element->IsAnyOfHTMLElements(nsGkAtoms::audio, nsGkAtoms::video));
   nsContentPolicyType contentPolicyType = element->IsHTMLElement(nsGkAtoms::audio) ?
     nsIContentPolicy::TYPE_INTERNAL_AUDIO : nsIContentPolicy::TYPE_INTERNAL_VIDEO;
 
-  nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
-                              mURI,
-                              element,
-                              securityFlags,
-                              contentPolicyType,
-                              loadGroup,
-                              nullptr,  // aCallbacks
-                              loadFlags);
+  // If element has 'loadingprincipal' attribute, we will use the value as
+  // loadingPrincipal for the channel, otherwise it will default to use
+  // aElement->NodePrincipal().
+  // This function returns true when element has 'loadingprincipal', so if
+  // setAttrs is true we will override the origin attributes on the channel
+  // later.
+  nsCOMPtr<nsIPrincipal> loadingPrincipal;
+  bool setAttrs =
+    nsContentUtils::GetLoadingPrincipalForXULNode(element,
+                                                  getter_AddRefs(loadingPrincipal));
+
+  nsresult rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(mChannel),
+                                                     mURI,
+                                                     element,
+                                                     loadingPrincipal,
+                                                     securityFlags,
+                                                     contentPolicyType,
+                                                     loadGroup,
+                                                     nullptr,  // aCallbacks
+                                                     loadFlags);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (setAttrs) {
+    nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
+    if (loadInfo) {
+      // The function simply returns NS_OK, so we ignore the return value.
+      Unused << loadInfo->SetOriginAttributes(loadingPrincipal->OriginAttributesRef());
+   }
+  }
+
   nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
   if (cos) {
     // Unconditionally disable throttling since we want the media to fluently
     // play even when we switch the tab to background.
     cos->AddClassFlags(nsIClassOfService::DontThrottle);
   }
 
   mSuspendAgent.NotifyChannelOpened(mChannel);
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -986,17 +986,17 @@ TCPSocket::CreateInputStreamPump()
 {
   if (!mSocketInputStream) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   nsresult rv;
   mInputStreamPump = do_CreateInstance("@mozilla.org/network/input-stream-pump;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = mInputStreamPump->Init(mSocketInputStream, -1, -1, 0, 0, false, nullptr);
+  rv = mInputStreamPump->Init(mSocketInputStream, 0, 0, false, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint64_t suspendCount = mSuspendCount;
   while (suspendCount--) {
     mInputStreamPump->Suspend();
   }
 
   rv = mInputStreamPump->AsyncRead(this, nullptr);
--- a/dom/presentation/PresentationTCPSessionTransport.cpp
+++ b/dom/presentation/PresentationTCPSessionTransport.cpp
@@ -277,17 +277,17 @@ PresentationTCPSessionTransport::CreateI
   }
 
   nsresult rv;
   mInputStreamPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = mInputStreamPump->Init(mSocketInputStream, -1, -1, 0, 0, false, nullptr);
+  rv = mInputStreamPump->Init(mSocketInputStream, 0, 0, false, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mInputStreamPump->AsyncRead(this, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
--- a/dom/presentation/provider/PresentationControlService.js
+++ b/dom/presentation/provider/PresentationControlService.js
@@ -658,17 +658,17 @@ TCPControlChannel.prototype = {
     if (this._pump) {
       return;
     }
 
     DEBUG && log("TCPControlChannel - create pump with role: " +
                  this._direction); // jshint ignore:line
     this._pump = Cc["@mozilla.org/network/input-stream-pump;1"].
                createInstance(Ci.nsIInputStreamPump);
-    this._pump.init(this._input, -1, -1, 0, 0, false);
+    this._pump.init(this._input, 0, 0, false);
     this._pump.asyncRead(this, null);
     this._stateMachine.onChannelReady();
   },
 
   // Handle command from remote side
   _handleMessage: function(aMsg) {
     DEBUG && log("TCPControlChannel - handleMessage from " +
                  JSON.stringify(this._deviceInfo) + ": " + JSON.stringify(aMsg)); // jshint ignore:line
--- a/dom/tests/browser/helper_largeAllocation.js
+++ b/dom/tests/browser/helper_largeAllocation.js
@@ -49,17 +49,17 @@ function getPID(aBrowser) {
 function getInLAProc(aBrowser) {
   return ContentTask.spawn(aBrowser, null, () => {
     return Services.appinfo.remoteType == "webLargeAllocation";
   });
 }
 
 async function largeAllocSuccessTests() {
   // I'm terrible and put this set of tests into a single file, so I need a longer timeout
-  requestLongerTimeout(2);
+  requestLongerTimeout(4);
 
   // Check if we are on win32
   let isWin32 = /Windows/.test(navigator.userAgent) && !/x64/.test(navigator.userAgent);
 
   await SpecialPowers.pushPrefEnv({
     set: [
       // Enable the header if it is disabled
       ["dom.largeAllocationHeader.enabled", true],
--- a/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html
@@ -11,30 +11,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1102502">Bug 1102502</a>
 <div id="container"></div>
 
 <script>
 
 SimpleTest.waitForExplicitFinish();
 
-var attachedCallbackCount = 0;
+var connectedCallbackCount = 0;
 
 var p = Object.create(HTMLElement.prototype);
 
 p.createdCallback = function() {
   ok(true, "createdCallback called.");
 };
 
-p.attachedCallback = function() {
-  ok(true, "attachedCallback should be called when the parser creates an element in the document.");
-  attachedCallbackCount++;
-  // attachedCallback should be called twice, once for the element created for innerHTML and
+p.connectedCallback = function() {
+  ok(true, "connectedCallback should be called when the parser creates an element in the document.");
+  connectedCallbackCount++;
+  // connectedCallback should be called twice, once for the element created for innerHTML and
   // once for the element created in this document.
-  if (attachedCallbackCount == 2) {
+  if (connectedCallbackCount == 2) {
     SimpleTest.finish();
   }
 }
 
 document.registerElement("x-foo", { prototype: p });
 
 var container = document.getElementById("container");
 container.innerHTML = '<x-foo></x-foo>';
--- a/dom/webidl/WebComponents.webidl
+++ b/dom/webidl/WebComponents.webidl
@@ -6,26 +6,26 @@
  * The origin of this IDL file is
  * http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 callback LifecycleCreatedCallback = void();
-callback LifecycleAttachedCallback = void();
-callback LifecycleDetachedCallback = void();
+callback LifecycleConnectedCallback = void();
+callback LifecycleDisconnectedCallback = void();
 callback LifecycleAttributeChangedCallback = void(DOMString attrName,
                                                   DOMString? oldValue,
                                                   DOMString? newValue,
                                                   DOMString? namespaceURI);
 
 dictionary LifecycleCallbacks {
   LifecycleCreatedCallback? createdCallback;
-  LifecycleAttachedCallback? attachedCallback;
-  LifecycleDetachedCallback? detachedCallback;
+  LifecycleConnectedCallback? connectedCallback;
+  LifecycleDisconnectedCallback? disconnectedCallback;
   LifecycleAttributeChangedCallback? attributeChangedCallback;
 };
 
 dictionary ElementRegistrationOptions {
   object? prototype = null;
   DOMString? extends = null;
 };
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1720,18 +1720,16 @@ CacheScriptLoader::ResolvedCallback(JSCo
                                      mCSPReportOnlyHeaderValue,
                                      mReferrerPolicyHeaderValue);
     return;
   }
 
   MOZ_ASSERT(!mPump);
   rv = NS_NewInputStreamPump(getter_AddRefs(mPump),
                              inputStream,
-                             -1, /* default streamPos */
-                             -1, /* default streamLen */
                              0, /* default segsize */
                              0, /* default segcount */
                              false, /* default closeWhenDone */
                              mMainThreadEventTarget);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Fail(rv);
     return;
   }
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -1154,18 +1154,16 @@ CompareCache::ManageValueResult(JSContex
 
   nsCOMPtr<nsIInputStream> inputStream;
   response->GetBody(getter_AddRefs(inputStream));
   MOZ_ASSERT(inputStream);
 
   MOZ_ASSERT(!mPump);
   rv = NS_NewInputStreamPump(getter_AddRefs(mPump),
                              inputStream,
-                             -1, /* default streamPos */
-                             -1, /* default streamLen */
                              0, /* default segsize */
                              0, /* default segcount */
                              false, /* default closeWhenDone */
                              SystemGroup::EventTargetFor(TaskCategory::Other));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Finish(rv, false);
     return;
   }
--- a/dom/xbl/nsXBLProtoImplField.h
+++ b/dom/xbl/nsXBLProtoImplField.h
@@ -40,17 +40,17 @@ public:
                             JS::Handle<JSObject*> aTargetClassObject);
 
   nsresult Read(nsIObjectInputStream* aStream);
   nsresult Write(nsIObjectOutputStream* aStream);
 
   const char16_t* GetName() const { return mName; }
 
   unsigned AccessorAttributes() const {
-    return JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER |
+    return JSPROP_GETTER | JSPROP_SETTER |
            (mJSAttributes & (JSPROP_ENUMERATE | JSPROP_PERMANENT));
   }
 
   bool IsEmpty() const { return mFieldTextLength == 0; }
 
 protected:
   nsXBLProtoImplField* mNext;
   char16_t* mName;
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -208,17 +208,17 @@ nsXBLProtoImplProperty::CompileMember(Au
                                       nullptr, getter, getterObject.address());
 
       delete getterText;
       deletedGetter = true;
 
       mGetter.SetJSFunction(getterObject);
 
       if (mGetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
-        mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
+        mJSAttributes |= JSPROP_GETTER;
       }
       if (NS_FAILED(rv)) {
         mGetter.SetJSFunction(nullptr);
         mJSAttributes &= ~JSPROP_GETTER;
         /*chaining to return failure*/
       }
     }
   } // if getter is not empty
@@ -254,17 +254,17 @@ nsXBLProtoImplProperty::CompileMember(Au
                                       gPropertyArgs, setter,
                                       setterObject.address());
 
       delete setterText;
       deletedSetter = true;
       mSetter.SetJSFunction(setterObject);
 
       if (mSetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
-        mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
+        mJSAttributes |= JSPROP_SETTER;
       }
       if (NS_FAILED(rv)) {
         mSetter.SetJSFunction(nullptr);
         mJSAttributes &= ~JSPROP_SETTER;
         /*chaining to return failure*/
       }
     }
   } // if setter wasn't empty....
@@ -303,27 +303,27 @@ nsXBLProtoImplProperty::Read(nsIObjectIn
 
   AutoJSContext cx;
   JS::Rooted<JSObject*> getterObject(cx);
   if (aType == XBLBinding_Serialize_GetterProperty ||
       aType == XBLBinding_Serialize_GetterSetterProperty) {
     nsresult rv = XBL_DeserializeFunction(aStream, &getterObject);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
+    mJSAttributes |= JSPROP_GETTER;
   }
   mGetter.SetJSFunction(getterObject);
 
   JS::Rooted<JSObject*> setterObject(cx);
   if (aType == XBLBinding_Serialize_SetterProperty ||
       aType == XBLBinding_Serialize_GetterSetterProperty) {
     nsresult rv = XBL_DeserializeFunction(aStream, &setterObject);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
+    mJSAttributes |= JSPROP_SETTER;
   }
   mSetter.SetJSFunction(setterObject);
 
 #ifdef DEBUG
   mIsCompiled = true;
 #endif
 
   return NS_OK;
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -63,82 +63,73 @@ GLScreenBuffer::Create(GLContext* gl,
 }
 
 /* static */ UniquePtr<SurfaceFactory>
 GLScreenBuffer::CreateFactory(GLContext* gl,
                               const SurfaceCaps& caps,
                               KnowsCompositor* compositorConnection,
                               const layers::TextureFlags& flags)
 {
-  return CreateFactory(gl, caps, compositorConnection->GetTextureForwarder(),
-                       compositorConnection->GetCompositorBackendType(), flags);
-}
+    LayersIPCChannel* ipcChannel = compositorConnection->GetTextureForwarder();
+    const layers::LayersBackend backend = compositorConnection->GetCompositorBackendType();
+    const bool useANGLE = compositorConnection->GetCompositorUseANGLE();
 
-/* static */ UniquePtr<SurfaceFactory>
-GLScreenBuffer::CreateFactory(GLContext* gl,
-                              const SurfaceCaps& caps,
-                              LayersIPCChannel* ipcChannel,
-                              const mozilla::layers::LayersBackend backend,
-                              const layers::TextureFlags& flags)
-{
+    const bool useGl = !gfxPrefs::WebGLForceLayersReadback() &&
+                       (backend == layers::LayersBackend::LAYERS_OPENGL ||
+                       (backend == layers::LayersBackend::LAYERS_WR && !useANGLE));
+    const bool useD3D = !gfxPrefs::WebGLForceLayersReadback() &&
+                        (backend == layers::LayersBackend::LAYERS_D3D11 ||
+                        (backend == layers::LayersBackend::LAYERS_WR && useANGLE));
+
     UniquePtr<SurfaceFactory> factory = nullptr;
-    if (!gfxPrefs::WebGLForceLayersReadback()) {
-        switch (backend) {
-            case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
+    if (useGl) {
 #if defined(XP_MACOSX)
-                factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
+        factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
 #elif defined(GL_PROVIDER_GLX)
-                if (sGLXLibrary.UseTextureFromPixmap())
-                  factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
+        if (sGLXLibrary.UseTextureFromPixmap())
+            factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
 #elif defined(MOZ_WIDGET_UIKIT)
-                factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel, mFlags);
+        factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel, mFlags);
 #elif defined(MOZ_WIDGET_ANDROID)
-                if (XRE_IsParentProcess() && !gfxPrefs::WebGLSurfaceTextureEnabled()) {
-                    factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
-                } else {
-                    factory = SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
-                }
+        if (XRE_IsParentProcess() && !gfxPrefs::WebGLSurfaceTextureEnabled()) {
+            factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
+        } else {
+            factory = SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
+        }
 #else
-                if (gl->GetContextType() == GLContextType::EGL) {
-                    if (XRE_IsParentProcess()) {
-                        factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
-                    }
-                }
+        if (gl->GetContextType() == GLContextType::EGL) {
+            if (XRE_IsParentProcess()) {
+                factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
+            }
+        }
 #endif
-                break;
-            }
-            case mozilla::layers::LayersBackend::LAYERS_D3D11: {
+    } else if (useD3D) {
 #ifdef XP_WIN
-                // Enable surface sharing only if ANGLE and compositing devices
-                // are both WARP or both not WARP
-                gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
-                if (gl->IsANGLE() &&
-                    (gl->IsWARP() == dm->IsWARP()) &&
-                    dm->TextureSharingWorks())
-                {
-                    factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, ipcChannel, flags);
-                }
-
-                if (!factory && gfxPrefs::WebGLDXGLEnabled()) {
-                  factory = SurfaceFactory_D3D11Interop::Create(gl, caps, ipcChannel, flags);
-                }
-#endif
-              break;
-            }
-            default:
-              break;
+        // Enable surface sharing only if ANGLE and compositing devices
+        // are both WARP or both not WARP
+        gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
+        if (gl->IsANGLE() &&
+            (gl->IsWARP() == dm->IsWARP()) &&
+             dm->TextureSharingWorks())
+        {
+            factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, ipcChannel, flags);
         }
 
-#ifdef GL_PROVIDER_GLX
-        if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
-            factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
+        if (!factory && gfxPrefs::WebGLDXGLEnabled()) {
+            factory = SurfaceFactory_D3D11Interop::Create(gl, caps, ipcChannel, flags);
         }
 #endif
     }
 
+#ifdef GL_PROVIDER_GLX
+    if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
+        factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
+    }
+#endif
+
     return factory;
 }
 
 GLScreenBuffer::GLScreenBuffer(GLContext* gl,
                                const SurfaceCaps& caps,
                                UniquePtr<SurfaceFactory> factory)
     : mGL(gl)
     , mCaps(caps)
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -135,22 +135,16 @@ public:
                                             const gfx::IntSize& size,
                                             const SurfaceCaps& caps);
 
     static UniquePtr<SurfaceFactory>
     CreateFactory(GLContext* gl,
                   const SurfaceCaps& caps,
                   layers::KnowsCompositor* compositorConnection,
                   const layers::TextureFlags& flags);
-    static UniquePtr<SurfaceFactory>
-    CreateFactory(GLContext* gl,
-                  const SurfaceCaps& caps,
-                  layers::LayersIPCChannel* ipcChannel,
-                  const mozilla::layers::LayersBackend backend,
-                  const layers::TextureFlags& flags);
 
 protected:
     GLContext* const mGL; // Owns us.
 public:
     const SurfaceCaps mCaps;
 protected:
     UniquePtr<SurfaceFactory> mFactory;
 
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -88,16 +88,21 @@ GPUParent::Init(base::ProcessId aParentP
 
   // Now it's safe to start IPC.
   if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
     return false;
   }
 
   nsDebugImpl::SetMultiprocessMode("GPU");
 
+  // This must be sent before any IPDL message, which may hit sentinel
+  // errors due to parent and content processes having different
+  // versions.
+  GetIPCChannel()->SendBuildID();
+
 #ifdef MOZ_CRASHREPORTER
   // Init crash reporter support.
   CrashReporterClient::InitSingleton(this);
 #endif
 
   // Ensure gfxPrefs are initialized.
   gfxPrefs::GetSingleton();
   gfxConfig::Init();
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -220,43 +220,41 @@ GPUProcessManager::EnsureProtocolsReady(
   EnsureCompositorManagerChild();
   EnsureImageBridgeChild();
   EnsureVRManager();
 }
 
 void
 GPUProcessManager::EnsureCompositorManagerChild()
 {
-  base::ProcessId gpuPid = EnsureGPUReady()
-                           ? mGPUChild->OtherPid()
-                           : base::GetCurrentProcId();
-
-  if (CompositorManagerChild::IsInitialized(gpuPid)) {
+  bool gpuReady = EnsureGPUReady();
+  if (CompositorManagerChild::IsInitialized(mProcessToken)) {
     return;
   }
 
-  if (!EnsureGPUReady()) {
-    CompositorManagerChild::InitSameProcess(AllocateNamespace());
+  if (!gpuReady) {
+    CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken);
     return;
   }
 
   ipc::Endpoint<PCompositorManagerParent> parentPipe;
   ipc::Endpoint<PCompositorManagerChild> childPipe;
   nsresult rv = PCompositorManager::CreateEndpoints(
     mGPUChild->OtherPid(),
     base::GetCurrentProcId(),
     &parentPipe,
     &childPipe);
   if (NS_FAILED(rv)) {
     DisableGPUProcess("Failed to create PCompositorManager endpoints");
     return;
   }
 
   mGPUChild->SendInitCompositorManager(Move(parentPipe));
-  CompositorManagerChild::Init(Move(childPipe), AllocateNamespace());
+  CompositorManagerChild::Init(Move(childPipe), AllocateNamespace(),
+                               mProcessToken);
 }
 
 void
 GPUProcessManager::EnsureImageBridgeChild()
 {
   if (ImageBridgeChild::GetSingleton()) {
     return;
   }
@@ -518,17 +516,17 @@ GPUProcessManager::NotifyListenersOnComp
   }
 }
 
 void
 GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
 {
   MOZ_ASSERT(mProcess && mProcess == aHost);
 
-  CompositorManagerChild::OnGPUProcessLost();
+  CompositorManagerChild::OnGPUProcessLost(aHost->GetProcessToken());
   DestroyProcess();
 
   if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestarts())) {
     char disableMessage[64];
     SprintfLiteral(disableMessage, "GPU process disabled after %d attempts",
                    mNumProcessAttempts);
     DisableGPUProcess(disableMessage);
   } else if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestartsWithDecoder()) &&
--- a/gfx/layers/composite/GPUVideoTextureHost.cpp
+++ b/gfx/layers/composite/GPUVideoTextureHost.cpp
@@ -106,47 +106,44 @@ GPUVideoTextureHost::HasIntermediateBuff
 void
 GPUVideoTextureHost::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
 {
   MOZ_ASSERT(mWrappedTextureHost);
 
   mWrappedTextureHost->CreateRenderTexture(aExternalImageId);
 }
 
-void
-GPUVideoTextureHost::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                                    const std::function<wr::ImageKey()>& aImageKeyAllocator)
+uint32_t
+GPUVideoTextureHost::NumSubTextures() const
 {
   MOZ_ASSERT(mWrappedTextureHost);
-  MOZ_ASSERT(aImageKeys.IsEmpty());
-
-  mWrappedTextureHost->GetWRImageKeys(aImageKeys, aImageKeyAllocator);
+  return mWrappedTextureHost->NumSubTextures();
 }
 
 void
-GPUVideoTextureHost::AddWRImage(wr::ResourceUpdateQueue& aResources,
-                                Range<const wr::ImageKey>& aImageKeys,
-                                const wr::ExternalImageId& aExtID)
+GPUVideoTextureHost::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                         ResourceUpdateOp aOp,
+                                         const Range<wr::ImageKey>& aImageKeys,
+                                         const wr::ExternalImageId& aExtID)
 {
   MOZ_ASSERT(mWrappedTextureHost);
-
-  mWrappedTextureHost->AddWRImage(aResources, aImageKeys, aExtID);
+  mWrappedTextureHost->PushResourceUpdates(aResources, aOp, aImageKeys, aExtID);
 }
 
 void
-GPUVideoTextureHost::PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                       const wr::LayoutRect& aBounds,
-                                       const wr::LayoutRect& aClip,
-                                       wr::ImageRendering aFilter,
-                                       Range<const wr::ImageKey>& aImageKeys)
+GPUVideoTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                      const wr::LayoutRect& aBounds,
+                                      const wr::LayoutRect& aClip,
+                                      wr::ImageRendering aFilter,
+                                      const Range<wr::ImageKey>& aImageKeys)
 {
   MOZ_ASSERT(mWrappedTextureHost);
   MOZ_ASSERT(aImageKeys.length() > 0);
 
-  mWrappedTextureHost->PushExternalImage(aBuilder,
+  mWrappedTextureHost->PushDisplayItems(aBuilder,
                                          aBounds,
                                          aClip,
                                          aFilter,
                                          aImageKeys);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/GPUVideoTextureHost.h
+++ b/gfx/layers/composite/GPUVideoTextureHost.h
@@ -43,28 +43,28 @@ public:
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() override { return "GPUVideoTextureHost"; }
 #endif
 
   virtual bool HasIntermediateBuffer() const override;
 
   virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
 
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+  virtual uint32_t NumSubTextures() const override;
 
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aResources,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID) override;
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
 
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aImageKeys) override;
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
 
 protected:
   RefPtr<TextureHost> mWrappedTextureHost;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -561,77 +561,61 @@ void
 BufferTextureHost::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
 {
   RefPtr<wr::RenderTextureHost> texture =
       new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor());
 
   wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId), texture.forget());
 }
 
-void
-BufferTextureHost::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                                  const std::function<wr::ImageKey()>& aImageKeyAllocator)
+uint32_t
+BufferTextureHost::NumSubTextures() const
 {
-  MOZ_ASSERT(aImageKeys.IsEmpty());
+  if (GetFormat() == gfx::SurfaceFormat::YUV) {
+    return 3;
+  }
 
-  if (GetFormat() != gfx::SurfaceFormat::YUV) {
-    // 1 image key
-    aImageKeys.AppendElement(aImageKeyAllocator());
-    MOZ_ASSERT(aImageKeys.Length() == 1);
-  } else {
-    // 3 image key
-    aImageKeys.AppendElement(aImageKeyAllocator());
-    aImageKeys.AppendElement(aImageKeyAllocator());
-    aImageKeys.AppendElement(aImageKeyAllocator());
-    MOZ_ASSERT(aImageKeys.Length() == 3);
-  }
+  return 1;
 }
 
 void
-BufferTextureHost::AddWRImage(wr::ResourceUpdateQueue& aResources,
-                              Range<const wr::ImageKey>& aImageKeys,
-                              const wr::ExternalImageId& aExtID)
+BufferTextureHost::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                       ResourceUpdateOp aOp,
+                                       const Range<wr::ImageKey>& aImageKeys,
+                                       const wr::ExternalImageId& aExtID)
 {
+  auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
+                                              : &wr::ResourceUpdateQueue::UpdateExternalImage;
+  auto bufferType = wr::WrExternalImageBufferType::ExternalBuffer;
+
   if (GetFormat() != gfx::SurfaceFormat::YUV) {
     MOZ_ASSERT(aImageKeys.length() == 1);
 
     wr::ImageDescriptor descriptor(GetSize(),
                                    ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
                                    GetFormat());
-    aResources.AddExternalImageBuffer(aImageKeys[0], descriptor, aExtID);
+    (aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
   } else {
     MOZ_ASSERT(aImageKeys.length() == 3);
 
     const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
     wr::ImageDescriptor yDescriptor(desc.ySize(), desc.ySize().width, gfx::SurfaceFormat::A8);
     wr::ImageDescriptor cbcrDescriptor(desc.cbCrSize(), desc.cbCrSize().width, gfx::SurfaceFormat::A8);
-    aResources.AddExternalImage(aImageKeys[0],
-                                yDescriptor,
-                                aExtID,
-                                wr::WrExternalImageBufferType::ExternalBuffer,
-                                0);
-    aResources.AddExternalImage(aImageKeys[1],
-                                cbcrDescriptor,
-                                aExtID,
-                                wr::WrExternalImageBufferType::ExternalBuffer,
-                                1);
-    aResources.AddExternalImage(aImageKeys[2],
-                                cbcrDescriptor,
-                                aExtID,
-                                wr::WrExternalImageBufferType::ExternalBuffer,
-                                2);
+    (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, bufferType, 0);
+    (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, bufferType, 1);
+    (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, bufferType, 2);
   }
 }
 
 void
-BufferTextureHost::PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                     const wr::LayoutRect& aBounds,
-                                     const wr::LayoutRect& aClip,
-                                     wr::ImageRendering aFilter,
-                                     Range<const wr::ImageKey>& aImageKeys)
+BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                    const wr::LayoutRect& aBounds,
+                                    const wr::LayoutRect& aClip,
+                                    wr::ImageRendering aFilter,
+                                    const Range<wr::ImageKey>& aImageKeys)
 {
   if (GetFormat() != gfx::SurfaceFormat::YUV) {
     MOZ_ASSERT(aImageKeys.length() == 1);
     aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
   } else {
     MOZ_ASSERT(aImageKeys.length() == 3);
     aBuilder.PushYCbCrPlanarImage(aBounds,
                                   aClip,
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -616,45 +616,42 @@ public:
 
   // Create the corresponding RenderTextureHost type of this texture, and
   // register the RenderTextureHost into render thread.
   virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
   {
     MOZ_RELEASE_ASSERT(false, "No CreateRenderTexture() implementation for this TextureHost type.");
   }
 
-  // Create all necessary image keys for this textureHost rendering.
-  // @param aImageKeys - [out] The set of ImageKeys used for this textureHost
-  // composing.
-  // @param aImageKeyAllocator - [in] The function which is used for creating
-  // the new ImageKey.
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator)
-  {
-    MOZ_ASSERT(aImageKeys.IsEmpty());
-    MOZ_ASSERT_UNREACHABLE("No GetWRImageKeys() implementation for this TextureHost type.");
-  }
+  /// Returns the number of actual textures that will be used to render this.
+  /// For example in a lot of YUV cases it will be 3
+  virtual uint32_t NumSubTextures() const { return 1; }
+
+  enum ResourceUpdateOp {
+    ADD_IMAGE,
+    UPDATE_IMAGE,
+  };
 
   // Add all necessary TextureHost informations to the resource update queue.
-  // Then, WR will use this informations to read from the TextureHost.
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aResources,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID)
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID)
   {
-    MOZ_ASSERT_UNREACHABLE("No AddWRImage() implementation for this TextureHost type.");
+    MOZ_ASSERT_UNREACHABLE("Unimplemented");
   }
 
   // Put all necessary WR commands into DisplayListBuilder for this textureHost rendering.
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aKeys)
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aKeys)
   {
-    MOZ_ASSERT_UNREACHABLE("No PushExternalImage() implementation for this TextureHost type.");
+    MOZ_ASSERT_UNREACHABLE("No PushDisplayItems() implementation for this TextureHost type.");
   }
 
   /**
    * Some API's can use the cross-process IOSurface directly, such as OpenVR
    */
   virtual MacIOSurface* GetMacIOSurface() { return nullptr; }
 
 protected:
@@ -742,28 +739,28 @@ public:
   virtual bool HasIntermediateBuffer() const override { return mHasIntermediateBuffer; }
 
   virtual BufferTextureHost* AsBufferTextureHost() override { return this; }
 
   const BufferDescriptor& GetBufferDescriptor() const { return mDescriptor; }
 
   virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
 
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+  virtual uint32_t NumSubTextures() const override;
 
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aResources,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID) override;
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
 
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aImageKeys) override;
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
 
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
   bool UploadIfNeeded();
   bool MaybeUpload(nsIntRegion *aRegion);
   bool EnsureWrappingTextureSource();
 
   virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -1037,96 +1037,79 @@ void
 DXGITextureHostD3D11::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
 {
   RefPtr<wr::RenderTextureHost> texture =
       new wr::RenderDXGITextureHostOGL(mHandle, mFormat, mSize);
 
   wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId), texture.forget());
 }
 
-void
-DXGITextureHostD3D11::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                                     const std::function<wr::ImageKey()>& aImageKeyAllocator)
+uint32_t
+DXGITextureHostD3D11::NumSubTextures() const
 {
-  MOZ_ASSERT(aImageKeys.IsEmpty());
-
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
-      // 1 image key
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      MOZ_ASSERT(aImageKeys.Length() == 1);
+      return 1;
+    }
+    case gfx::SurfaceFormat::NV12: {
+      return 2;
+    }
+    default: {
+      MOZ_ASSERT_UNREACHABLE("unexpected format");
+      return 1;
+    }
+  }
+}
+
+void
+DXGITextureHostD3D11::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                          ResourceUpdateOp aOp,
+                                          const Range<wr::ImageKey>& aImageKeys,
+                                          const wr::ExternalImageId& aExtID)
+{
+  MOZ_ASSERT(mHandle);
+  auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
+                                              : &wr::ResourceUpdateQueue::UpdateExternalImage;
+  auto bufferType = wr::WrExternalImageBufferType::TextureExternalHandle;
+
+  switch (mFormat) {
+    case gfx::SurfaceFormat::R8G8B8X8:
+    case gfx::SurfaceFormat::R8G8B8A8:
+    case gfx::SurfaceFormat::B8G8R8A8:
+    case gfx::SurfaceFormat::B8G8R8X8: {
+      MOZ_ASSERT(aImageKeys.length() == 1);
+
+      wr::ImageDescriptor descriptor(GetSize(), GetFormat());
+      (aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
       break;
     }
     case gfx::SurfaceFormat::NV12: {
-      // 2 image key
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      MOZ_ASSERT(aImageKeys.Length() == 2);
+      MOZ_ASSERT(aImageKeys.length() == 2);
+
+      wr::ImageDescriptor descriptor0(GetSize(), gfx::SurfaceFormat::A8);
+      wr::ImageDescriptor descriptor1(GetSize() / 2, gfx::SurfaceFormat::R8G8);
+      (aResources.*method)(aImageKeys[0], descriptor0, aExtID, bufferType, 0);
+      (aResources.*method)(aImageKeys[1], descriptor1, aExtID, bufferType, 1);
       break;
     }
     default: {
       MOZ_ASSERT_UNREACHABLE("unexpected to be called");
     }
   }
 }
 
 void
-DXGITextureHostD3D11::AddWRImage(wr::ResourceUpdateQueue& aResources,
-                                 Range<const wr::ImageKey>& aImageKeys,
-                                 const wr::ExternalImageId& aExtID)
-{
-  MOZ_ASSERT(mHandle);
-
-  switch (mFormat) {
-    case gfx::SurfaceFormat::R8G8B8X8:
-    case gfx::SurfaceFormat::R8G8B8A8:
-    case gfx::SurfaceFormat::B8G8R8A8:
-    case gfx::SurfaceFormat::B8G8R8X8: {
-      MOZ_ASSERT(aImageKeys.length() == 1);
-
-      wr::ImageDescriptor descriptor(GetSize(), GetFormat());
-      aResources.AddExternalImage(aImageKeys[0],
-                                  descriptor,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::Texture2DHandle,
-                                  0);
-      break;
-    }
-    case gfx::SurfaceFormat::NV12: {
-      MOZ_ASSERT(aImageKeys.length() == 2);
-
-      wr::ImageDescriptor descriptor0(GetSize(), gfx::SurfaceFormat::A8);
-      wr::ImageDescriptor descriptor1(GetSize() / 2, gfx::SurfaceFormat::R8G8);
-      aResources.AddExternalImage(aImageKeys[0],
-                                  descriptor0,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::TextureExternalHandle,
-                                  0);
-      aResources.AddExternalImage(aImageKeys[1],
-                                  descriptor1,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::TextureExternalHandle,
-                                  1);
-      break;
-    }
-    default: {
-      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
-    }
-  }
-}
-
-void
-DXGITextureHostD3D11::PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                        const wr::LayoutRect& aBounds,
-                                        const wr::LayoutRect& aClip,
-                                        wr::ImageRendering aFilter,
-                                        Range<const wr::ImageKey>& aImageKeys)
+DXGITextureHostD3D11::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                       const wr::LayoutRect& aBounds,
+                                       const wr::LayoutRect& aClip,
+                                       wr::ImageRendering aFilter,
+                                       const Range<wr::ImageKey>& aImageKeys)
 {
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
       aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
@@ -1307,30 +1290,20 @@ DXGIYCbCrTextureHostD3D11::BindTextureSo
 
 void
 DXGIYCbCrTextureHostD3D11::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
 {
   // We use AddImage() directly. It's no corresponding RenderTextureHost.
 }
 
 void
-DXGIYCbCrTextureHostD3D11::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                                          const std::function<wr::ImageKey()>& aImageKeyAllocator)
-{
-  MOZ_ASSERT(aImageKeys.IsEmpty());
-
-  // 1 image key
-  aImageKeys.AppendElement(aImageKeyAllocator());
-  MOZ_ASSERT(aImageKeys.Length() == 1);
-}
-
-void
-DXGIYCbCrTextureHostD3D11::AddWRImage(wr::ResourceUpdateQueue& aResources,
-                                      Range<const wr::ImageKey>& aImageKeys,
-                                      const wr::ExternalImageId& aExtID)
+DXGIYCbCrTextureHostD3D11::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                               ResourceUpdateOp aOp,
+                                               const Range<wr::ImageKey>& aImageKeys,
+                                               const wr::ExternalImageId& aExtID)
 {
   // TODO - This implementation is very slow (read-back, copy on the copy and re-upload).
 
   MOZ_ASSERT(mTextures[0] && mTextures[1] && mTextures[2]);
   MOZ_ASSERT(aImageKeys.length() == 1);
 
   // There are 3 A8 channel data in DXGIYCbCrTextureHostD3D11, but ANGLE doesn't
   // support for converting the D3D A8 texture to OpenGL texture handle. So, we
@@ -1346,27 +1319,31 @@ DXGIYCbCrTextureHostD3D11::AddWRImage(wr
   if (!dataSourceSurface->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
     return;
   }
 
   IntSize size = dataSourceSurface->GetSize();
   wr::ImageDescriptor descriptor(size, map.mStride, dataSourceSurface->GetFormat());
   wr::Vec_u8 imgBytes;
   imgBytes.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
-  aResources.AddImage(aImageKeys[0], descriptor, imgBytes);
+  if (aOp == TextureHost::ADD_IMAGE) {
+    aResources.AddImage(aImageKeys[0], descriptor, imgBytes);
+  } else {
+    aResources.UpdateImageBuffer(aImageKeys[0], descriptor, imgBytes);
+  }
 
   dataSourceSurface->Unmap();
 }
 
 void
-DXGIYCbCrTextureHostD3D11::PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                             const wr::LayoutRect& aBounds,
-                                             const wr::LayoutRect& aClip,
-                                             wr::ImageRendering aFilter,
-                                             Range<const wr::ImageKey>& aImageKeys)
+DXGIYCbCrTextureHostD3D11::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                            const wr::LayoutRect& aBounds,
+                                            const wr::LayoutRect& aClip,
+                                            wr::ImageRendering aFilter,
+                                            const Range<wr::ImageKey>& aImageKeys)
 {
   // 1 image key
   MOZ_ASSERT(aImageKeys.length() == 1);
   aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
 }
 
 bool
 DXGIYCbCrTextureHostD3D11::AcquireTextureSource(CompositableTextureSourceRef& aTexture)
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -330,28 +330,28 @@ public:
   virtual void UnlockWithoutCompositor() override;
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
 
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+  virtual uint32_t NumSubTextures() const override;
 
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aAPI,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID) override;
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
 
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aImageKeys) override;
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
 
 protected:
   bool LockInternal();
   void UnlockInternal();
 
   bool EnsureTextureSource();
 
   RefPtr<ID3D11Device> GetDevice();
@@ -393,28 +393,26 @@ public:
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr;
   }
 
   virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
 
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
 
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aResources,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID) override;
-
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aImageKeys) override;
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
 
 private:
   bool EnsureTextureSource();
 
 protected:
   RefPtr<ID3D11Device> GetDevice();
 
   bool EnsureTexture();
--- a/gfx/layers/ipc/CompositorManagerChild.cpp
+++ b/gfx/layers/ipc/CompositorManagerChild.cpp
@@ -19,47 +19,58 @@
 namespace mozilla {
 namespace layers {
 
 using gfx::GPUProcessManager;
 
 StaticRefPtr<CompositorManagerChild> CompositorManagerChild::sInstance;
 
 /* static */ bool
-CompositorManagerChild::IsInitialized(base::ProcessId aGPUPid)
+CompositorManagerChild::IsInitialized(uint64_t aProcessToken)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return sInstance && sInstance->CanSend() && sInstance->OtherPid() == aGPUPid;
+  return sInstance && sInstance->CanSend() &&
+         sInstance->mProcessToken == aProcessToken;
 }
 
-/* static */ bool
-CompositorManagerChild::InitSameProcess(uint32_t aNamespace)
+/* static */ void
+CompositorManagerChild::InitSameProcess(uint32_t aNamespace,
+                                        uint64_t aProcessToken)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (NS_WARN_IF(IsInitialized(base::GetCurrentProcId()))) {
     MOZ_ASSERT_UNREACHABLE("Already initialized same process");
-    return false;
+    return;
   }
 
   RefPtr<CompositorManagerParent> parent =
     CompositorManagerParent::CreateSameProcess();
-  sInstance = new CompositorManagerChild(parent, aNamespace);
-  return true;
+  RefPtr<CompositorManagerChild> child =
+    new CompositorManagerChild(parent, aProcessToken, aNamespace);
+  if (NS_WARN_IF(!child->CanSend())) {
+    MOZ_DIAGNOSTIC_ASSERT(false, "Failed to open same process protocol");
+    return;
+  }
+
+  parent->BindComplete();
+  sInstance = child.forget();
 }
 
 /* static */ bool
 CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
-                             uint32_t aNamespace)
+                             uint32_t aNamespace,
+                             uint64_t aProcessToken /* = 0 */)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (sInstance) {
     MOZ_ASSERT(sInstance->mNamespace != aNamespace);
   }
 
-  sInstance = new CompositorManagerChild(Move(aEndpoint), aNamespace);
+  sInstance = new CompositorManagerChild(Move(aEndpoint), aProcessToken,
+                                         aNamespace);
   return sInstance->CanSend();
 }
 
 /* static */ void
 CompositorManagerChild::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   CompositorBridgeChild::ShutDown();
@@ -68,24 +79,24 @@ CompositorManagerChild::Shutdown()
     return;
   }
 
   sInstance->Close();
   sInstance = nullptr;
 }
 
 /* static */ void
-CompositorManagerChild::OnGPUProcessLost()
+CompositorManagerChild::OnGPUProcessLost(uint64_t aProcessToken)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
   // cannot know if the CompositorManagerChild is about to be released but has
   // yet to be. As such, we want to pre-emptively set mCanSend to false.
-  if (sInstance) {
+  if (sInstance && sInstance->mProcessToken == aProcessToken) {
     sInstance->mCanSend = false;
   }
 }
 
 /* static */ bool
 CompositorManagerChild::CreateContentCompositorBridge(uint32_t aNamespace)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -157,40 +168,44 @@ CompositorManagerChild::CreateSameProces
 
   RefPtr<CompositorBridgeChild> bridge =
     static_cast<CompositorBridgeChild*>(pbridge);
   bridge->InitForWidget(1, aLayerManager, aNamespace);
   return bridge.forget();
 }
 
 CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent,
+                                               uint64_t aProcessToken,
                                                uint32_t aNamespace)
-  : mCanSend(false)
+  : mProcessToken(aProcessToken)
   , mNamespace(aNamespace)
   , mResourceId(0)
+  , mCanSend(false)
 {
   MOZ_ASSERT(aParent);
 
   SetOtherProcessId(base::GetCurrentProcId());
   MessageLoop* loop = CompositorThreadHolder::Loop();
   ipc::MessageChannel* channel = aParent->GetIPCChannel();
   if (NS_WARN_IF(!Open(channel, loop, ipc::ChildSide))) {
     return;
   }
 
   mCanSend = true;
   AddRef();
   SetReplyTimeout();
 }
 
 CompositorManagerChild::CompositorManagerChild(Endpoint<PCompositorManagerChild>&& aEndpoint,
+                                               uint64_t aProcessToken,
                                                uint32_t aNamespace)
-  : mCanSend(false)
+  : mProcessToken(aProcessToken)
   , mNamespace(aNamespace)
   , mResourceId(0)
+  , mCanSend(false)
 {
   if (NS_WARN_IF(!aEndpoint.Bind(this))) {
     return;
   }
 
   mCanSend = true;
   AddRef();
   SetReplyTimeout();
--- a/gfx/layers/ipc/CompositorManagerChild.h
+++ b/gfx/layers/ipc/CompositorManagerChild.h
@@ -19,22 +19,23 @@ namespace layers {
 class CompositorManagerParent;
 class LayerManager;
 
 class CompositorManagerChild : public PCompositorManagerChild
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorManagerChild)
 
 public:
-  static bool IsInitialized(base::ProcessId aPid);
-  static bool InitSameProcess(uint32_t aNamespace);
+  static bool IsInitialized(uint64_t aProcessToken);
+  static void InitSameProcess(uint32_t aNamespace, uint64_t aProcessToken);
   static bool Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
-                   uint32_t aNamespace);
+                   uint32_t aNamespace,
+                   uint64_t aProcessToken = 0);
   static void Shutdown();
-  static void OnGPUProcessLost();
+  static void OnGPUProcessLost(uint64_t aProcessToken);
 
   static bool
   CreateContentCompositorBridge(uint32_t aNamespace);
 
   static already_AddRefed<CompositorBridgeChild>
   CreateWidgetCompositorBridge(uint64_t aProcessToken,
                                LayerManager* aLayerManager,
                                uint32_t aNamespace,
@@ -68,19 +69,21 @@ public:
   bool DeallocPCompositorBridgeChild(PCompositorBridgeChild* aActor) override;
 
   bool ShouldContinueFromReplyTimeout() override;
 
 private:
   static StaticRefPtr<CompositorManagerChild> sInstance;
 
   CompositorManagerChild(CompositorManagerParent* aParent,
+                         uint64_t aProcessToken,
                          uint32_t aNamespace);
 
   CompositorManagerChild(Endpoint<PCompositorManagerChild>&& aEndpoint,
+                         uint64_t aProcessToken,
                          uint32_t aNamespace);
 
   ~CompositorManagerChild() override
   {
   }
 
   bool CanSend() const
   {
@@ -90,17 +93,18 @@ private:
 
   void DeallocPCompositorManagerChild() override;
 
   already_AddRefed<nsIEventTarget>
   GetSpecificMessageEventTarget(const Message& aMsg) override;
 
   void SetReplyTimeout();
 
-  bool mCanSend;
+  uint64_t mProcessToken;
   uint32_t mNamespace;
   uint32_t mResourceId;
+  bool mCanSend;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/CompositorManagerParent.cpp
+++ b/gfx/layers/ipc/CompositorManagerParent.cpp
@@ -37,28 +37,16 @@ CompositorManagerParent::CreateSameProce
     return nullptr;
   }
 
   // The child is responsible for setting up the IPC channel in the same
   // process case because if we open from the child perspective, we can do it
   // on the main thread and complete before we return the manager handles.
   RefPtr<CompositorManagerParent> parent = new CompositorManagerParent();
   parent->SetOtherProcessId(base::GetCurrentProcId());
-
-  // CompositorManagerParent::Bind would normally add a reference for IPDL but
-  // we don't use that in the same process case.
-  parent.get()->AddRef();
-  sInstance = parent;
-
-#ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
-  if (!sActiveActors) {
-    sActiveActors = new nsTArray<CompositorManagerParent*>();
-  }
-  sActiveActors->AppendElement(parent);
-#endif
   return parent.forget();
 }
 
 /* static */ void
 CompositorManagerParent::Create(Endpoint<PCompositorManagerParent>&& aEndpoint)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -128,22 +116,32 @@ CompositorManagerParent::~CompositorMana
 void
 CompositorManagerParent::Bind(Endpoint<PCompositorManagerParent>&& aEndpoint)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   if (NS_WARN_IF(!aEndpoint.Bind(this))) {
     return;
   }
 
+  BindComplete();
+}
+
+void
+CompositorManagerParent::BindComplete()
+{
   // Add the IPDL reference to ourself, so we can't get freed until IPDL is
   // done with us.
   AddRef();
 
+  StaticMutexAutoLock lock(sMutex);
+  if (OtherPid() == base::GetCurrentProcId()) {
+    sInstance = this;
+  }
+
 #ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
-  StaticMutexAutoLock lock(sMutex);
   if (!sActiveActors) {
     sActiveActors = new nsTArray<CompositorManagerParent*>();
   }
   sActiveActors->AppendElement(this);
 #endif
 }
 
 void
--- a/gfx/layers/ipc/CompositorManagerParent.h
+++ b/gfx/layers/ipc/CompositorManagerParent.h
@@ -34,16 +34,17 @@ public:
   static void Shutdown();
 
   static already_AddRefed<CompositorBridgeParent>
   CreateSameProcessWidgetCompositorBridge(CSSToLayoutDeviceScale aScale,
                                           const CompositorOptions& aOptions,
                                           bool aUseExternalSurfaceSize,
                                           const gfx::IntSize& aSurfaceSize);
 
+  void BindComplete();
   void ActorDestroy(ActorDestroyReason aReason) override;
 
   bool DeallocPCompositorBridgeParent(PCompositorBridgeParent* aActor) override;
   PCompositorBridgeParent* AllocPCompositorBridgeParent(const CompositorBridgeOptions& aOpt) override;
 
 private:
   static StaticRefPtr<CompositorManagerParent> sInstance;
   static StaticMutex sMutex;
--- a/gfx/layers/ipc/CompositorThread.cpp
+++ b/gfx/layers/ipc/CompositorThread.cpp
@@ -17,19 +17,16 @@ namespace gfx {
 void ReleaseVRManagerParentSingleton();
 } // namespace gfx
 
 namespace layers {
 
 static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
 static bool sFinishedCompositorShutDown = false;
 
-// See ImageBridgeChild.cpp
-void ReleaseImageBridgeParentSingleton();
-
 CompositorThreadHolder* GetCompositorThreadHolder()
 {
   return sCompositorThreadHolder;
 }
 
 base::Thread*
 CompositorThread()
 {
@@ -121,17 +118,17 @@ CompositorThreadHolder::Start()
 }
 
 void
 CompositorThreadHolder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
   MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
 
-  ReleaseImageBridgeParentSingleton();
+  ImageBridgeParent::Shutdown();
   gfx::ReleaseVRManagerParentSingleton();
   MediaSystemResourceService::Shutdown();
   CompositorManagerParent::Shutdown();
 
   sCompositorThreadHolder = nullptr;
 
   // No locking is needed around sFinishedCompositorShutDown because it is only
   // ever accessed on the main thread.
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -235,23 +235,26 @@ ImageBridgeChild::ShutdownStep1(Synchron
 // dispatched function
 void
 ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
 {
   AutoCompleteTask complete(aTask);
 
   MOZ_ASSERT(InImageBridgeChildThread(),
              "Should be in ImageBridgeChild thread.");
-  Close();
+  if (!mDestroyed) {
+    Close();
+  }
 }
 
 void
 ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mCanSend = false;
+  mDestroyed = true;
   {
     MutexAutoLock lock(mContainerMapLock);
     mImageContainerListeners.Clear();
   }
 }
 
 void
 ImageBridgeChild::DeallocPImageBridgeChild()
@@ -645,18 +648,16 @@ ImageBridgeChild::WillShutdown()
     RefPtr<Runnable> runnable = WrapRunnable(
       RefPtr<ImageBridgeChild>(this),
       &ImageBridgeChild::ShutdownStep2,
       &task);
     GetMessageLoop()->PostTask(runnable.forget());
 
     task.Wait();
   }
-
-  mDestroyed = true;
 }
 
 void
 ImageBridgeChild::InitSameProcess(uint32_t aNamespace)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
 
   MOZ_ASSERT(!sImageBridgeChildSingleton);
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -41,16 +41,18 @@ namespace layers {
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace mozilla::media;
 
 std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
 
 StaticAutoPtr<mozilla::Monitor> sImageBridgesLock;
 
+static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
+
 // defined in CompositorBridgeParent.cpp
 CompositorThreadHolder* GetCompositorThreadHolder();
 
 /* static */ void
 ImageBridgeParent::Setup()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!sImageBridgesLock) {
@@ -76,22 +78,16 @@ ImageBridgeParent::ImageBridgeParent(Mes
   }
   SetOtherProcessId(aChildProcessId);
 }
 
 ImageBridgeParent::~ImageBridgeParent()
 {
 }
 
-static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
-
-void ReleaseImageBridgeParentSingleton() {
-  sImageBridgeParentSingleton = nullptr;
-}
-
 /* static */ ImageBridgeParent*
 ImageBridgeParent::CreateSameProcess()
 {
   RefPtr<ImageBridgeParent> parent =
     new ImageBridgeParent(CompositorThreadHolder::Loop(), base::GetCurrentProcId());
   parent->mSelfRef = parent;
 
   sImageBridgeParentSingleton = parent;
@@ -111,16 +107,46 @@ ImageBridgeParent::CreateForGPUProcess(E
     parent,
     &ImageBridgeParent::Bind,
     Move(aEndpoint)));
 
   sImageBridgeParentSingleton = parent;
   return true;
 }
 
+/* static */ void
+ImageBridgeParent::ShutdownInternal()
+{
+  // We make a copy because we don't want to hold the lock while closing and we
+  // don't want the object to get freed underneath us.
+  nsTArray<RefPtr<ImageBridgeParent>> actors;
+  {
+    MonitorAutoLock lock(*sImageBridgesLock);
+    for (const auto& iter : sImageBridges) {
+      actors.AppendElement(iter.second);
+    }
+  }
+
+  for (auto const& actor : actors) {
+    MOZ_RELEASE_ASSERT(!actor->mClosed);
+    actor->Close();
+  }
+
+  sImageBridgeParentSingleton = nullptr;
+}
+
+/* static */ void
+ImageBridgeParent::Shutdown()
+{
+  CompositorThreadHolder::Loop()->PostTask(
+    NS_NewRunnableFunction("ImageBridgeParent::Shutdown", []() -> void {
+      ImageBridgeParent::ShutdownInternal();
+  }));
+}
+
 void
 ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Can't alloc/dealloc shmems from now on.
   mClosed = true;
   mCompositables.clear();
   {
     MonitorAutoLock lock(*sImageBridgesLock);
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -53,16 +53,17 @@ public:
   /**
    * Creates the globals of ImageBridgeParent.
    */
   static void Setup();
 
   static ImageBridgeParent* CreateSameProcess();
   static bool CreateForGPUProcess(Endpoint<PImageBridgeParent>&& aEndpoint);
   static bool CreateForContent(Endpoint<PImageBridgeParent>&& aEndpoint);
+  static void Shutdown();
 
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   // CompositableParentManager
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
 
@@ -120,16 +121,18 @@ public:
   virtual bool UsesImageBridge() const override { return true; }
 
   virtual bool IPCOpen() const override { return !mClosed; }
 
 protected:
   void Bind(Endpoint<PImageBridgeParent>&& aEndpoint);
 
 private:
+  static void ShutdownInternal();
+
   void DeferredDestroy();
   MessageLoop* mMessageLoop;
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   RefPtr<ImageBridgeParent> mSelfRef;
 
   bool mSetChildThreadPriority;
   bool mClosed;
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -120,119 +120,94 @@ void
 MacIOSurfaceTextureHostOGL::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
 {
   RefPtr<wr::RenderTextureHost> texture =
       new wr::RenderMacIOSurfaceTextureHostOGL(GetMacIOSurface());
 
   wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId), texture.forget());
 }
 
-void
-MacIOSurfaceTextureHostOGL::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                                           const std::function<wr::ImageKey()>& aImageKeyAllocator)
+uint32_t
+MacIOSurfaceTextureHostOGL::NumSubTextures() const
 {
-  MOZ_ASSERT(aImageKeys.IsEmpty());
-
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
-    case gfx::SurfaceFormat::B8G8R8X8: {
-      // 1 image key
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      MOZ_ASSERT(aImageKeys.Length() == 1);
-      break;
-    }
+    case gfx::SurfaceFormat::B8G8R8X8:
     case gfx::SurfaceFormat::YUV422: {
-      // 1 image key
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      MOZ_ASSERT(aImageKeys.Length() == 1);
-      break;
+      return 1;
     }
     case gfx::SurfaceFormat::NV12: {
-      // 2 image key
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      aImageKeys.AppendElement(aImageKeyAllocator());
-      MOZ_ASSERT(aImageKeys.Length() == 2);
-      break;
+      return 2;
     }
     default: {
-      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+      MOZ_ASSERT_UNREACHABLE("unexpected format");
+      return 1;
     }
   }
 }
 
 void
-MacIOSurfaceTextureHostOGL::AddWRImage(wr::ResourceUpdateQueue& aResources,
-                                       Range<const wr::ImageKey>& aImageKeys,
-                                       const wr::ExternalImageId& aExtID)
+MacIOSurfaceTextureHostOGL::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                                ResourceUpdateOp aOp,
+                                                const Range<wr::ImageKey>& aImageKeys,
+                                                const wr::ExternalImageId& aExtID)
 {
   MOZ_ASSERT(mSurface);
 
+  auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
+                                              : &wr::ResourceUpdateQueue::UpdateExternalImage;
+  auto bufferType = wr::WrExternalImageBufferType::TextureRectHandle;
+
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
       wr::ImageDescriptor descriptor(GetSize(), GetFormat());
-      aResources.AddExternalImage(aImageKeys[0],
-                                  descriptor,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::TextureRectHandle,
-                                  0);
+      (aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
       break;
     }
     case gfx::SurfaceFormat::YUV422: {
       // This is the special buffer format. The buffer contents could be a
       // converted RGB interleaving data or a YCbCr interleaving data depending
       // on the different platform setting. (e.g. It will be RGB at OpenGL 2.1
       // and YCbCr at OpenGL 3.1)
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
       wr::ImageDescriptor descriptor(GetSize(), gfx::SurfaceFormat::R8G8B8X8);
-      aResources.AddExternalImage(aImageKeys[0],
-                                  descriptor,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::TextureRectHandle,
-                                  0);
+      (aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
       break;
     }
     case gfx::SurfaceFormat::NV12: {
       MOZ_ASSERT(aImageKeys.length() == 2);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
       wr::ImageDescriptor descriptor0(gfx::IntSize(mSurface->GetDevicePixelWidth(0), mSurface->GetDevicePixelHeight(0)),
                                       gfx::SurfaceFormat::A8);
       wr::ImageDescriptor descriptor1(gfx::IntSize(mSurface->GetDevicePixelWidth(1), mSurface->GetDevicePixelHeight(1)),
                                       gfx::SurfaceFormat::R8G8);
-      aResources.AddExternalImage(aImageKeys[0],
-                                  descriptor0,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::TextureRectHandle,
-                                  0);
-      aResources.AddExternalImage(aImageKeys[1],
-                                  descriptor1,
-                                  aExtID,
-                                  wr::WrExternalImageBufferType::TextureRectHandle,
-                                  1);
+      (aResources.*method)(aImageKeys[0], descriptor0, aExtID, bufferType, 0);
+      (aResources.*method)(aImageKeys[1], descriptor1, aExtID, bufferType, 1);
       break;
     }
     default: {
       MOZ_ASSERT_UNREACHABLE("unexpected to be called");
     }
   }
 }
 
 void
-MacIOSurfaceTextureHostOGL::PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                              const wr::LayoutRect& aBounds,
-                                              const wr::LayoutRect& aClip,
-                                              wr::ImageRendering aFilter,
-                                              Range<const wr::ImageKey>& aImageKeys)
+MacIOSurfaceTextureHostOGL::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                             const wr::LayoutRect& aBounds,
+                                             const wr::LayoutRect& aClip,
+                                             wr::ImageRendering aFilter,
+                                             const Range<wr::ImageKey>& aImageKeys)
 {
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
@@ -59,28 +59,28 @@ public:
 #endif
 
   virtual MacIOSurfaceTextureHostOGL* AsMacIOSurfaceTextureHost() override { return this; }
 
   virtual MacIOSurface* GetMacIOSurface() override { return mSurface; }
 
   virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
 
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+  virtual uint32_t NumSubTextures() const override;
 
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aResources,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID) override;
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
 
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aImageKeys) override;
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
 
 protected:
   GLTextureSource* CreateTextureSourceForPlane(size_t aPlane);
 
   RefPtr<GLTextureSource> mTextureSource;
   RefPtr<MacIOSurface> mSurface;
 };
 
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -6,16 +6,17 @@
 #include "AsyncImagePipelineManager.h"
 
 #include "CompositableHost.h"
 #include "gfxEnv.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/WebRenderImageHost.h"
 #include "mozilla/layers/WebRenderTextureHost.h"
 #include "mozilla/webrender/WebRenderAPI.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace layers {
 
 AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline()
  : mInitialised(false)
  , mIsChanged(false)
  , mUseExternalImage(false)
@@ -37,39 +38,20 @@ AsyncImagePipelineManager::~AsyncImagePi
 {
   MOZ_COUNT_DTOR(AsyncImagePipelineManager);
 }
 
 void
 AsyncImagePipelineManager::Destroy()
 {
   MOZ_ASSERT(!mDestroyed);
-  DeleteOldAsyncImages();
   mApi = nullptr;
   mDestroyed = true;
 }
 
-bool
-AsyncImagePipelineManager::HasKeysToDelete()
-{
-  return !mKeysToDelete.IsEmpty();
-}
-
-void
-AsyncImagePipelineManager::DeleteOldAsyncImages()
-{
-  MOZ_ASSERT(!mDestroyed);
-  wr::ResourceUpdateQueue resources;
-  for (wr::ImageKey key : mKeysToDelete) {
-    resources.DeleteImage(key);
-  }
-  mApi->UpdateResources(resources);
-  mKeysToDelete.Clear();
-}
-
 void
 AsyncImagePipelineManager::AddPipeline(const wr::PipelineId& aPipelineId)
 {
   if (mDestroyed) {
     return;
   }
   uint64_t id = wr::AsUint64(aPipelineId);
 
@@ -157,183 +139,197 @@ AsyncImagePipelineManager::UpdateAsyncIm
   pipeline->mIsChanged = true;
   pipeline->mScBounds = aScBounds;
   pipeline->mScTransform = aScTransform;
   pipeline->mScaleToSize = aScaleToSize;
   pipeline->mFilter = aFilter;
   pipeline->mMixBlendMode = aMixBlendMode;
 }
 
-bool
-AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::ResourceUpdateQueue& aResources,
-                                                          TextureHost* aTexture,
-                                                          nsTArray<wr::ImageKey>& aKeys)
+Maybe<TextureHost::ResourceUpdateOp>
+AsyncImagePipelineManager::UpdateImageKeys(wr::ResourceUpdateQueue& aResources,
+                                           AsyncImagePipeline* aPipeline,
+                                           nsTArray<wr::ImageKey>& aKeys)
 {
   MOZ_ASSERT(aKeys.IsEmpty());
-  MOZ_ASSERT(aTexture);
+  MOZ_ASSERT(aPipeline);
+  if (!aPipeline->mInitialised) {
+    return Nothing();
+  }
+
+  TextureHost* texture = aPipeline->mImageHost->GetAsTextureHostForComposite();
+  TextureHost* previousTexture = aPipeline->mCurrentTexture.get();
 
-  WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
+  if (!aPipeline->mIsChanged && texture == previousTexture) {
+    // The texture has not changed, just reuse previous ImageKeys.
+    // No need to update DisplayList.
+    return Nothing();
+  }
+
+  if (!texture) {
+    // We don't have a new texture, there isn't much we can do.
+    return Nothing();
+  }
 
-  if (!gfxEnv::EnableWebRenderRecording() && wrTexture) {
-    wrTexture->GetWRImageKeys(aKeys, std::bind(&AsyncImagePipelineManager::GenerateImageKey, this));
-    MOZ_ASSERT(!aKeys.IsEmpty());
-    Range<const wr::ImageKey> keys(&aKeys[0], aKeys.Length());
-    wrTexture->AddWRImage(aResources, keys, wrTexture->GetExternalImageKey());
-    return true;
-  } else {
-    RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
-    if (!dSurf) {
-      NS_ERROR("TextureHost does not return DataSourceSurface");
-      return false;
+  aPipeline->mIsChanged = false;
+  aPipeline->mCurrentTexture = texture;
+
+  WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
+
+  bool useExternalImage = !gfxEnv::EnableWebRenderRecording() && wrTexture;
+  aPipeline->mUseExternalImage = useExternalImage;
+
+  // The non-external image code path falls back to converting the texture into
+  // an rgb image.
+  auto numKeys = useExternalImage ? texture->NumSubTextures() : 1;
+
+  // If we already had a texture and the format hasn't changed, better to reuse the image keys
+  // than create new ones.
+  bool canUpdate = !!previousTexture
+                   && previousTexture->GetFormat() == texture->GetFormat()
+                   && aPipeline->mKeys.Length() == numKeys;
+
+  if (!canUpdate) {
+    for (auto key : aPipeline->mKeys) {
+      aResources.DeleteImage(key);
     }
-    gfx::DataSourceSurface::MappedSurface map;
-    if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
-      NS_ERROR("DataSourceSurface failed to map");
-      return false;
+    aPipeline->mKeys.Clear();
+    for (uint32_t i = 0; i < numKeys; ++i) {
+      aPipeline->mKeys.AppendElement(GenerateImageKey());
     }
-    gfx::IntSize size = dSurf->GetSize();
-    wr::Vec_u8 imgBytes;
-    imgBytes.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
-    wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
+  }
+
+  aKeys = aPipeline->mKeys;
+
+  auto op = canUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
 
-    wr::ImageKey key = GenerateImageKey();
-    aKeys.AppendElement(key);
-    aResources.AddImage(key, descriptor, imgBytes);
-    dSurf->Unmap();
+  if (!useExternalImage) {
+    return UpdateWithoutExternalImage(aResources, texture, aKeys[0], op);
   }
-  return false;
+
+  Range<wr::ImageKey> keys(&aKeys[0], aKeys.Length());
+  wrTexture->PushResourceUpdates(aResources, op, keys, wrTexture->GetExternalImageKey());
+
+  return Some(op);
 }
 
-bool
-AsyncImagePipelineManager::UpdateImageKeys(wr::ResourceUpdateQueue& aResources,
-                                           bool& aUseExternalImage,
-                                           AsyncImagePipeline* aImageMgr,
-                                           nsTArray<wr::ImageKey>& aKeys,
-                                           nsTArray<wr::ImageKey>& aKeysToDelete)
+Maybe<TextureHost::ResourceUpdateOp>
+AsyncImagePipelineManager::UpdateWithoutExternalImage(wr::ResourceUpdateQueue& aResources,
+                                                      TextureHost* aTexture,
+                                                      wr::ImageKey aKey,
+                                                      TextureHost::ResourceUpdateOp aOp)
 {
-  MOZ_ASSERT(aKeys.IsEmpty());
-  MOZ_ASSERT(aImageMgr);
-  TextureHost* texture = aImageMgr->mImageHost->GetAsTextureHostForComposite();
+  MOZ_ASSERT(aTexture);
 
-  if (!aImageMgr->mInitialised) {
-    return false;
+  RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
+  if (!dSurf) {
+    NS_ERROR("TextureHost does not return DataSourceSurface");
+    return Nothing();
   }
-
-  // No change
-  if (!aImageMgr->mIsChanged && texture == aImageMgr->mCurrentTexture) {
-    // No need to update DisplayList.
-    return false;
+  gfx::DataSourceSurface::MappedSurface map;
+  if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
+    NS_ERROR("DataSourceSurface failed to map");
+    return Nothing();
   }
 
-  aImageMgr->mIsChanged = false;
+  gfx::IntSize size = dSurf->GetSize();
+  wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
 
-  if (texture == aImageMgr->mCurrentTexture) {
-    // Reuse previous ImageKeys.
-    aKeys.AppendElements(aImageMgr->mKeys);
-    aUseExternalImage = aImageMgr->mUseExternalImage;
-    return true;
+  // Costly copy right here...
+  wr::Vec_u8 bytes;
+  bytes.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
+
+  if (aOp == TextureHost::UPDATE_IMAGE) {
+    aResources.UpdateImageBuffer(aKey, descriptor, bytes);
+  } else {
+    aResources.AddImage(aKey, descriptor, bytes);
   }
 
-  // Delete old ImageKeys
-  aKeysToDelete.AppendElements(aImageMgr->mKeys);
-  aImageMgr->mKeys.Clear();
-  aImageMgr->mCurrentTexture = nullptr;
+  dSurf->Unmap();
 
-  // No txture to render
-  if (!texture) {
-    return true;
-  }
-
-  aUseExternalImage = aImageMgr->mUseExternalImage = GenerateImageKeyForTextureHost(aResources, texture, aKeys);
-  MOZ_ASSERT(!aKeys.IsEmpty());
-  aImageMgr->mKeys.AppendElements(aKeys);
-  aImageMgr->mCurrentTexture = texture;
-  return true;
+  return Some(aOp);
 }
 
 void
 AsyncImagePipelineManager::ApplyAsyncImages()
 {
   if (mDestroyed || mAsyncImagePipelines.Count() == 0) {
     return;
   }
 
   ++mAsyncImageEpoch; // Update webrender epoch
   wr::Epoch epoch = wr::NewEpoch(mAsyncImageEpoch);
-  nsTArray<wr::ImageKey> keysToDelete;
 
-  wr::ResourceUpdateQueue resourceUpdates;
-
+  // We use a pipeline with a very small display list for each video element.
+  // Update each of them if needed.
   for (auto iter = mAsyncImagePipelines.Iter(); !iter.Done(); iter.Next()) {
+    wr::ResourceUpdateQueue resourceUpdates;
     wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
     AsyncImagePipeline* pipeline = iter.Data();
 
     nsTArray<wr::ImageKey> keys;
-    bool useExternalImage = false;
-    bool updateDisplayList = UpdateImageKeys(resourceUpdates,
-                                             useExternalImage,
-                                             pipeline,
-                                             keys,
-                                             keysToDelete);
-    if (!updateDisplayList) {
+    auto op = UpdateImageKeys(resourceUpdates, pipeline, keys);
+
+    if (op != Some(TextureHost::ADD_IMAGE)) {
+      // We don't need to update the display list, either because we can't or because
+      // the previous one is still up to date.
+      // We may, however, have updated some resources.
+      mApi->UpdateResources(resourceUpdates);
       continue;
     }
 
     wr::LayoutSize contentSize { pipeline->mScBounds.Width(), pipeline->mScBounds.Height() };
     wr::DisplayListBuilder builder(pipelineId, contentSize);
 
-    if (!keys.IsEmpty()) {
-      MOZ_ASSERT(pipeline->mCurrentTexture.get());
+    MOZ_ASSERT(!keys.IsEmpty());
+    MOZ_ASSERT(pipeline->mCurrentTexture.get());
 
-      float opacity = 1.0f;
-      builder.PushStackingContext(wr::ToLayoutRect(pipeline->mScBounds),
-                                  0,
-                                  &opacity,
-                                  pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
-                                  wr::TransformStyle::Flat,
-                                  nullptr,
-                                  pipeline->mMixBlendMode,
-                                  nsTArray<wr::WrFilterOp>(),
-                                  true);
+    float opacity = 1.0f;
+    builder.PushStackingContext(wr::ToLayoutRect(pipeline->mScBounds),
+                                0,
+                                &opacity,
+                                pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
+                                wr::TransformStyle::Flat,
+                                nullptr,
+                                pipeline->mMixBlendMode,
+                                nsTArray<wr::WrFilterOp>(),
+                                true);
 
-      LayerRect rect(0, 0, pipeline->mCurrentTexture->GetSize().width, pipeline->mCurrentTexture->GetSize().height);
-      if (pipeline->mScaleToSize.isSome()) {
-        rect = LayerRect(0, 0, pipeline->mScaleToSize.value().width, pipeline->mScaleToSize.value().height);
-      }
+    LayerRect rect(0, 0, pipeline->mCurrentTexture->GetSize().width, pipeline->mCurrentTexture->GetSize().height);
+    if (pipeline->mScaleToSize.isSome()) {
+      rect = LayerRect(0, 0, pipeline->mScaleToSize.value().width, pipeline->mScaleToSize.value().height);
+    }
 
-      if (useExternalImage) {
-        MOZ_ASSERT(pipeline->mCurrentTexture->AsWebRenderTextureHost());
-        Range<const wr::ImageKey> range_keys(&keys[0], keys.Length());
-        pipeline->mCurrentTexture->PushExternalImage(builder,
-                                                     wr::ToLayoutRect(rect),
-                                                     wr::ToLayoutRect(rect),
-                                                     pipeline->mFilter,
-                                                     range_keys);
-        HoldExternalImage(pipelineId, epoch, pipeline->mCurrentTexture->AsWebRenderTextureHost());
-      } else {
-        MOZ_ASSERT(keys.Length() == 1);
-        builder.PushImage(wr::ToLayoutRect(rect),
-                          wr::ToLayoutRect(rect),
-                          true,
-                          pipeline->mFilter,
-                          keys[0]);
-      }
-      builder.PopStackingContext();
+    if (pipeline->mUseExternalImage) {
+      MOZ_ASSERT(pipeline->mCurrentTexture->AsWebRenderTextureHost());
+      Range<wr::ImageKey> range_keys(&keys[0], keys.Length());
+      pipeline->mCurrentTexture->PushDisplayItems(builder,
+                                                  wr::ToLayoutRect(rect),
+                                                  wr::ToLayoutRect(rect),
+                                                  pipeline->mFilter,
+                                                  range_keys);
+      HoldExternalImage(pipelineId, epoch, pipeline->mCurrentTexture->AsWebRenderTextureHost());
+    } else {
+      MOZ_ASSERT(keys.Length() == 1);
+      builder.PushImage(wr::ToLayoutRect(rect),
+                        wr::ToLayoutRect(rect),
+                        true,
+                        pipeline->mFilter,
+                        keys[0]);
     }
+    builder.PopStackingContext();
 
     wr::BuiltDisplayList dl;
     wr::LayoutSize builderContentSize;
     builder.Finalize(builderContentSize, dl);
     mApi->SetDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.Width(), pipeline->mScBounds.Height()),
                          pipelineId, builderContentSize,
                          dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length,
                          resourceUpdates);
   }
-  DeleteOldAsyncImages();
-  mKeysToDelete.SwapElements(keysToDelete);
 }
 
 void
 AsyncImagePipelineManager::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
 {
   if (mDestroyed) {
     return;
   }
--- a/gfx/layers/wr/AsyncImagePipelineManager.h
+++ b/gfx/layers/wr/AsyncImagePipelineManager.h
@@ -37,17 +37,16 @@ public:
 
   explicit AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi);
 
 protected:
   ~AsyncImagePipelineManager();
 
 public:
   void Destroy();
-  bool HasKeysToDelete();
 
   void AddPipeline(const wr::PipelineId& aPipelineId);
   void RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
 
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
   void Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
 
   TimeStamp GetCompositionTime() const {
@@ -87,30 +86,26 @@ public:
   }
 
   void FlushImageNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
   {
     aNotifications->AppendElements(Move(mImageCompositeNotifications));
   }
 
 private:
-  void DeleteOldAsyncImages();
 
   uint32_t GetNextResourceId() { return ++mResourceId; }
   wr::IdNamespace GetNamespace() { return mIdNamespace; }
   wr::ImageKey GenerateImageKey()
   {
     wr::ImageKey key;
     key.mNamespace = GetNamespace();
     key.mHandle = GetNextResourceId();
     return key;
   }
-  bool GenerateImageKeyForTextureHost(wr::ResourceUpdateQueue& aResources,
-                                      TextureHost* aTexture,
-                                      nsTArray<wr::ImageKey>& aKeys);
 
   struct ForwardingTextureHost {
     ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
       : mEpoch(aEpoch)
       , mTexture(aTexture)
     {}
     wr::Epoch mEpoch;
     CompositableTextureHostRef mTexture;
@@ -133,30 +128,33 @@ private:
     gfx::MaybeIntSize mScaleToSize;
     wr::ImageRendering mFilter;
     wr::MixBlendMode mMixBlendMode;
     RefPtr<WebRenderImageHost> mImageHost;
     CompositableTextureHostRef mCurrentTexture;
     nsTArray<wr::ImageKey> mKeys;
   };
 
-  bool UpdateImageKeys(wr::ResourceUpdateQueue& aResourceUpdates,
-                       bool& aUseExternalImage,
-                       AsyncImagePipeline* aImageMgr,
-                       nsTArray<wr::ImageKey>& aKeys,
-                       nsTArray<wr::ImageKey>& aKeysToDelete);
+  Maybe<TextureHost::ResourceUpdateOp>
+  UpdateImageKeys(wr::ResourceUpdateQueue& aResourceUpdates,
+                  AsyncImagePipeline* aPipeline,
+                  nsTArray<wr::ImageKey>& aKeys);
+  Maybe<TextureHost::ResourceUpdateOp>
+  UpdateWithoutExternalImage(wr::ResourceUpdateQueue& aResources,
+                             TextureHost* aTexture,
+                             wr::ImageKey aKey,
+                             TextureHost::ResourceUpdateOp);
 
   RefPtr<wr::WebRenderAPI> mApi;
   wr::IdNamespace mIdNamespace;
   uint32_t mResourceId;
 
   nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder> mPipelineTexturesHolders;
   nsClassHashtable<nsUint64HashKey, AsyncImagePipeline> mAsyncImagePipelines;
   uint32_t mAsyncImageEpoch;
-  nsTArray<wr::ImageKey> mKeysToDelete;
   bool mDestroyed;
 
   // Render time for the current composition.
   TimeStamp mCompositionTime;
 
   // When nonnull, during rendering, some compositable indicated that it will
   // change its rendering at this time. In order not to miss it, we composite
   // on every vsync until this time occurs (this is the latest such time).
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -329,17 +329,17 @@ WebRenderBridgeParent::UpdateResources(c
 
   return true;
 }
 
 bool
 WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                                         wr::ResourceUpdateQueue& aResources)
 {
-  Range<const wr::ImageKey> keys(&aKey, 1);
+  Range<wr::ImageKey> keys(&aKey, 1);
   // Check if key is obsoleted.
   if (keys[0].mNamespace != mIdNamespace) {
     return true;
   }
   MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(aExtId)).get());
 
   RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(aExtId));
   if (!host) {
@@ -349,17 +349,18 @@ WebRenderBridgeParent::AddExternalImage(
   if (!gfxEnv::EnableWebRenderRecording()) {
     TextureHost* texture = host->GetAsTextureHostForComposite();
     if (!texture) {
       NS_ERROR("TextureHost does not exist");
       return false;
     }
     WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
     if (wrTexture) {
-      wrTexture->AddWRImage(aResources, keys, wrTexture->GetExternalImageKey());
+      wrTexture->PushResourceUpdates(aResources, TextureHost::ADD_IMAGE, keys,
+                                     wrTexture->GetExternalImageKey());
       return true;
     }
   }
   RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
   if (!dSurf) {
     NS_ERROR("TextureHost does not return DataSourceSurface");
     return false;
   }
--- a/gfx/layers/wr/WebRenderCanvasRenderer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasRenderer.cpp
@@ -19,26 +19,16 @@ WebRenderCanvasRenderer::GetForwarder()
 {
   return mManager->WrBridge();
 }
 
 void
 WebRenderCanvasRenderer::Initialize(const CanvasInitializeData& aData)
 {
   ShareableCanvasRenderer::Initialize(aData);
-
-  // XXX: Use basic surface factory until we support shared surface.
-  if (!mGLContext || mGLFrontbuffer)
-    return;
-
-  gl::GLScreenBuffer* screen = mGLContext->Screen();
-  auto factory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext,
-                                                      screen->mCaps,
-                                                      mFlags);
-  screen->Morph(Move(factory));
 }
 
 WebRenderCanvasRendererSync::~WebRenderCanvasRendererSync()
 {
   Destroy();
 }
 
 void
--- a/gfx/layers/wr/WebRenderTextureHost.cpp
+++ b/gfx/layers/wr/WebRenderTextureHost.cpp
@@ -129,48 +129,46 @@ WebRenderTextureHost::GetRGBStride()
   if (GetFormat() == gfx::SurfaceFormat::YUV) {
     // XXX this stride is used until yuv image rendering by webrender is used.
     // Software converted RGB buffers strides are aliened to 16
     return gfx::GetAlignedStride<16>(GetSize().width, BytesPerPixel(gfx::SurfaceFormat::B8G8R8A8));
   }
   return ImageDataSerializer::ComputeRGBStride(format, GetSize().width);
 }
 
-void
-WebRenderTextureHost::GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                                     const std::function<wr::ImageKey()>& aImageKeyAllocator)
+uint32_t
+WebRenderTextureHost::NumSubTextures() const
 {
   MOZ_ASSERT(mWrappedTextureHost);
-  MOZ_ASSERT(aImageKeys.IsEmpty());
-
-  mWrappedTextureHost->GetWRImageKeys(aImageKeys, aImageKeyAllocator);
+  return mWrappedTextureHost->NumSubTextures();
 }
 
 void
-WebRenderTextureHost::AddWRImage(wr::ResourceUpdateQueue& aResources,
-                                 Range<const wr::ImageKey>& aImageKeys,
-                                 const wr::ExternalImageId& aExtID)
+WebRenderTextureHost::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                          ResourceUpdateOp aOp,
+                                          const Range<wr::ImageKey>& aImageKeys,
+                                          const wr::ExternalImageId& aExtID)
 {
   MOZ_ASSERT(mWrappedTextureHost);
   MOZ_ASSERT(mExternalImageId == aExtID);
 
-  mWrappedTextureHost->AddWRImage(aResources, aImageKeys, aExtID);
+  mWrappedTextureHost->PushResourceUpdates(aResources, aOp, aImageKeys, aExtID);
 }
 
 void
-WebRenderTextureHost::PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                        const wr::LayoutRect& aBounds,
-                                        const wr::LayoutRect& aClip,
-                                        wr::ImageRendering aFilter,
-                                        Range<const wr::ImageKey>& aImageKeys)
+WebRenderTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                       const wr::LayoutRect& aBounds,
+                                       const wr::LayoutRect& aClip,
+                                       wr::ImageRendering aFilter,
+                                       const Range<wr::ImageKey>& aImageKeys)
 {
   MOZ_ASSERT(mWrappedTextureHost);
   MOZ_ASSERT(aImageKeys.length() > 0);
 
-  mWrappedTextureHost->PushExternalImage(aBuilder,
+  mWrappedTextureHost->PushDisplayItems(aBuilder,
                                          aBounds,
                                          aClip,
                                          aFilter,
                                          aImageKeys);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderTextureHost.h
+++ b/gfx/layers/wr/WebRenderTextureHost.h
@@ -58,28 +58,28 @@ public:
 #endif
 
   virtual WebRenderTextureHost* AsWebRenderTextureHost() override { return this; }
 
   wr::ExternalImageId GetExternalImageKey() { return mExternalImageId; }
 
   int32_t GetRGBStride();
 
-  virtual void GetWRImageKeys(nsTArray<wr::ImageKey>& aImageKeys,
-                              const std::function<wr::ImageKey()>& aImageKeyAllocator) override;
+  virtual uint32_t NumSubTextures() const override;
 
-  virtual void AddWRImage(wr::ResourceUpdateQueue& aResources,
-                          Range<const wr::ImageKey>& aImageKeys,
-                          const wr::ExternalImageId& aExtID) override;
+  virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
 
-  virtual void PushExternalImage(wr::DisplayListBuilder& aBuilder,
-                                 const wr::LayoutRect& aBounds,
-                                 const wr::LayoutRect& aClip,
-                                 wr::ImageRendering aFilter,
-                                 Range<const wr::ImageKey>& aImageKeys) override;
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
 
 protected:
   void CreateRenderTextureHost(const SurfaceDescriptor& aDesc, TextureHost* aTexture);
 
   RefPtr<TextureHost> mWrappedTextureHost;
   wr::ExternalImageId mExternalImageId;
 };
 
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -236,17 +236,17 @@ nsIconChannel::AsyncOpen(nsIStreamListen
       mCallbacks = nullptr;
       return rv;
   }
 
   // Init our stream pump
   nsCOMPtr<nsIEventTarget> target =
       nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo,
                                                mozilla::TaskCategory::Other);
-  rv = mPump->Init(inStream, int64_t(-1), int64_t(-1), 0, 0, false, target);
+  rv = mPump->Init(inStream, 0, 0, false, target);
   if (NS_FAILED(rv)) {
       mCallbacks = nullptr;
       return rv;
   }
 
   rv = mPump->AsyncRead(this, ctxt);
   if (NS_SUCCEEDED(rv)) {
     // Store our real listener
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -251,17 +251,17 @@ nsIconChannel::AsyncOpen(nsIStreamListen
     mCallbacks = nullptr;
     return rv;
   }
 
   // Init our streampump
   nsCOMPtr<nsIEventTarget> target =
     nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo,
                                              mozilla::TaskCategory::Other);
-  rv = mPump->Init(inStream, int64_t(-1), int64_t(-1), 0, 0, false, target);
+  rv = mPump->Init(inStream, 0, 0, false, target);
   if (NS_FAILED(rv)) {
     mCallbacks = nullptr;
     return rv;
   }
 
   rv = mPump->AsyncRead(this, ctxt);
   if (NS_SUCCEEDED(rv)) {
     // Store our real listener
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -623,24 +623,25 @@ BackgroundChildImpl::RecvDispatchLocalSt
 
   LocalStorage::DispatchStorageEvent(aDocumentURI, aKey, aOldValue, aNewValue,
                                      principal, aIsPrivate, nullptr, true);
 
   return IPC_OK();
 }
 
 bool
-BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, nsTArray<RefPtr<SchedulerGroup>>& aGroups)
+BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
 {
   if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
     MOZ_ASSERT(NS_IsMainThread());
     aGroups.Clear();
     if (dom::TabChild::HasActiveTabs()) {
-      for (dom::TabChild* tabChild : dom::TabChild::GetActiveTabs()) {
-        aGroups.AppendElement(tabChild->TabGroup());
+      for (auto iter = dom::TabChild::GetActiveTabs().ConstIter();
+           !iter.Done(); iter.Next()) {
+        aGroups.Put(iter.Get()->GetKey()->TabGroup());
       }
     }
     return true;
   }
 
   return false;
 }
 
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -219,17 +219,17 @@ protected:
   RecvDispatchLocalStorageChange(const nsString& aDocumentURI,
                                  const nsString& aKey,
                                  const nsString& aOldValue,
                                  const nsString& aNewValue,
                                  const PrincipalInfo& aPrincipalInfo,
                                  const bool& aIsPrivate) override;
 
   bool
-  GetMessageSchedulerGroups(const Message& aMsg, nsTArray<RefPtr<SchedulerGroup>>& aGroups) override;
+  GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups) override;
 };
 
 class BackgroundChildImpl::ThreadLocal final
 {
   friend class nsAutoPtr<ThreadLocal>;
 
 public:
   nsAutoPtr<mozilla::dom::indexedDB::ThreadLocal> mIndexedDBThreadLocal;
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -1013,17 +1013,17 @@ MessageChannel::SendBuildID()
 
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
     // Don't check for MSG_ROUTING_NONE.
 
     MonitorAutoLock lock(*mMonitor);
     if (!Connected()) {
         ReportConnectionError("MessageChannel", msg);
-        MOZ_CRASH();
+        return;
     }
     mLink->SendMessage(msg.forget());
 }
 
 class CancelMessage : public IPC::Message
 {
 public:
     explicit CancelMessage(int transaction) :
@@ -1997,17 +1997,17 @@ MessageChannel::MessageTask::GetPriority
   default:
     MOZ_ASSERT(false);
     break;
   }
   return NS_OK;
 }
 
 bool
-MessageChannel::MessageTask::GetAffectedSchedulerGroups(nsTArray<RefPtr<SchedulerGroup>>& aGroups)
+MessageChannel::MessageTask::GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups)
 {
     if (!mChannel) {
         return false;
     }
 
     mChannel->AssertWorkerThread();
     return mChannel->mListener->GetMessageSchedulerGroups(mMessage, aGroups);
 }
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -559,17 +559,17 @@ class MessageChannel : HasResultCodes, M
         void Post();
         void Clear();
 
         bool IsScheduled() const { return mScheduled; }
 
         Message& Msg() { return mMessage; }
         const Message& Msg() const { return mMessage; }
 
-        bool GetAffectedSchedulerGroups(nsTArray<RefPtr<SchedulerGroup>>& aGroups) override;
+        bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override;
 
     private:
         MessageTask() = delete;
         MessageTask(const MessageTask&) = delete;
         ~MessageTask() {}
 
         MessageChannel* mChannel;
         Message mMessage;
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -24,16 +24,17 @@
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/UniquePtr.h"
 #include "MainThreadUtils.h"
+#include "nsILabelableRunnable.h"
 
 #if defined(ANDROID) && defined(DEBUG)
 #include <android/log.h>
 #endif
 
 template<typename T> class nsTHashtable;
 template<typename T> class nsPtrHashKey;
 
@@ -263,16 +264,18 @@ class IToplevelProtocol : public IProtoc
 {
     template<class PFooSide> friend class Endpoint;
 
 protected:
     explicit IToplevelProtocol(ProtocolId aProtoId, Side aSide);
     ~IToplevelProtocol();
 
 public:
+    using SchedulerGroupSet = nsILabelableRunnable::SchedulerGroupSet;
+
     void SetTransport(UniquePtr<Transport> aTrans)
     {
         mTrans = Move(aTrans);
     }
 
     Transport* GetTransport() const { return mTrans.get(); }
 
     ProtocolId GetProtocolId() const { return mProtocolId; }
@@ -383,17 +386,17 @@ public:
     virtual void ProcessRemoteNativeEventsInInterruptCall() {
     }
 
     // Override this method in top-level protocols to change the SchedulerGroups
     // that a message might affect. This should be used only as a last resort
     // when it's difficult to determine an EventTarget ahead of time. See the
     // comment in nsILabelableRunnable.h for more information.
     virtual bool
-    GetMessageSchedulerGroups(const Message& aMsg, nsTArray<RefPtr<SchedulerGroup>>& aGroups)
+    GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
     {
         return false;
     }
 
     virtual already_AddRefed<nsIEventTarget>
     GetMessageEventTarget(const Message& aMsg);
 
     already_AddRefed<nsIEventTarget>
--- a/js/public/GCPolicyAPI.h
+++ b/js/public/GCPolicyAPI.h
@@ -126,17 +126,17 @@ struct GCPointerPolicy
             js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name);
     }
     static bool needsSweep(T* vp) {
         if (*vp)
             return js::gc::IsAboutToBeFinalizedUnbarriered(vp);
         return false;
     }
     static bool isValid(T v) {
-        return js::gc::IsCellPointerValid(v);
+        return js::gc::IsCellPointerValidOrNull(v);
     }
 };
 template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
 template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
 template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
 template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};
 template <> struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {};
 template <> struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {};
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -401,29 +401,35 @@ IsInsideNursery(const js::gc::Cell* cell
     auto location = detail::GetCellLocation(cell);
     MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap);
     return location == ChunkLocation::Nursery;
 }
 
 MOZ_ALWAYS_INLINE bool
 IsCellPointerValid(const void* cell)
 {
-    if (!cell)
-        return true;
     auto addr = uintptr_t(cell);
     if (addr < ChunkSize || addr % CellAlignBytes != 0)
         return false;
     auto location = detail::GetCellLocation(cell);
     if (location == ChunkLocation::TenuredHeap)
         return !!detail::GetGCThingZone(addr);
     if (location == ChunkLocation::Nursery)
         return detail::NurseryCellHasStoreBuffer(cell);
     return false;
 }
 
+MOZ_ALWAYS_INLINE bool
+IsCellPointerValidOrNull(const void* cell)
+{
+    if (!cell)
+        return true;
+    return IsCellPointerValid(cell);
+}
+
 } /* namespace gc */
 } /* namespace js */
 
 namespace JS {
 
 static MOZ_ALWAYS_INLINE Zone*
 GetTenuredGCThingZone(GCCellPtr thing)
 {
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -397,17 +397,17 @@ class TenuredHeap : public js::HeapBase<
         static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
                       "TenuredHeap<T> must be binary compatible with T.");
     }
     explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
     explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) { setPtr(p.getPtr()); }
 
     void setPtr(T newPtr) {
         MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
-        MOZ_ASSERT(js::gc::IsCellPointerValid(newPtr));
+        MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr));
         if (newPtr)
             AssertGCThingMustBeTenured(newPtr);
         bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr);
     }
 
     void setFlags(uintptr_t flagsToSet) {
         MOZ_ASSERT((flagsToSet & ~flagsMask) == 0);
         bits |= flagsToSet;
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -312,19 +312,18 @@ function ModuleInstantiate()
                    "Bad module status after failed instantiation");
 
             RecordModuleError(m, error);
         }
 
         if (stack.length === 0 &&
             typeof(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT)) === "undefined")
         {
-            // This can happen due to OOM when appending to the stack.
-            assert(error === "out of memory",
-                   "Stack must contain module unless we hit OOM");
+            // This can happen due to OOM when appending to the stack or
+            // over-recursion errors.
             RecordModuleError(module, error);
         }
 
         assert(module.status === MODULE_STATUS_ERRORED,
                "Bad module status after failed instantiation");
         assert(SameValue(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT), error),
                "Module has different error set after failed instantiation");
 
@@ -537,19 +536,18 @@ function ModuleEvaluate()
                    "Bad module status after failed evaluation");
 
             RecordModuleError(m, error);
         }
 
         if (stack.length === 0 &&
             typeof(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT)) === "undefined")
         {
-            // This can happen due to OOM when appending to the stack.
-            assert(error === "out of memory",
-                  "Stack must contain module unless we hit OOM");
+            // This can happen due to OOM when appending to the stack or
+            // over-recursion errors.
             RecordModuleError(module, error);
         }
 
         assert(module.status === MODULE_STATUS_ERRORED,
                "Bad module status after failed evaluation");
         assert(SameValue(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT), error),
                "Module has different error set after failed evaluation");
 
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/ModuleObject.h"
 
+#include "mozilla/EnumSet.h"
+
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/ParseNode.h"
 #include "frontend/SharedContext.h"
 #include "gc/Policy.h"
 #include "gc/Tracer.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
 
@@ -884,39 +886,51 @@ ModuleObject::Freeze(JSContext* cx, Hand
            FreezeObjectProperty(cx, self, IndirectExportEntriesSlot) &&
            FreezeObjectProperty(cx, self, StarExportEntriesSlot) &&
            FreezeObject(cx, self);
 }
 
 #ifdef DEBUG
 
 static inline bool
-IsObjectFrozen(JSContext* cx, HandleObject obj)
+CheckObjectFrozen(JSContext* cx, HandleObject obj, bool* result)
 {
-    bool frozen = false;
-    MOZ_ALWAYS_TRUE(TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, &frozen));
-    return frozen;
+    return TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, result);
 }
 
 static inline bool
-IsObjectPropertyFrozen(JSContext* cx, HandleNativeObject obj, uint32_t slot)
+CheckObjectPropertyFrozen(JSContext* cx, HandleNativeObject obj, uint32_t slot, bool* result)
 {
     RootedObject property(cx, &obj->getSlot(slot).toObject());
-    return IsObjectFrozen(cx, property);
+    return CheckObjectFrozen(cx, property, result);
 }
 
 /* static */ inline bool
-ModuleObject::IsFrozen(JSContext* cx, HandleModuleObject self)
+ModuleObject::AssertFrozen(JSContext* cx, HandleModuleObject self)
 {
-    return IsObjectPropertyFrozen(cx, self, RequestedModulesSlot) &&
-           IsObjectPropertyFrozen(cx, self, ImportEntriesSlot) &&
-           IsObjectPropertyFrozen(cx, self, LocalExportEntriesSlot) &&
-           IsObjectPropertyFrozen(cx, self, IndirectExportEntriesSlot) &&
-           IsObjectPropertyFrozen(cx, self, StarExportEntriesSlot) &&
-           IsObjectFrozen(cx, self);
+    static const mozilla::EnumSet<ModuleSlot> slotsToCheck = {
+        RequestedModulesSlot,
+        ImportEntriesSlot,
+        LocalExportEntriesSlot,
+        IndirectExportEntriesSlot,
+        StarExportEntriesSlot
+    };
+
+    bool frozen = false;
+    for (auto slot : slotsToCheck) {
+        if (!CheckObjectPropertyFrozen(cx, self, slot, &frozen))
+            return false;
+        MOZ_ASSERT(frozen);
+    }
+
+    if (!CheckObjectFrozen(cx, self, &frozen))
+        return false;
+    MOZ_ASSERT(frozen);
+
+    return true;
 }
 
 #endif
 
 inline static void
 AssertModuleScopesMatch(ModuleObject* module)
 {
     MOZ_ASSERT(module->enclosingScope()->is<GlobalScope>());
@@ -1029,17 +1043,20 @@ ModuleObject::noteFunctionDeclaration(JS
     }
 
     return true;
 }
 
 /* static */ bool
 ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self)
 {
-    MOZ_ASSERT(IsFrozen(cx, self));
+#ifdef DEBUG
+    if (!AssertFrozen(cx, self))
+        return false;
+#endif
 
     FunctionDeclarationVector* funDecls = self->functionDeclarations();
     if (!funDecls) {
         JS_ReportErrorASCII(cx, "Module function declarations have already been instantiated");
         return false;
     }
 
     RootedModuleEnvironmentObject env(cx, &self->initialEnvironment());
@@ -1056,30 +1073,36 @@ ModuleObject::instantiateFunctionDeclara
         if (fun->isAsync()) {
             if (fun->isStarGenerator()) {
                 obj = WrapAsyncGenerator(cx, obj.as<JSFunction>());
             } else {
                 obj = WrapAsyncFunction(cx, obj.as<JSFunction>());
             }
         }
 
+        if (!obj)
+            return false;
+
         value = ObjectValue(*obj);
         if (!SetProperty(cx, env, funDecl.name->asPropertyName(), value))
             return false;
     }
 
     js_delete(funDecls);
     self->setReservedSlot(FunctionDeclarationsSlot, UndefinedValue());
     return true;
 }
 
 /* static */ bool
 ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval)
 {
-    MOZ_ASSERT(IsFrozen(cx, self));
+#ifdef DEBUG
+    if (!AssertFrozen(cx, self))
+        return false;
+#endif
 
     RootedScript script(cx, self->script());
     RootedModuleEnvironmentObject scope(cx, self->environment());
     if (!scope) {
         JS_ReportErrorASCII(cx, "Module declarations have not yet been instantiated");
         return false;
     }
 
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -231,17 +231,17 @@ struct FunctionDeclaration
 using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>;
 
 // Possible values for ModuleStatus are defined in SelfHostingDefines.h.
 using ModuleStatus = int32_t;
 
 class ModuleObject : public NativeObject
 {
   public:
-    enum
+    enum ModuleSlot
     {
         ScriptSlot = 0,
         InitialEnvironmentSlot,
         EnvironmentSlot,
         NamespaceSlot,
         StatusSlot,
         ErrorSlot,
         HostDefinedSlot,
@@ -279,17 +279,17 @@ class ModuleObject : public NativeObject
     void setInitialEnvironment(Handle<ModuleEnvironmentObject*> initialEnvironment);
     void initImportExportData(HandleArrayObject requestedModules,
                               HandleArrayObject importEntries,
                               HandleArrayObject localExportEntries,
                               HandleArrayObject indiretExportEntries,
                               HandleArrayObject starExportEntries);
     static bool Freeze(JSContext* cx, HandleModuleObject self);
 #ifdef DEBUG
-    static bool IsFrozen(JSContext* cx, HandleModuleObject self);
+    static bool AssertFrozen(JSContext* cx, HandleModuleObject self);
 #endif
     void fixEnvironmentsAfterCompartmentMerge();
 
     JSScript* script() const;
     Scope* enclosingScope() const;
     ModuleEnvironmentObject& initialEnvironment() const;
     ModuleEnvironmentObject* environment() const;
     ModuleNamespaceObject* namespace_();
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -6115,17 +6115,17 @@ StructType::DefineInternal(JSContext* cx
       SetFunctionNativeReserved(setter, StructType::SLOT_FIELDNAME,
                                 StringValue(JS_FORGET_STRING_FLATNESS(name)));
       RootedObject setterObj(cx, JS_GetFunctionObject(setter));
 
       if (!JS_DefineUCProperty(cx, prototype,
              nameChars.twoByteChars(), name->length(),
              JS_DATA_TO_FUNC_PTR(JSNative, getterObj.get()),
              JS_DATA_TO_FUNC_PTR(JSNative, setterObj.get()),
-             JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER))
+             JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER))
       {
         return false;
       }
 
       size_t fieldSize = CType::GetSize(fieldType);
       size_t fieldAlign = CType::GetAlignment(fieldType);
       size_t fieldOffset = Align(structSize, fieldAlign);
       // Check for overflow. Since we hold invariant that fieldSize % fieldAlign
--- a/js/src/gc/Policy.h
+++ b/js/src/gc/Policy.h
@@ -122,17 +122,17 @@ struct InternalGCPointerPolicy {
     static T initial() { return nullptr; }
     static void preBarrier(T v) { Type::writeBarrierPre(v); }
     static void postBarrier(T* vp, T prev, T next) { Type::writeBarrierPost(vp, prev, next); }
     static void readBarrier(T v) { Type::readBarrier(v); }
     static void trace(JSTracer* trc, T* vp, const char* name) {
         TraceManuallyBarrieredEdge(trc, vp, name);
     }
     static bool isValid(T v) {
-        return gc::IsCellPointerValid(v);
+        return gc::IsCellPointerValidOrNull(v);
     }
 };
 
 } // namespace js
 
 namespace JS {
 
 #define DEFINE_INTERNAL_GC_POLICY(type) \
--- a/js/src/gc/ZoneGroup.cpp
+++ b/js/src/gc/ZoneGroup.cpp
@@ -60,17 +60,17 @@ ZoneGroup::~ZoneGroup()
 }
 
 void
 ZoneGroup::enter(JSContext* cx)
 {
     if (ownerContext().context() == cx) {
         MOZ_ASSERT(enterCount);
     } else {
-        if (useExclusiveLocking) {
+        if (useExclusiveLocking()) {
             MOZ_ASSERT(!usedByHelperThread());
             while (ownerContext().context() != nullptr) {
                 cx->yieldToEmbedding();
             }
         }
         MOZ_RELEASE_ASSERT(ownerContext().context() == nullptr);
         MOZ_ASSERT(enterCount == 0);
         ownerContext_ = CooperatingContext(cx);
--- a/js/src/gc/ZoneGroup.h
+++ b/js/src/gc/ZoneGroup.h
@@ -38,17 +38,17 @@ class ZoneGroup
     // The context with exclusive access to this zone group.
     UnprotectedData<CooperatingContext> ownerContext_;
 
     // The number of times the context has entered this zone group.
     UnprotectedData<size_t> enterCount;
 
     // If this flag is true, then we may need to block before entering this zone
     // group. Blocking happens using JSContext::yieldToEmbedding.
-    UnprotectedData<bool> useExclusiveLocking;
+    UnprotectedData<bool> useExclusiveLocking_;
 
   public:
     CooperatingContext& ownerContext() { return ownerContext_.ref(); }
     void* addressOfOwnerContext() { return &ownerContext_.ref().cx; }
 
     void enter(JSContext* cx);
     void leave();
     bool ownedByCurrentThread();
@@ -97,18 +97,19 @@ class ZoneGroup
     bool init();
 
     inline Nursery& nursery();
     inline gc::StoreBuffer& storeBuffer();
 
     inline bool isCollecting();
     inline bool isGCScheduled();
 
-    // See the useExclusiveLocking field above.
-    void setUseExclusiveLocking() { useExclusiveLocking = true; }
+    // See the useExclusiveLocking_ field above.
+    void setUseExclusiveLocking() { useExclusiveLocking_ = true; }
+    bool useExclusiveLocking() { return useExclusiveLocking_; }
 
     // Delete an empty zone after its contents have been merged.
     void deleteEmptyZone(Zone* zone);
 
 #ifdef DEBUG
   private:
     // The number of possible bailing places encounters before forcefully bailing
     // in that place. Zero means inactive.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1402535.js
@@ -0,0 +1,7 @@
+if (!('stackTest' in this))
+   quit();
+
+stackTest(function() {
+    let m = parseModule(``);
+    m.declarationInstantiation();
+});
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1402649.js
@@ -0,0 +1,15 @@
+if (!('oomTest' in this))
+   quit();
+
+loadFile(`
+function parseAndEvaluate(source) {
+    let m = parseModule(source);
+    m.declarationInstantiation();
+}
+parseAndEvaluate("async function a() { await 2 + 3; }")
+`);
+function loadFile(lfVarx) {
+    oomTest(function() {
+        eval(lfVarx);
+    });
+}
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
+++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
@@ -31,22 +31,22 @@ BEGIN_TEST(testDefineGetterSetterNonEnum
     CHECK(funSet);
     JS::RootedObject funSetObj(cx, JS_GetFunctionObject(funSet));
     JS::RootedValue vset(cx, JS::ObjectValue(*funSetObj));
 
     JS::RootedObject vObject(cx, vobj.toObjectOrNull());
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
                             JS_DATA_TO_FUNC_PTR(JSNative, (JSObject*) funGetObj),
                             JS_DATA_TO_FUNC_PTR(JSNative, (JSObject*) funSetObj),
-                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED | JSPROP_ENUMERATE));
+                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE));
 
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
                             JS_DATA_TO_FUNC_PTR(JSNative, (JSObject*) funGetObj),
                             JS_DATA_TO_FUNC_PTR(JSNative, (JSObject*) funSetObj),
-                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED | JSPROP_PERMANENT));
+                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_PERMANENT));
 
     JS::Rooted<JS::PropertyDescriptor> desc(cx);
     CHECK(JS_GetOwnPropertyDescriptor(cx, vObject, PROPERTY_NAME, &desc));
     CHECK(desc.object());
     CHECK(desc.hasGetterObject());
     CHECK(desc.hasSetterObject());
     CHECK(!desc.configurable());
     CHECK(!desc.enumerable());
--- a/js/src/jsapi-tests/testDefineProperty.cpp
+++ b/js/src/jsapi-tests/testDefineProperty.cpp
@@ -12,12 +12,12 @@ BEGIN_TEST(testDefineProperty_bug564344)
     JS::RootedValue x(cx);
     EVAL("function f() {}\n"
          "var x = {p: f};\n"
          "x.p();  // brand x's scope\n"
          "x;", &x);
 
     JS::RootedObject obj(cx, x.toObjectOrNull());
     for (int i = 0; i < 2; i++)
-        CHECK(JS_DefineProperty(cx, obj, "q", JS::UndefinedHandleValue, JSPROP_SHARED));
+        CHECK(JS_DefineProperty(cx, obj, "q", JS::UndefinedHandleValue, 0));
     return true;
 }
 END_TEST(testDefineProperty_bug564344)
--- a/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp
+++ b/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp
@@ -42,35 +42,35 @@ BEGIN_TEST(testDefinePropertyIgnoredAttr
     JS::Rooted<JS::PropertyDescriptor> desc(cx);
     JS::RootedValue defineValue(cx);
 
     // Try a getter. Allow it to fill in the defaults. Because we're passing a
     // JSNative, JS_DefineProperty will infer JSPROP_GETTER even though we
     // aren't passing it.
     CHECK(JS_DefineProperty(cx, obj, "foo",
                             Getter, nullptr,
-                            JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_PERMANENT | JSPROP_SHARED));
+                            JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_PERMANENT));
 
     CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "foo", &desc));
 
     // Note that JSPROP_READONLY is meaningless for accessor properties.
     CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, false));
 
     // Install another configurable property, so we can futz with it.
     CHECK(JS_DefineProperty(cx, obj, "bar",
                             Getter, nullptr,
-                            JSPROP_IGNORE_ENUMERATE | JSPROP_SHARED));
+                            JSPROP_IGNORE_ENUMERATE));
     CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc));
     CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, true));
 
     // Rewrite the descriptor to now be enumerable, leaving the configurability
     // unchanged.
     CHECK(JS_DefineProperty(cx, obj, "bar",
                             Getter, nullptr,
-                            JSPROP_IGNORE_PERMANENT | JSPROP_ENUMERATE | JSPROP_SHARED));
+                            JSPROP_IGNORE_PERMANENT | JSPROP_ENUMERATE));
     CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc));
     CHECK(CheckDescriptor(desc, AccessorDescriptor, true, true, true));
 
     // Now try the same game with a value property
     defineValue.setObject(*obj);
     CHECK(JS_DefineProperty(cx, obj, "baz", defineValue,
                             JSPROP_IGNORE_ENUMERATE |
                             JSPROP_IGNORE_READONLY |
--- a/js/src/jsapi-tests/testSetProperty.cpp
+++ b/js/src/jsapi-tests/testSetProperty.cpp
@@ -11,17 +11,17 @@ BEGIN_TEST(testSetProperty_NativeGetterS
 {
     JS::RootedObject obj(cx, JS_NewPlainObject(cx));
     CHECK(obj);
 
     CHECK(JS_DefineProperty(cx, global, "globalProp", obj, JSPROP_ENUMERATE));
 
     CHECK(JS_DefineProperty(cx, obj, "prop",
                             JS_PROPERTYOP_GETTER(NativeGet), nullptr,
-                            JSPROP_SHARED | JSPROP_PROPOP_ACCESSORS));
+                            JSPROP_PROPOP_ACCESSORS));
 
     EXEC("'use strict';                                     \n"
          "var error, passed = false;                        \n"
          "try                                               \n"
          "{                                                 \n"
          "  this.globalProp.prop = 42;                      \n"
          "  throw new Error('setting property succeeded!'); \n"
          "}                                                 \n"
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -870,21 +870,16 @@ static const uint8_t JSPROP_PERMANENT = 
 static const uint8_t JSPROP_PROPOP_ACCESSORS = 0x08;
 
 /* property holds getter function */
 static const uint8_t JSPROP_GETTER =           0x10;
 
 /* property holds setter function */
 static const uint8_t JSPROP_SETTER =           0x20;
 
-/* don't allocate a value slot for this property; don't copy the property on set
-   of the same-named property in an object that delegates to a prototype
-   containing this property */
-static const uint8_t JSPROP_SHARED =           0x40;
-
 /* internal JS engine use only */
 static const uint8_t JSPROP_INTERNAL_USE_BIT = 0x80;
 
 /* native that can be called as a ctor */
 static const unsigned JSFUN_CONSTRUCTOR =     0x400;
 
 /* | of all the JSFUN_* flags */
 static const unsigned JSFUN_FLAGS_MASK =      0x400;
@@ -2273,33 +2268,33 @@ inline int CheckIsSetterOp(JSSetterOp op
 
 /*
  * JSPropertySpec uses JSNativeWrapper.  These macros encapsulate the definition
  * of JSNative-backed JSPropertySpecs, by defining the JSNativeWrappers for
  * them.
  */
 #define JS_PSG(name, getter, flags) \
     JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, \
-                        JSPROP_SHARED)
+                        0)
 #define JS_PSGS(name, getter, setter, flags) \
     JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \
-                         JSPROP_SHARED)
+                        0)
 #define JS_SYM_GET(symbol, getter, flags) \
     JS_PS_ACCESSOR_SPEC(reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
-                        JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, JSPROP_SHARED)
+                        JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, 0)
 #define JS_SELF_HOSTED_GET(name, getterName, flags) \
     JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \
-                         JSPROP_SHARED | JSPROP_GETTER)
+                        JSPROP_GETTER)
 #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \
     JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), SELFHOSTED_WRAPPER(setterName), \
-                         flags, JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER)
+                         flags, JSPROP_GETTER | JSPROP_SETTER)
 #define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \
     JS_PS_ACCESSOR_SPEC(reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
                          SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \
-                         JSPROP_SHARED | JSPROP_GETTER)
+                         JSPROP_GETTER)
 #define JS_STRING_PS(name, string, flags) \
     JS_PS_VALUE_SPEC(name, STRINGVALUE_WRAPPER(string), flags)
 #define JS_STRING_SYM_PS(symbol, string, flags) \
     JS_PS_VALUE_SPEC(reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
                      STRINGVALUE_WRAPPER(string), flags)
 #define JS_INT32_PS(name, value, flags) \
     JS_PS_VALUE_SPEC(name, INT32VALUE_WRAPPER(value), flags)
 #define JS_PS_END \
@@ -2859,41 +2854,38 @@ class WrappedPtrOperations<JS::PropertyD
     bool hasSetterObject() const { return has(JSPROP_SETTER); }
     JS::HandleObject setterObject() const {
         MOZ_ASSERT(hasSetterObject());
         return JS::HandleObject::fromMarkedLocation(
                 reinterpret_cast<JSObject* const*>(&desc().setter));
     }
 
     bool hasGetterOrSetter() const { return desc().getter || desc().setter; }
-    bool isShared() const { return has(JSPROP_SHARED); }
 
     JS::HandleObject object() const {
         return JS::HandleObject::fromMarkedLocation(&desc().obj);
     }
     unsigned attributes() const { return desc().attrs; }
     JSGetterOp getter() const { return desc().getter; }
     JSSetterOp setter() const { return desc().setter; }
 
     void assertValid() const {
 #ifdef DEBUG
         MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE |
                                      JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT |
                                      JSPROP_READONLY | JSPROP_IGNORE_READONLY |
                                      JSPROP_IGNORE_VALUE |
                                      JSPROP_GETTER |
                                      JSPROP_SETTER |
-                                     JSPROP_SHARED |
                                      JSPROP_REDEFINE_NONCONFIGURABLE |
                                      JSPROP_RESOLVING |
                                      SHADOWABLE)) == 0);
         MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE));
         MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT));
         if (isAccessorDescriptor()) {
-            MOZ_ASSERT(has(JSPROP_SHARED));
             MOZ_ASSERT(!has(JSPROP_READONLY));
             MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY));
             MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE));
             MOZ_ASSERT(!has(SHADOWABLE));
             MOZ_ASSERT(value().isUndefined());
             MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter());
             MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter());
         } else {
@@ -2912,17 +2904,16 @@ class WrappedPtrOperations<JS::PropertyD
     void assertComplete() const {
 #ifdef DEBUG
         assertValid();
         MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE |
                                      JSPROP_PERMANENT |
                                      JSPROP_READONLY |
                                      JSPROP_GETTER |
                                      JSPROP_SETTER |
-                                     JSPROP_SHARED |
                                      JSPROP_REDEFINE_NONCONFIGURABLE |
                                      JSPROP_RESOLVING |
                                      SHADOWABLE)) == 0);
         MOZ_ASSERT_IF(isAccessorDescriptor(), has(JSPROP_GETTER) && has(JSPROP_SETTER));
 #endif
     }
 
     void assertCompleteIfFound() const {
@@ -3013,22 +3004,22 @@ class MutableWrappedPtrOperations<JS::Pr
         desc().getter = op;
     }
     void setSetter(JSSetterOp op) {
         desc().setter = op;
     }
     void setGetterObject(JSObject* obj) {
         desc().getter = reinterpret_cast<JSGetterOp>(obj);
         desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY);
-        desc().attrs |= JSPROP_GETTER | JSPROP_SHARED;
+        desc().attrs |= JSPROP_GETTER;
     }
     void setSetterObject(JSObject* obj) {
         desc().setter = reinterpret_cast<JSSetterOp>(obj);
         desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY);
-        desc().attrs |= JSPROP_SETTER | JSPROP_SHARED;
+        desc().attrs |= JSPROP_SETTER;
     }
 
     JS::MutableHandleObject getterObject() {
         MOZ_ASSERT(this->hasGetterObject());
         return JS::MutableHandleObject::fromMarkedLocation(
                 reinterpret_cast<JSObject**>(&desc().getter));
     }
     JS::MutableHandleObject setterObject() {
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1042,17 +1042,17 @@ AddLengthProperty(JSContext* cx, HandleA
      * as accesses to 'length' will use the elements header.
      */
 
     RootedId lengthId(cx, NameToId(cx->names().length));
     MOZ_ASSERT(!obj->lookup(cx, lengthId));
 
     return NativeObject::addProperty(cx, obj, lengthId, array_length_getter, array_length_setter,
                                      SHAPE_INVALID_SLOT,
-                                     JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_SHADOWABLE,
+                                     JSPROP_PERMANENT | JSPROP_SHADOWABLE,
                                      0, /* allowDictionary = */ false);
 }
 
 static bool
 IsArrayConstructor(const JSObject* obj)
 {
     // This must only return true if v is *the* Array constructor for the
     // current compartment; we rely on the fact that any other Array
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -8076,23 +8076,29 @@ JS::AssertGCThingIsNotAnObjectSubclass(C
 {
     MOZ_ASSERT(cell);
     MOZ_ASSERT(cell->getTraceKind() != JS::TraceKind::Object);
 }
 
 JS_FRIEND_API(void)
 js::gc::AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind)
 {
-    MOZ_ASSERT(IsCellPointerValid(cell));
-    if (!cell)
+    if (!cell) {
         MOZ_ASSERT(kind == JS::TraceKind::Null);
-    else if (IsInsideNursery(cell))
+        return;
+    }
+
+    MOZ_ASSERT(IsCellPointerValid(cell));
+
+    if (IsInsideNursery(cell)) {
         MOZ_ASSERT(kind == JS::TraceKind::Object);
-    else
-        MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured().getAllocKind()) == kind);
+        return;
+    }
+
+    MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured().getAllocKind()) == kind);
 }
 #endif
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 
 JS::AutoAssertNoGC::AutoAssertNoGC(JSContext* maybecx)
   : cx_(maybecx ? maybecx : TlsContext.get())
 {
@@ -8646,17 +8652,17 @@ NewMemoryInfoObject(JSContext* cx)
     for (auto pair : getters) {
 #ifdef JS_MORE_DETERMINISTIC
         JSNative getter = DummyGetter;
 #else
         JSNative getter = pair.getter;
 #endif
         if (!JS_DefineProperty(cx, obj, pair.name,
                                getter, nullptr,
-                               JSPROP_ENUMERATE | JSPROP_SHARED))
+                               JSPROP_ENUMERATE))
         {
             return nullptr;
         }
     }
 
     RootedObject zoneObj(cx, JS_NewObject(cx, nullptr));
     if (!zoneObj)
         return nullptr;
@@ -8681,17 +8687,17 @@ NewMemoryInfoObject(JSContext* cx)
     for (auto pair : zoneGetters) {
  #ifdef JS_MORE_DETERMINISTIC
         JSNative getter = DummyGetter;
 #else
         JSNative getter = pair.getter;
 #endif
         if (!JS_DefineProperty(cx, zoneObj, pair.name,
                                getter, nullptr,
-                               JSPROP_ENUMERATE | JSPROP_SHARED))
+                               JSPROP_ENUMERATE))
         {
             return nullptr;
         }
     }
 
     return obj;
 }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -356,17 +356,17 @@ js::ToPropertyDescriptor(JSContext* cx, 
             if (checkAccessors)
                 JS_TRY_OR_RETURN_FALSE(cx, CheckCallable(cx, &v.toObject(), js_getter_str));
             desc.setGetterObject(&v.toObject());
         } else if (!v.isUndefined()) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
                                       js_getter_str);
             return false;
         }
-        attrs |= JSPROP_GETTER | JSPROP_SHARED;
+        attrs |= JSPROP_GETTER;
     }
 
     // step 9
     id = NameToId(cx->names().set);
     if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
         return false;
     hasGetOrSet |= found;
     if (found) {
@@ -374,33 +374,32 @@ js::ToPropertyDescriptor(JSContext* cx, 
             if (checkAccessors)
                 JS_TRY_OR_RETURN_FALSE(cx, CheckCallable(cx, &v.toObject(), js_setter_str));
             desc.setSetterObject(&v.toObject());
         } else if (!v.isUndefined()) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
                                       js_setter_str);
             return false;
         }
-        attrs |= JSPROP_SETTER | JSPROP_SHARED;
+        attrs |= JSPROP_SETTER;
     }
 
     // step 10
     if (hasGetOrSet) {
         if (!(attrs & JSPROP_IGNORE_READONLY) || !(attrs & JSPROP_IGNORE_VALUE)) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INVALID_DESCRIPTOR);
             return false;
         }
 
         // By convention, these bits are not used on accessor descriptors.
         attrs &= ~(JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
     }
 
     desc.setAttributes(attrs);
     MOZ_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
-    MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
     return true;
 }
 
 Result<>
 js::CheckPropertyDescriptorAccessors(JSContext* cx, Handle<PropertyDescriptor> desc)
 {
     if (desc.hasGetterObject())
         MOZ_TRY(CheckCallable(cx, desc.getterObject(), js_getter_str));
@@ -420,17 +419,17 @@ js::CompletePropertyDescriptor(MutableHa
         if (!desc.hasWritable())
             desc.attributesRef() |= JSPROP_READONLY;
         desc.attributesRef() &= ~(JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
     } else {
         if (!desc.hasGetterObject())
             desc.setGetterObject(nullptr);
         if (!desc.hasSetterObject())
             desc.setSetterObject(nullptr);
-        desc.attributesRef() |= JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
+        desc.attributesRef() |= JSPROP_GETTER | JSPROP_SETTER;
     }
     if (!desc.hasConfigurable())
         desc.attributesRef() |= JSPROP_PERMANENT;
     desc.attributesRef() &= ~(JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_ENUMERATE);
 
     desc.assertComplete();
 }
 
@@ -3521,17 +3520,16 @@ DumpProperty(const NativeObject* obj, Sh
 {
     jsid id = shape.propid();
     uint8_t attrs = shape.attributes();
 
     out.printf("    ((js::Shape*) %p) ", (void*) &shape);
     if (attrs & JSPROP_ENUMERATE) out.put("enumerate ");
     if (attrs & JSPROP_READONLY) out.put("readonly ");
     if (attrs & JSPROP_PERMANENT) out.put("permanent ");
-    if (attrs & JSPROP_SHARED) out.put("shared ");
 
     if (shape.hasGetterValue())
         out.printf("getterValue=%p ", (void*) shape.getterObject());
     else if (!shape.hasDefaultGetter())
         out.printf("getterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.getterOp()));
 
     if (shape.hasSetterValue())
         out.printf("setterValue=%p ", (void*) shape.setterObject());
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1443,16 +1443,19 @@ ConvertTranscodeResultToJSException(JSCo
 
       case JS::TranscodeResult_Throw:
         MOZ_ASSERT(cx->isExceptionPending());
         return false;
     }
 }
 
 static bool
+CooperativeThreadMayYield(JSContext* cx);
+
+static bool
 Evaluate(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() < 1 || args.length() > 2) {
         JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr,
                                   args.length() < 1 ? JSSMSG_NOT_ENOUGH_ARGS : JSSMSG_TOO_MANY_ARGS,
                                   "evaluate");
@@ -1533,24 +1536,35 @@ Evaluate(JSContext* cx, unsigned argc, V
         if (!JS_GetProperty(cx, opts, "zoneGroup", &v))
             return false;
         if (!v.isUndefined()) {
             if (global != JS_GetGlobalForObject(cx, &args.callee())) {
                 JS_ReportErrorASCII(cx, "zoneGroup and global cannot both be specified.");
                 return false;
             }
 
-            // Find all eligible globals to execute in: any global in another
-            // zone group which has not been entered by a cooperative thread.
+            // Find all eligible globals to execute in.
             JS::AutoObjectVector eligibleGlobals(cx);
             for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
-                if (!c->zone()->group()->ownerContext().context() &&
-                    c->maybeGlobal() &&
-                    !cx->runtime()->isSelfHostingGlobal(c->maybeGlobal()))
-                {
+                // Compartments without globals and the self hosting global may
+                // not be entered.
+                if (!c->maybeGlobal() || cx->runtime()->isSelfHostingGlobal(c->maybeGlobal()))
+                    continue;
+
+                // Globals in zone groups which are not in use by a cooperative
+                // thread may be entered.
+                if (!c->zone()->group()->ownerContext().context()) {
+                    if (!eligibleGlobals.append(c->maybeGlobal()))
+                        return false;
+                }
+
+                // Globals in zone groups which use exclusive locking may be
+                // entered, in which case this thread will yield until the zone
+                // group is available.
+                if (c->zone()->group()->useExclusiveLocking() && CooperativeThreadMayYield(cx)) {
                     if (!eligibleGlobals.append(c->maybeGlobal()))
                         return false;
                 }
             }
 
             if (eligibleGlobals.empty()) {
                 JS_ReportErrorASCII(cx, "zoneGroup can only be used if another"
                                     " cooperative thread has called cooperativeYield(true).");
@@ -3332,47 +3346,59 @@ CooperativeYield()
     // is another thread to do so.
     if (cooperationState->numThreads) {
         uint64_t count = cooperationState->yieldCount;
         cooperationState->cvar.wait(lock, [&] { return cooperationState->yieldCount != count; });
     }
 }
 
 static bool
-CooperativeYieldThread(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    if (!cx->runtime()->gc.canChangeActiveContext(cx)) {
-        JS_ReportErrorASCII(cx, "Cooperating multithreading context switches are not currently allowed");
-        return false;
-    }
-
-    if (GetShellContext(cx)->isWorker) {
-        JS_ReportErrorASCII(cx, "Worker threads cannot yield");
-        return false;
-    }
-
-    if (cooperationState->singleThreaded) {
-        JS_ReportErrorASCII(cx, "Yielding is not allowed while single threaded");
-        return false;
-    }
+CooperativeThreadMayYield(JSContext* cx)
+{
+    if (!cx->runtime()->gc.canChangeActiveContext(cx))
+        return false;
+
+    if (GetShellContext(cx)->isWorker)
+        return false;
+
+    if (cooperationState->singleThreaded)
+        return false;
 
     // To avoid contention issues between threads, yields are not allowed while
     // a thread has access to zone groups other than its original one, i.e. if
     // the thread is inside an evaluate() call with a different zone group.
     // This is not a limit which the browser has, but is necessary in the
     // shell: the shell can have arbitrary interleavings between cooperative
     // threads, whereas the browser has more control over which threads are
     // running at different times.
     for (ZoneGroupsIter group(cx->runtime()); !group.done(); group.next()) {
-        if (group->ownerContext().context() == cx && group != cx->zone()->group()) {
-            JS_ReportErrorASCII(cx, "Yielding is not allowed while owning multiple zone groups");
-            return false;
-        }
+        if (group->ownerContext().context() == cx && group != cx->zone()->group())
+            return false;
+    }
+
+    return true;
+}
+
+static void
+CooperativeYieldCallback(JSContext* cx)
+{
+    MOZ_ASSERT(CooperativeThreadMayYield(cx));
+    CooperativeBeginWait(cx);
+    CooperativeYield();
+    CooperativeEndWait(cx);
+}
+
+static bool
+CooperativeYieldThread(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!CooperativeThreadMayYield(cx)) {
+        JS_ReportErrorASCII(cx, "Yielding is not currently allowed");
+        return false;
     }
 
     {
         Maybe<JS::AutoRelinquishZoneGroups> artzg;
         if ((args.length() > 0) && ToBoolean(args[0]))
             artzg.emplace(cx);
 
         CooperativeBeginWait(cx);
@@ -3462,16 +3488,18 @@ WorkerMain(void* arg)
     MOZ_ASSERT(!!input->parentRuntime != !!input->siblingContext);
 
     JSContext* cx = input->parentRuntime
          ? JS_NewContext(8L * 1024L * 1024L, 2L * 1024L * 1024L, input->parentRuntime)
          : JS_NewCooperativeContext(input->siblingContext);
     if (!cx)
         return;
 
+    SetCooperativeYieldCallback(cx, CooperativeYieldCallback);
+
     UniquePtr<ShellContext> sc = MakeUnique<ShellContext>(cx);
     if (!sc)
         return;
 
     auto guard = mozilla::MakeScopeExit([&] {
         if (cx)
             JS_DestroyContext(cx);
         if (input->siblingContext) {
@@ -7268,17 +7296,17 @@ static const JSJitInfo doFoo_methodinfo 
     false,    /* isAlwaysInSlot */
     false,    /* isLazilyCachedInSlot */
     false,    /* isTypedMethod */
     0         /* slotIndex */
 };
 
 static const JSPropertySpec dom_props[] = {
     {"x",
-     JSPROP_SHARED | JSPROP_ENUMERATE,
+     JSPROP_ENUMERATE,
      { {
         { { dom_genericGetter, &dom_x_getterinfo } },
         { { dom_genericSetter, &dom_x_setterinfo } }
      } },
     },
     JS_PS_END
 };
 
@@ -8640,16 +8668,17 @@ main(int argc, char** argv, char** envp)
 #endif
 
     js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
 
     cooperationState = js_new<CooperationState>();
     JS::SetSingleThreadedExecutionCallbacks(cx,
                                             CooperativeBeginSingleThreadedExecution,
                                             CooperativeEndSingleThreadedExecution);
+    SetCooperativeYieldCallback(cx, CooperativeYieldCallback);
 
     result = Shell(cx, &op, envp);
 
 #ifdef DEBUG
     if (OOM_printAllocationCount)
         printf("OOM max count: %" PRIu64 "\n", js::oom::counter);
 #endif
 
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -571,17 +571,17 @@ MappedArgumentsObject::obj_resolve(JSCon
             return true;
 
         if (!DefineArgumentsIterator(cx, argsobj))
             return false;
         *resolvedp = true;
         return true;
     }
 
-    unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE | JSPROP_RESOLVING;
+    unsigned attrs = JSPROP_SHADOWABLE | JSPROP_RESOLVING;
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
         if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->names().length)) {
         if (argsobj->hasOverriddenLength())
@@ -771,34 +771,34 @@ UnmappedArgumentsObject::obj_resolve(JSC
             return true;
 
         if (!DefineArgumentsIterator(cx, argsobj))
             return false;
         *resolvedp = true;
         return true;
     }
 
-    unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
+    unsigned attrs = JSPROP_SHADOWABLE;
     GetterOp getter = UnmappedArgGetter;
     SetterOp setter = UnmappedArgSetter;
 
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
         if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->names().length)) {
         if (argsobj->hasOverriddenLength())
             return true;
     } else {
         if (!JSID_IS_ATOM(id, cx->names().callee))
             return true;
 
-        attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
+        attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER;
         getter = CastAsGetterOp(argsobj->global().getThrowTypeError());
         setter = CastAsSetterOp(argsobj->global().getThrowTypeError());
     }
 
     attrs |= JSPROP_RESOLVING;
     if (!NativeDefineAccessorProperty(cx, argsobj, id, getter, setter, attrs))
         return false;
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -8479,17 +8479,17 @@ DebuggerArguments::create(JSContext* cx,
         getobj = NewNativeFunction(cx, DebuggerArguments_getArg, 0, nullptr,
                                    gc::AllocKind::FUNCTION_EXTENDED);
         if (!getobj)
             return nullptr;
         id = INT_TO_JSID(i);
         if (!getobj ||
             !NativeDefineAccessorProperty(cx, obj, id,
                                           JS_DATA_TO_FUNC_PTR(GetterOp, getobj.get()), nullptr,
-                                          JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER))
+                                          JSPROP_ENUMERATE | JSPROP_GETTER))
         {
             return nullptr;
         }
         getobj->setExtendedSlot(0, Int32Value(i));
     }
 
     return &obj->as<DebuggerArguments>();
 }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4800,20 +4800,20 @@ js::GetInitDataPropAttrs(JSOp op)
 
 bool
 js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleId id,
                               HandleObject val)
 {
     MOZ_ASSERT(val->isCallable());
     GetterOp getter;
     SetterOp setter;
-    unsigned attrs = JSPROP_SHARED;
 
     JSOp op = JSOp(*pc);
 
+    unsigned attrs = 0;
     if (!IsHiddenInitOp(op))
         attrs |= JSPROP_ENUMERATE;
 
     if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER ||
         op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER)
     {
         getter = CastAsGetterOp(val);
         setter = nullptr;
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2059,18 +2059,16 @@ js::NativeGetOwnPropertyDescriptor(JSCon
         return false;
     if (!prop) {
         desc.object().set(nullptr);
         return true;
     }
 
     desc.setAttributes(GetPropertyAttributes(obj, prop));
     if (desc.isAccessorDescriptor()) {
-        MOZ_ASSERT(desc.isShared());
-
         // The result of GetOwnPropertyDescriptor() must be either undefined or
         // a complete property descriptor (per ES6 draft rev 32 (2015 Feb 2)
         // 6.1.7.3, Invariants of the Essential Internal Methods).
         //
         // It is an unfortunate fact that in SM, properties can exist that have
         // JSPROP_GETTER or JSPROP_SETTER but not both. In these cases, rather
         // than return true with desc incomplete, we fill out the missing
         // getter or setter with a null, following CompletePropertyDescriptor.
@@ -2090,17 +2088,16 @@ js::NativeGetOwnPropertyDescriptor(JSCon
         desc.value().setUndefined();
     } else {
         // This is either a straight-up data property or (rarely) a
         // property with a JSGetterOp/JSSetterOp. The latter must be
         // reported to the caller as a plain data property, so clear
         // desc.getter/setter, and mask away the SHARED bit.
         desc.setGetter(nullptr);
         desc.setSetter(nullptr);
-        desc.attributesRef() &= ~JSPROP_SHARED;
 
         if (prop.isDenseOrTypedArrayElement()) {
             desc.value().set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
         } else {
             RootedShape shape(cx, prop.shape());
             if (!NativeGetExistingProperty(cx, obj, obj, shape, desc.value()))
                 return false;
         }
@@ -2134,25 +2131,30 @@ template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
 GetExistingProperty(JSContext* cx,
                     typename MaybeRooted<Value, allowGC>::HandleType receiver,
                     typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
                     typename MaybeRooted<Shape*, allowGC>::HandleType shape,
                     typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
     if (shape->hasSlot()) {
+        MOZ_ASSERT(shape->hasDefaultGetter());
+
         vp.set(obj->getSlot(shape->slot()));
+
         MOZ_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LEXICAL) &&
                       !obj->isSingleton() &&
                       !obj->template is<EnvironmentObject>() &&
                       shape->hasDefaultGetter(),
                       ObjectGroupHasProperty(cx, obj->group(), shape->propid(), vp));
-    } else {
-        vp.setUndefined();
+        return true;
     }
+
+    vp.setUndefined();
+
     if (shape->hasDefaultGetter())
         return true;
 
     {
         jsbytecode* pc;
         JSScript* script = cx->currentScript(&pc);
         if (script && script->hasBaselineScript()) {
             switch (JSOp(*pc)) {
@@ -2165,32 +2167,21 @@ GetExistingProperty(JSContext* cx,
                 break;
             }
         }
     }
 
     if (!allowGC)
         return false;
 
-    if (!CallGetter(cx,
-                    MaybeRooted<JSObject*, allowGC>::toHandle(obj),
-                    MaybeRooted<Value, allowGC>::toHandle(receiver),
-                    MaybeRooted<Shape*, allowGC>::toHandle(shape),
-                    MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
-    {
-        return false;
-    }
-
-    // Ancient nonstandard extension: via the JSAPI it's possible to create a
-    // data property that has both a slot and a getter. In that case, copy the
-    // value returned by the getter back into the slot.
-    if (shape->hasSlot() && obj->contains(cx, shape))
-        obj->setSlot(shape->slot(), vp);
-
-    return true;
+    return CallGetter(cx,
+                      MaybeRooted<JSObject*, allowGC>::toHandle(obj),
+                      MaybeRooted<Value, allowGC>::toHandle(receiver),
+                      MaybeRooted<Shape*, allowGC>::toHandle(shape),
+                      MaybeRooted<Value, allowGC>::toMutableHandle(vp));
 }
 
 bool
 js::NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObject obj,
                               HandleShape shape, MutableHandleValue vp)
 {
     RootedValue receiverValue(cx, ObjectValue(*receiver));
     return GetExistingProperty<CanGC>(cx, receiverValue, obj, shape, vp);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -619,24 +619,24 @@ intrinsic_DefineProperty(JSContext* cx, 
         attrs |= JSPROP_IGNORE_VALUE;
 
     if (attributes & ACCESSOR_DESCRIPTOR_KIND) {
         Value getter = args[3];
         MOZ_ASSERT(getter.isObject() || getter.isNullOrUndefined());
         if (getter.isObject())
             desc.setGetterObject(&getter.toObject());
         if (!getter.isNull())
-            attrs |= JSPROP_GETTER | JSPROP_SHARED;
+            attrs |= JSPROP_GETTER;
 
         Value setter = args[4];
         MOZ_ASSERT(setter.isObject() || setter.isNullOrUndefined());
         if (setter.isObject())
             desc.setSetterObject(&setter.toObject());
         if (!setter.isNull())
-            attrs |= JSPROP_SETTER | JSPROP_SHARED;
+            attrs |= JSPROP_SETTER;
 
         // By convention, these bits are not used on accessor descriptors.
         attrs &= ~(JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
     }
 
     desc.setAttributes(attrs);
     desc.assertValid();
 
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -661,39 +661,33 @@ js::ReshapeForAllocKind(JSContext* cx, S
         if (!newShape)
             return nullptr;
     }
 
     return newShape;
 }
 
 /*
- * Check and adjust the new attributes for the shape to make sure that our
- * slot access optimizations are sound. It is responsibility of the callers to
- * enforce all restrictions from ECMA-262 v5 8.12.9 [[DefineOwnProperty]].
+ * Assert some invariants that should hold when changing properties. It's the
+ * responsibility of the callers to ensure these hold.
  */
-static inline bool
-CheckCanChangeAttrs(JSContext* cx, JSObject* obj, Shape* shape, unsigned* attrsp)
+static void
+AssertCanChangeAttrs(Shape* shape, unsigned attrs)
 {
+#ifdef DEBUG
     if (shape->configurable())
-        return true;
+        return;
 
     /* A permanent property must stay permanent. */
-    *attrsp |= JSPROP_PERMANENT;
+    MOZ_ASSERT(attrs & JSPROP_PERMANENT);
 
     /* Reject attempts to remove a slot from the permanent data property. */
-    if (shape->isDataDescriptor() && shape->hasSlot() &&
-        (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)))
-    {
-        if (!cx->helperThread())
-            JSObject::reportNotConfigurable(cx, shape->propid());
-        return false;
-    }
-
-    return true;
+    MOZ_ASSERT_IF(shape->isDataDescriptor() && shape->hasSlot(),
+                  !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
+#endif
 }
 
 /* static */ Shape*
 NativeObject::putProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
                           GetterOp getter, SetterOp setter, uint32_t slot, unsigned attrs,
                           unsigned flags)
 {
     MOZ_ASSERT(!JSID_IS_VOID(id));
@@ -737,27 +731,27 @@ NativeObject::putProperty(JSContext* cx,
 
         return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags,
                                    entry, true, keep);
     }
 
     /* Property exists: search must have returned a valid entry. */
     MOZ_ASSERT_IF(entry, !entry->isRemoved());
 
-    if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
-        return nullptr;
+    AssertCanChangeAttrs(shape, attrs);
 
     /*
      * If the caller wants to allocate a slot, but doesn't care which slot,
      * copy the existing shape's slot into slot so we can match shape, if all
      * other members match.
      */
     bool hadSlot = shape->hasSlot();
     uint32_t oldSlot = shape->maybeSlot();
-    if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot)
+    bool needSlot = !getter && !setter;
+    if (needSlot && slot == SHAPE_INVALID_SLOT && hadSlot)
         slot = oldSlot;
 
     Rooted<UnownedBaseShape*> nbase(cx);
     {
         RootedShape shape(cx, obj->lastProperty());
         nbase = GetBaseShapeForNewShape(cx, shape, id);
         if (!nbase)
             return nullptr;
@@ -779,17 +773,17 @@ NativeObject::putProperty(JSContext* cx,
         if (!toDictionaryMode(cx, obj))
             return nullptr;
         ShapeTable* table = obj->lastProperty()->maybeTable(keep);
         MOZ_ASSERT(table);
         entry = &table->search<MaybeAdding::NotAdding>(shape->propid(), keep);
         shape = entry->shape();
     }
 
-    MOZ_ASSERT_IF(shape->hasSlot() && !(attrs & JSPROP_SHARED), shape->slot() == slot);
+    MOZ_ASSERT_IF(shape->hasSlot() && needSlot, shape->slot() == slot);
 
     if (obj->inDictionaryMode()) {
         /*
          * Updating some property in a dictionary-mode object. Create a new
          * shape for the existing property, and also generate a new shape for
          * the last property of the dictionary (unless the modified property
          * is also the last property).
          */
@@ -801,28 +795,26 @@ NativeObject::putProperty(JSContext* cx,
             return nullptr;
         if (!updateLast && !NativeObject::generateOwnShape(cx, obj))
             return nullptr;
 
         /*
          * FIXME bug 593129 -- slot allocation and NativeObject *this must move
          * out of here!
          */
-        if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED)) {
+        if (slot == SHAPE_INVALID_SLOT && needSlot) {
             if (!allocDictionarySlot(cx, obj, &slot))
                 return nullptr;
         }
 
         if (updateLast)
             shape->base()->adoptUnowned(nbase);
         else
             shape->base_ = nbase;
 
-        MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
-
         shape->setSlot(slot);
         shape->attrs = uint8_t(attrs);
         shape->flags = flags | Shape::IN_DICTIONARY | (accessorShape ? Shape::ACCESSOR_SHAPE : 0);
         if (shape->isAccessorShape()) {
             AccessorShape& accShape = shape->asAccessorShape();
             accShape.rawGetter = getter;
             accShape.rawSetter = setter;
             GetterSetterWriteBarrierPost(&accShape);
@@ -876,26 +868,26 @@ NativeObject::putProperty(JSContext* cx,
     return shape;
 }
 
 /* static */ Shape*
 NativeObject::changeProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
                              unsigned attrs, GetterOp getter, SetterOp setter)
 {
     MOZ_ASSERT(obj->containsPure(shape));
-    MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
 
     /* Allow only shared (slotless) => unshared (slotful) transition. */
-    MOZ_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
-               !(attrs & JSPROP_SHARED));
+#ifdef DEBUG
+    bool needSlot = !getter && !setter;
+    MOZ_ASSERT_IF(shape->hasSlot() != needSlot, needSlot);
+#endif
 
     MarkTypePropertyNonData(cx, obj, shape->propid());
 
-    if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
-        return nullptr;
+    AssertCanChangeAttrs(shape, attrs);
 
     if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
         return shape;
 
     /*
      * Let JSObject::putProperty handle this |overwriting| case, including
      * the conservation of shape->slot (if it's valid). We must not call
      * removeProperty because it will free an allocated shape->slot, and
@@ -1803,17 +1795,16 @@ Shape::dump(js::GenericPrinter& out) con
         int first = 1;
         out.putChar('(');
 #define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) out.put(&(" " #display)[first]), first = 0
         DUMP_ATTR(ENUMERATE, enumerate);
         DUMP_ATTR(READONLY, readonly);
         DUMP_ATTR(PERMANENT, permanent);
         DUMP_ATTR(GETTER, getter);
         DUMP_ATTR(SETTER, setter);
-        DUMP_ATTR(SHARED, shared);
 #undef  DUMP_ATTR
         out.putChar(')');
     }
 
     out.printf("flags %x ", flags);
     if (flags) {
         int first = 1;
         out.putChar('(');
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1008,17 +1008,17 @@ class Shape : public gc::TenuredCell
                attrs == aattrs &&
                getter() == rawGetter &&
                setter() == rawSetter;
     }
 
     BaseShape* base() const { return base_.get(); }
 
     bool hasSlot() const {
-        return (attrs & JSPROP_SHARED) == 0;
+        return !isEmptyShape() && !getter() && !setter();
     }
     uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
     uint32_t maybeSlot() const {
         return slotInfo & SLOT_MASK;
     }
 
     bool isEmptyShape() const {
         MOZ_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
@@ -1445,17 +1445,16 @@ struct StackShape
         rawSetter(nullptr),
         slot_(slot),
         attrs(uint8_t(attrs)),
         flags(uint8_t(flags))
     {
         MOZ_ASSERT(base);
         MOZ_ASSERT(!JSID_IS_VOID(propid));
         MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
-        MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
     }
 
     explicit StackShape(Shape* shape)
       : base(shape->base()->unowned()),
         propid(shape->propidRef()),
         rawGetter(shape->getter()),
         rawSetter(shape->setter()),
         slot_(shape->maybeSlot()),
@@ -1468,17 +1467,20 @@ struct StackShape
             flags |= Shape::ACCESSOR_SHAPE;
         else
             flags &= ~Shape::ACCESSOR_SHAPE;
 
         this->rawGetter = rawGetter;
         this->rawSetter = rawSetter;
     }
 
-    bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
+    bool hasSlot() const {
+        MOZ_ASSERT(!JSID_IS_EMPTY(propid));
+        return !rawGetter && !rawSetter;
+    }
     bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
 
     uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return slot_; }
     uint32_t maybeSlot() const { return slot_; }
 
     void setSlot(uint32_t slot) {
         MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
         slot_ = slot;
@@ -1541,17 +1543,16 @@ Shape::Shape(const StackShape& other, ui
 #ifdef DEBUG
     gc::AllocKind allocKind = getAllocKind();
     MOZ_ASSERT_IF(other.isAccessorShape(), allocKind == gc::AllocKind::ACCESSOR_SHAPE);
     MOZ_ASSERT_IF(allocKind == gc::AllocKind::SHAPE, !other.isAccessorShape());
 #endif
 
     MOZ_ASSERT_IF(!isEmptyShape(), AtomIsMarked(zone(), propid()));
 
-    MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
     kids.setNull();
 }
 
 // This class is used to update any shapes in a zone that have nursery objects
 // as getters/setters.  It updates the pointers and the shapes' entries in the
 // parents' KidsHash tables.
 class NurseryShapesRef : public gc::BufferableRef
 {
@@ -1562,17 +1563,17 @@ class NurseryShapesRef : public gc::Buff
     void trace(JSTracer* trc) override;
 };
 
 inline
 Shape::Shape(UnownedBaseShape* base, uint32_t nfixed)
   : base_(base),
     propid_(JSID_EMPTY),
     slotInfo(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
-    attrs(JSPROP_SHARED),
+    attrs(0),
     flags(0),
     parent(nullptr)
 {
     MOZ_ASSERT(base);
     kids.setNull();
 }
 
 inline GetterOp
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1365,17 +1365,17 @@ XRE_XPCShellMain(int argc, char** argv, 
             }
 
             nsAutoString workingDirectory;
             if (GetCurrentWorkingDirectory(workingDirectory))
                 gWorkingDirectory = &workingDirectory;
 
             JS_DefineProperty(cx, glob, "__LOCATION__",
                               GetLocationProperty, nullptr,
-                              JSPROP_SHARED);
+                              0);
 
             {
                 // We are almost certainly going to run script here, so we need an
                 // AutoEntryScript. This is Gecko-specific and not in any spec.
                 AutoEntryScript aes(backstagePass, "xpcshell argument processing");
 
                 // If an exception is thrown, we'll set our return code
                 // appropriately, and then let the AutoEntryScript destructor report
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -345,17 +345,17 @@ DefinePropertyIfFound(XPCCallContext& cc
 
             if (!fun)
                 return false;
 
             RootedObject funobj(ccx, JS_GetFunctionObject(fun));
             if (!funobj)
                 return false;
 
-            propFlags |= JSPROP_GETTER | JSPROP_SHARED;
+            propFlags |= JSPROP_GETTER;
             propFlags &= ~JSPROP_ENUMERATE;
 
             AutoResolveName arn(ccx, id);
             if (resolved)
                 *resolved = true;
             return JS_DefinePropertyById(ccx, obj, id,
                                          JS_DATA_TO_FUNC_PTR(JSNative, funobj.get()),
                                          nullptr,
@@ -429,17 +429,17 @@ DefinePropertyIfFound(XPCCallContext& cc
             *resolved = true;
         return JS_DefinePropertyById(ccx, obj, id, funval, propFlags);
     }
 
     // else...
 
     MOZ_ASSERT(member->IsAttribute(), "way broken!");
 
-    propFlags |= JSPROP_GETTER | JSPROP_SHARED;
+    propFlags |= JSPROP_GETTER;
     propFlags &= ~JSPROP_READONLY;
     JSObject* funobj = funval.toObjectOrNull();
     JSNative getter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
     JSNative setter;
     if (member->IsWritableAttribute()) {
         propFlags |= JSPROP_SETTER;
         setter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
     } else {
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1450,19 +1450,16 @@ XPCWrappedNativeXrayTraits::resolveNativ
             return false;
         }
 
         unsigned attrs = desc.attributes();
         attrs |= JSPROP_GETTER;
         if (member->IsWritableAttribute())
             attrs |= JSPROP_SETTER;
 
-        // Make the property shared on the holder so no slot is allocated
-        // for it. This avoids keeping garbage alive through that slot.
-        attrs |= JSPROP_SHARED;
         desc.setAttributes(attrs);
     } else {
         // This is a method. Clone a function for it.
         if (!member->NewFunctionObject(ccx, iface, wrapper, desc.value().address())) {
             JS_ReportErrorASCII(cx, "Failed to clone function object for native function");
             return false;
         }
 
@@ -1558,17 +1555,17 @@ XrayTraits::resolveOwnProperty(JSContext
     // Handle .wrappedJSObject for subsuming callers. This should move once we
     // sort out own-ness for the holder.
     if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
         WrapperFactory::AllowWaiver(wrapper))
     {
         if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found))
             return false;
         if (!found && !JS_DefinePropertyById(cx, holder, id, wrappedJSObject_getter, nullptr,
-                                             JSPROP_ENUMERATE | JSPROP_SHARED)) {
+                                             JSPROP_ENUMERATE)) {
             return false;
         }
         if (!JS_GetOwnPropertyDescriptorById(cx, holder, id, desc))
             return false;
         desc.object().set(wrapper);
         return true;
     }
 
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -652,24 +652,22 @@ nsNumberControlFrame::SetValueOfAnonText
     return;
   }
 
   // Init to aValue so that we set aValue as the value of our text control if
   // aValue isn't a valid number (in which case the HTMLInputElement's validity
   // state will be set to invalid) or if aValue can't be localized:
   nsAutoString localizedValue(aValue);
 
-#ifdef ENABLE_INTL_API
   // Try and localize the value we will set:
   Decimal val = HTMLInputElement::StringToDecimal(aValue);
   if (val.isFinite()) {
     ICUUtils::LanguageTagIterForContent langTagIter(mContent);
     ICUUtils::LocalizeNumber(val.toDouble(), langTagIter, localizedValue);
   }
-#endif
 
   // We need to update the value of our anonymous text control here. Note that
   // this must be its value, and not its 'value' attribute (the default value),
   // since the default value is ignored once a user types into the text
   // control.
   //
   // Pass NonSystem as the caller type; this should work fine for actual number
   // inputs, and be safe in case our input has a type we don't expect for some
@@ -685,17 +683,16 @@ nsNumberControlFrame::GetValueOfAnonText
 {
   if (!mTextField) {
     aValue.Truncate();
     return;
   }
 
   HTMLInputElement::FromContent(mTextField)->GetValue(aValue, CallerType::System);
 
-#ifdef ENABLE_INTL_API
   // Here we need to de-localize any number typed in by the user. That is, we
   // need to convert it from the number format of the user's language, region,
   // etc. to the format that the HTML 5 spec defines to be a "valid
   // floating-point number":
   //
   //   http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#floating-point-numbers
   //
   // This is necessary to allow the number that we return to be parsed by
@@ -726,17 +723,16 @@ nsNumberControlFrame::GetValueOfAnonText
   // We can't preserve the formatting, otherwise functions such as
   // HTMLInputElement::StringToDecimal would incorrectly process the number
   // input by the user. For example, "12.345" with lang=de de-localizes as
   // 12345, but HTMLInputElement::StringToDecimal would mistakenly parse it as
   // 12.345. Another example would be "12,345" with lang=de which de-localizes
   // as 12.345, but HTMLInputElement::StringToDecimal would parse it to NaN.
   aValue.Truncate();
   aValue.AppendFloat(value);
-#endif
 }
 
 bool
 nsNumberControlFrame::AnonTextControlIsEmpty()
 {
   if (!mTextField) {
     return true;
   }
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -626,33 +626,33 @@ SVGObserverUtils::GetEffectProperties(ns
   return result;
 }
 
 nsSVGPaintServerFrame *
 SVGObserverUtils::GetPaintServer(nsIFrame* aTargetFrame,
                                  nsStyleSVGPaint nsStyleSVG::* aPaint,
                                  PaintingPropertyDescriptor aType)
 {
-  const nsStyleSVG* svgStyle = aTargetFrame->StyleSVG();
-  if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
-    return nullptr;
-
   // If we're looking at a frame within SVG text, then we need to look up
   // to find the right frame to get the painting property off.  We should at
   // least look up past a text frame, and if the text frame's parent is the
   // anonymous block frame, then we look up to its parent (the SVGTextFrame).
   nsIFrame* frame = aTargetFrame;
   if (frame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
     frame = frame->GetParent();
     nsIFrame* grandparent = frame->GetParent();
     if (grandparent && grandparent->IsSVGTextFrame()) {
       frame = grandparent;
     }
   }
 
+  const nsStyleSVG* svgStyle = frame->StyleSVG();
+  if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
+    return nullptr;
+
   nsCOMPtr<nsIURI> paintServerURL =
     SVGObserverUtils::GetPaintURI(frame, aPaint);
   nsSVGPaintingProperty *property =
     SVGObserverUtils::GetPaintingProperty(paintServerURL, frame, aType);
   if (!property)
     return nullptr;
   nsIFrame* result = property->GetReferencedFrame();
   if (!result)
--- a/modules/libjar/zipwriter/nsZipWriter.cpp
+++ b/modules/libjar/zipwriter/nsZipWriter.cpp
@@ -984,17 +984,17 @@ inline nsresult nsZipWriter::BeginProces
         RefPtr<nsZipDataStream> stream = new nsZipDataStream();
         NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
         rv = stream->Init(this, mStream, header, aItem->mCompression);
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (aItem->mStream) {
             nsCOMPtr<nsIInputStreamPump> pump;
             rv = NS_NewInputStreamPump(getter_AddRefs(pump), aItem->mStream,
-                                       -1, -1, 0, 0, true);
+                                       0, 0, true);
             NS_ENSURE_SUCCESS(rv, rv);
 
             rv = pump->AsyncRead(stream, nullptr);
             NS_ENSURE_SUCCESS(rv, rv);
         }
         else {
             rv = NS_MaybeOpenChannelUsingAsyncOpen2(aItem->mChannel, stream);
             NS_ENSURE_SUCCESS(rv, rv);
@@ -1012,18 +1012,17 @@ inline nsresult nsZipWriter::BeginProces
 inline nsresult nsZipWriter::BeginProcessingRemoval(int32_t aPos)
 {
     // Open the zip file for reading
     nsCOMPtr<nsIInputStream> inputStream;
     nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
                                              mFile);
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIInputStreamPump> pump;
-    rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream, -1, -1, 0,
-                               0, true);
+    rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream, 0, 0, true);
     if (NS_FAILED(rv)) {
         inputStream->Close();
         return rv;
     }
     nsCOMPtr<nsIStreamListener> listener;
     rv = NS_NewSimpleStreamListener(getter_AddRefs(listener), mStream, this);
     if (NS_FAILED(rv)) {
         inputStream->Close();
--- a/modules/libjar/zipwriter/test/unit/test_bug399727.js
+++ b/modules/libjar/zipwriter/test/unit/test_bug399727.js
@@ -75,12 +75,12 @@ function run_test()
   // Open the expected output file
   var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
                 createInstance(Ci.nsIFileInputStream);
   fstream.init(source, -1, 0, 0);
 
   // Set up a pump to push data from the file to the stream converter
   var pump = Cc["@mozilla.org/network/input-stream-pump;1"].
              createInstance(Ci.nsIInputStreamPump);
-  pump.init(fstream, -1, -1, 0, 0, true);
+  pump.init(fstream, 0, 0, true);
   pump.asyncRead(converter, null);
   do_test_pending();
 }
--- a/modules/libjar/zipwriter/test/unit/test_bug717061.js
+++ b/modules/libjar/zipwriter/test/unit/test_bug717061.js
@@ -81,12 +81,12 @@ function run_test()
   // Open the expected output file
   var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
                 createInstance(Ci.nsIFileInputStream);
   fstream.init(source, -1, 0, 0);
 
   // Set up a pump to push data from the file to the stream converter
   var pump = Cc["@mozilla.org/network/input-stream-pump;1"].
              createInstance(Ci.nsIInputStreamPump);
-  pump.init(fstream, -1, -1, 0, 0, true);
+  pump.init(fstream, 0, 0, true);
   pump.asyncRead(converter, null);
   do_test_pending();
 }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1417,17 +1417,17 @@ pref("javascript.options.strict",       
 #ifdef DEBUG
 pref("javascript.options.strict.debug",     false);
 #endif
 pref("javascript.options.baselinejit",      true);
 pref("javascript.options.ion",              true);
 pref("javascript.options.asmjs",            true);
 pref("javascript.options.wasm",             true);
 pref("javascript.options.wasm_ionjit",      true);
-pref("javascript.options.wasm_baselinejit", false);
+pref("javascript.options.wasm_baselinejit", true);
 pref("javascript.options.native_regexp",    true);
 pref("javascript.options.parallel_parsing", true);
 #if !defined(RELEASE_OR_BETA) && !defined(ANDROID) && !defined(XP_IOS)
 pref("javascript.options.asyncstack",       true);
 #else
 pref("javascript.options.asyncstack",       false);
 #endif
 pref("javascript.options.throw_on_asmjs_validation_failure", false);
--- a/netwerk/base/NetUtil.jsm
+++ b/netwerk/base/NetUtil.jsm
@@ -131,17 +131,17 @@ this.NetUtil = {
                 aCallback(pipe.inputStream, aStatusCode, aRequest);
             }
         });
 
         // Input streams are handled slightly differently from everything else.
         if (aSource instanceof Ci.nsIInputStream) {
             let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
                        createInstance(Ci.nsIInputStreamPump);
-            pump.init(aSource, -1, -1, 0, 0, true);
+            pump.init(aSource, 0, 0, true);
             pump.asyncRead(listener, null);
             return;
         }
 
         let channel = aSource;
         if (!(channel instanceof Ci.nsIChannel)) {
             channel = this.newChannel(aSource);
         }
--- a/netwerk/base/nsBaseChannel.cpp
+++ b/netwerk/base/nsBaseChannel.cpp
@@ -252,18 +252,18 @@ nsBaseChannel::BeginPumpingData()
 
   // By assigning mPump, we flag this channel as pending (see Pending).  It's
   // important that the pending flag is set when we call into the stream (the
   // call to AsyncRead results in the stream's AsyncWait method being called)
   // and especially when we call into the loadgroup.  Our caller takes care to
   // release mPump if we return an error.
 
   nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
-  rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
-                                 true, target);
+  rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, 0, 0, true,
+                                 target);
   if (NS_SUCCEEDED(rv)) {
     mPumpingData = true;
     mRequest = mPump;
     rv = mPump->AsyncRead(this, nullptr);
   }
 
   return rv;
 }
--- a/netwerk/base/nsIInputStreamPump.idl
+++ b/netwerk/base/nsIInputStreamPump.idl
@@ -29,40 +29,30 @@ interface nsIInputStreamPump : nsIReques
     /**
      * Initialize the input stream pump.
      *
      * @param aStream
      *        contains the data to be read.  if the input stream is non-blocking,
      *        then it will be QI'd to nsIAsyncInputStream.  if the QI succeeds
      *        then the stream will be read directly.  otherwise, it will be read
      *        on a background thread using the stream transport service.
-     * @param aStreamPos
-     *        specifies the stream offset from which to start reading.  the
-     *        offset value is absolute.  pass -1 to specify the current offset.
-     *        NOTE: this parameter is ignored if the underlying stream does not
-     *        implement nsISeekableStream.
-     * @param aStreamLen
-     *        specifies how much data to read from the stream.  pass -1 to read
-     *        all data available in the stream.
      * @param aSegmentSize
      *        if the stream transport service is used, then this parameter
      *        specifies the segment size for the stream transport's buffer.
      *        pass 0 to specify the default value.
      * @param aSegmentCount
      *        if the stream transport service is used, then this parameter
      *        specifies the segment count for the stream transport's buffer.
      *        pass 0 to specify the default value.
      * @param aCloseWhenDone
      *        if true, the input stream will be closed after it has been read.
      * @param aMainThreadTarget
      *        a labeled main therad event target.
      */
     void init(in nsIInputStream aStream,
-              in long long      aStreamPos,
-              in long long      aStreamLen,
               in unsigned long  aSegmentSize,
               in unsigned long  aSegmentCount,
               in boolean        aCloseWhenDone,
               [optional] in nsIEventTarget aMainThreadTarget);
 
     /**
      * asyncRead causes the input stream to be read in chunks and delivered
      * asynchronously to the listener via OnDataAvailable.
--- a/netwerk/base/nsIStreamTransportService.idl
+++ b/netwerk/base/nsIStreamTransportService.idl
@@ -20,59 +20,27 @@ interface nsIInputAvailableCallback;
 interface nsIStreamTransportService : nsISupports
 {
     /**
      * CreateInputTransport
      *
      * @param aStream
      *        The input stream that will be read on a background thread.
      *        This stream must implement "blocking" stream semantics.
-     * @param aStartOffset
-     *        The input stream will be read starting from this offset.  Pass
-     *        -1 to read from the current stream offset.  NOTE: this parameter
-     *        is ignored if the stream does not support nsISeekableStream.
-     * @param aReadLimit
-     *        This parameter limits the number of bytes that will be read from
-     *        the input stream.  Pass -1 to read everything.
      * @param aCloseWhenDone
      *        Specify this flag to have the input stream closed once its
      *        contents have been completely read.
      *
      * @return nsITransport instance.
      */
     nsITransport createInputTransport(in nsIInputStream aStream,
-                                      in long long aStartOffset,
-                                      in long long aReadLimit,
                                       in boolean aCloseWhenDone);
 
     void InputAvailable(in nsIInputStream aStream,
                         in nsIInputAvailableCallback aCallback);
-    /**
-     * CreateOutputTransport
-     *
-     * @param aStream
-     *        The output stream that will be written to on a background thread.
-     *        This stream must implement "blocking" stream semantics.
-     * @param aStartOffset
-     *        The output stream will be written starting at this offset.  Pass
-     *        -1 to write to the current stream offset.  NOTE: this parameter
-     *        is ignored if the stream does not support nsISeekableStream.
-     * @param aWriteLimit
-     *        This parameter limits the number of bytes that will be written to
-     *        the output stream.  Pass -1 for unlimited writing.
-     * @param aCloseWhenDone
-     *        Specify this flag to have the output stream closed once its
-     *        contents have been completely written.
-     *
-     * @return nsITransport instance.
-     */
-    nsITransport createOutputTransport(in nsIOutputStream aStream,
-                                       in long long aStartOffset,
-                                       in long long aWriteLimit,
-                                       in boolean aCloseWhenDone);
 };
 
 [builtinclass, uuid(ff2da731-44d0-4dd9-8236-c99387fec721)]
 interface nsIInputAvailableCallback : nsISupports
 {
   void onInputAvailableComplete(in unsigned long long available,
 			        in nsresult available_return_code);
 };
--- a/netwerk/base/nsInputStreamPump.cpp
+++ b/netwerk/base/nsInputStreamPump.cpp
@@ -31,17 +31,16 @@ static mozilla::LazyLogModule gStreamPum
 
 //-----------------------------------------------------------------------------
 // nsInputStreamPump methods
 //-----------------------------------------------------------------------------
 
 nsInputStreamPump::nsInputStreamPump()
     : mState(STATE_IDLE)
     , mStreamOffset(0)
-    , mStreamLength(UINT64_MAX)
     , mStatus(NS_OK)
     , mSuspendCount(0)
     , mLoadFlags(LOAD_NORMAL)
     , mProcessingCallbacks(false)
     , mWaitingForInputStreamReady(false)
     , mCloseWhenDone(false)
     , mRetargeting(false)
     , mMutex("nsInputStreamPump")
@@ -50,28 +49,26 @@ nsInputStreamPump::nsInputStreamPump()
 
 nsInputStreamPump::~nsInputStreamPump()
 {
 }
 
 nsresult
 nsInputStreamPump::Create(nsInputStreamPump  **result,
                           nsIInputStream      *stream,
-                          int64_t              streamPos,
-                          int64_t              streamLen,
                           uint32_t             segsize,
                           uint32_t             segcount,
                           bool                 closeWhenDone,
                           nsIEventTarget      *mainThreadTarget)
 {
     nsresult rv = NS_ERROR_OUT_OF_MEMORY;
     RefPtr<nsInputStreamPump> pump = new nsInputStreamPump();
     if (pump) {
-        rv = pump->Init(stream, streamPos, streamLen,
-                        segsize, segcount, closeWhenDone, mainThreadTarget);
+        rv = pump->Init(stream, segsize, segcount, closeWhenDone,
+                        mainThreadTarget);
         if (NS_SUCCEEDED(rv)) {
             pump.forget(result);
         }
     }
     return rv;
 }
 
 struct PeekData {
@@ -292,25 +289,21 @@ nsInputStreamPump::SetLoadGroup(nsILoadG
 }
 
 //-----------------------------------------------------------------------------
 // nsInputStreamPump::nsIInputStreamPump implementation
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsInputStreamPump::Init(nsIInputStream *stream,
-                        int64_t streamPos, int64_t streamLen,
                         uint32_t segsize, uint32_t segcount,
                         bool closeWhenDone, nsIEventTarget *mainThreadTarget)
 {
     NS_ENSURE_TRUE(mState == STATE_IDLE, NS_ERROR_IN_PROGRESS);
 
-    mStreamOffset = uint64_t(streamPos);
-    if (int64_t(streamLen) >= int64_t(0))
-        mStreamLength = uint64_t(streamLen);
     mStream = stream;
     mSegSize = segsize;
     mSegCount = segcount;
     mCloseWhenDone = closeWhenDone;
     mLabeledMainThreadTarget = mainThreadTarget;
 
     return NS_OK;
 }
@@ -333,54 +326,41 @@ nsInputStreamPump::AsyncRead(nsIStreamLi
     //
 
     bool nonBlocking;
     nsresult rv = mStream->IsNonBlocking(&nonBlocking);
     if (NS_FAILED(rv)) return rv;
 
     if (nonBlocking) {
         mAsyncStream = do_QueryInterface(mStream);
-        //
-        // if the stream supports nsIAsyncInputStream, and if we need to seek
-        // to a starting offset, then we must do so here.  in the non-async
-        // stream case, the stream transport service will take care of seeking
-        // for us.
-        //
-        if (mAsyncStream && (mStreamOffset != UINT64_MAX)) {
-            nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
-            if (seekable)
-                seekable->Seek(nsISeekableStream::NS_SEEK_SET, mStreamOffset);
-        }
     }
 
     if (!mAsyncStream) {
         // ok, let's use the stream transport service to read this stream.
         nsCOMPtr<nsIStreamTransportService> sts =
             do_GetService(kStreamTransportServiceCID, &rv);
         if (NS_FAILED(rv)) return rv;
 
         nsCOMPtr<nsITransport> transport;
-        rv = sts->CreateInputTransport(mStream, mStreamOffset, mStreamLength,
-                                       mCloseWhenDone, getter_AddRefs(transport));
+        rv = sts->CreateInputTransport(mStream, mCloseWhenDone, getter_AddRefs(transport));
         if (NS_FAILED(rv)) return rv;
 
         nsCOMPtr<nsIInputStream> wrapper;
         rv = transport->OpenInputStream(0, mSegSize, mSegCount, getter_AddRefs(wrapper));
         if (NS_FAILED(rv)) return rv;
 
         mAsyncStream = do_QueryInterface(wrapper, &rv);
         if (NS_FAILED(rv)) return rv;
     }
 
     // release our reference to the original stream.  from this point forward,
     // we only reference the "stream" via mAsyncStream.
     mStream = nullptr;
 
-    // mStreamOffset now holds the number of bytes currently read.  we use this
-    // to enforce the mStreamLength restriction.
+    // mStreamOffset now holds the number of bytes currently read.
     mStreamOffset = 0;
 
     // grab event queue (we must do this here by contract, since all notifications
     // must go to the thread which called AsyncRead)
     if (NS_IsMainThread() && mLabeledMainThreadTarget) {
         mTargetThread = mLabeledMainThreadTarget;
     } else {
         mTargetThread = GetCurrentThreadEventTarget();
@@ -568,86 +548,80 @@ nsInputStreamPump::OnStateTransfer()
     LOG(("  Available returned [stream=%p rv=%" PRIx32 " avail=%" PRIu64 "]\n", mAsyncStream.get(),
          static_cast<uint32_t>(rv), avail));
 
     if (rv == NS_BASE_STREAM_CLOSED) {
         rv = NS_OK;
         avail = 0;
     }
     else if (NS_SUCCEEDED(rv) && avail) {
-        // figure out how much data to report (XXX detect overflow??)
-        if (avail > mStreamLength - mStreamOffset)
-            avail = mStreamLength - mStreamOffset;
+        // we used to limit avail to 16K - we were afraid some ODA handlers
+        // might assume they wouldn't get more than 16K at once
+        // we're removing that limit since it speeds up local file access.
+        // Now there's an implicit 64K limit of 4 16K segments
+        // NOTE: ok, so the story is as follows.  OnDataAvailable impls
+        //       are by contract supposed to consume exactly |avail| bytes.
+        //       however, many do not... mailnews... stream converters...
+        //       cough, cough.  the input stream pump is fairly tolerant
+        //       in this regard; however, if an ODA does not consume any
+        //       data from the stream, then we could potentially end up in
+        //       an infinite loop.  we do our best here to try to catch
+        //       such an error.  (see bug 189672)
 
-        if (avail) {
-            // we used to limit avail to 16K - we were afraid some ODA handlers
-            // might assume they wouldn't get more than 16K at once
-            // we're removing that limit since it speeds up local file access.
-            // Now there's an implicit 64K limit of 4 16K segments
-            // NOTE: ok, so the story is as follows.  OnDataAvailable impls
-            //       are by contract supposed to consume exactly |avail| bytes.
-            //       however, many do not... mailnews... stream converters...
-            //       cough, cough.  the input stream pump is fairly tolerant
-            //       in this regard; however, if an ODA does not consume any
-            //       data from the stream, then we could potentially end up in
-            //       an infinite loop.  we do our best here to try to catch
-            //       such an error.  (see bug 189672)
+        // in most cases this QI will succeed (mAsyncStream is almost always
+        // a nsPipeInputStream, which implements nsISeekableStream::Tell).
+        int64_t offsetBefore;
+        nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mBufferedStream);
+        if (seekable && NS_FAILED(seekable->Tell(&offsetBefore))) {
+            NS_NOTREACHED("Tell failed on readable stream");
+            offsetBefore = 0;
+        }
 
-            // in most cases this QI will succeed (mAsyncStream is almost always
-            // a nsPipeInputStream, which implements nsISeekableStream::Tell).
-            int64_t offsetBefore;
-            nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mBufferedStream);
-            if (seekable && NS_FAILED(seekable->Tell(&offsetBefore))) {
-                NS_NOTREACHED("Tell failed on readable stream");
-                offsetBefore = 0;
-            }
+        uint32_t odaAvail =
+            avail > UINT32_MAX ?
+            UINT32_MAX : uint32_t(avail);
 
-            uint32_t odaAvail =
-                avail > UINT32_MAX ?
-                UINT32_MAX : uint32_t(avail);
-
-            LOG(("  calling OnDataAvailable [offset=%" PRIu64 " count=%" PRIu64 "(%u)]\n",
-                mStreamOffset, avail, odaAvail));
+        LOG(("  calling OnDataAvailable [offset=%" PRIu64 " count=%" PRIu64 "(%u)]\n",
+            mStreamOffset, avail, odaAvail));
 
-            {
-                // Note: Must exit mutex for call to OnStartRequest to avoid
-                // deadlocks when calls to RetargetDeliveryTo for multiple
-                // nsInputStreamPumps are needed (e.g. nsHttpChannel).
-                RecursiveMutexAutoUnlock unlock(mMutex);
-                rv = mListener->OnDataAvailable(this, mListenerContext,
-                                                mBufferedStream, mStreamOffset,
-                                                odaAvail);
-            }
+        {
+            // Note: Must exit mutex for call to OnStartRequest to avoid
+            // deadlocks when calls to RetargetDeliveryTo for multiple
+            // nsInputStreamPumps are needed (e.g. nsHttpChannel).
+            RecursiveMutexAutoUnlock unlock(mMutex);
+            rv = mListener->OnDataAvailable(this, mListenerContext,
+                                            mBufferedStream, mStreamOffset,
+                                            odaAvail);
+        }
 
-            // don't enter this code if ODA failed or called Cancel
-            if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) {
-                // test to see if this ODA failed to consume data
-                if (seekable) {
-                    // NOTE: if Tell fails, which can happen if the stream is
-                    // now closed, then we assume that everything was read.
-                    int64_t offsetAfter;
-                    if (NS_FAILED(seekable->Tell(&offsetAfter)))
-                        offsetAfter = offsetBefore + odaAvail;
-                    if (offsetAfter > offsetBefore)
-                        mStreamOffset += (offsetAfter - offsetBefore);
-                    else if (mSuspendCount == 0) {
-                        //
-                        // possible infinite loop if we continue pumping data!
-                        //
-                        // NOTE: although not allowed by nsIStreamListener, we
-                        // will allow the ODA impl to Suspend the pump.  IMAP
-                        // does this :-(
-                        //
-                        NS_ERROR("OnDataAvailable implementation consumed no data");
-                        mStatus = NS_ERROR_UNEXPECTED;
-                    }
+        // don't enter this code if ODA failed or called Cancel
+        if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) {
+            // test to see if this ODA failed to consume data
+            if (seekable) {
+                // NOTE: if Tell fails, which can happen if the stream is
+                // now closed, then we assume that everything was read.
+                int64_t offsetAfter;
+                if (NS_FAILED(seekable->Tell(&offsetAfter)))
+                    offsetAfter = offsetBefore + odaAvail;
+                if (offsetAfter > offsetBefore)
+                    mStreamOffset += (offsetAfter - offsetBefore);
+                else if (mSuspendCount == 0) {
+                    //
+                    // possible infinite loop if we continue pumping data!
+                    //
+                    // NOTE: although not allowed by nsIStreamListener, we
+                    // will allow the ODA impl to Suspend the pump.  IMAP
+                    // does this :-(
+                    //
+                    NS_ERROR("OnDataAvailable implementation consumed no data");
+                    mStatus = NS_ERROR_UNEXPECTED;
                 }
-                else
-                    mStreamOffset += odaAvail; // assume ODA behaved well
             }
+            else
+                mStreamOffset += odaAvail; // assume ODA behaved well
         }
     }
 
     // an error returned from Available or OnDataAvailable should cause us to
     // abort; however, we must not stomp on mStatus if already canceled.
 
     if (NS_SUCCEEDED(mStatus)) {
         if (NS_FAILED(rv))
--- a/netwerk/base/nsInputStreamPump.h
+++ b/netwerk/base/nsInputStreamPump.h
@@ -32,18 +32,16 @@ public:
     NS_DECL_NSIINPUTSTREAMCALLBACK
     NS_DECL_NSITHREADRETARGETABLEREQUEST
 
     nsInputStreamPump();
 
     static nsresult
                       Create(nsInputStreamPump  **result,
                              nsIInputStream      *stream,
-                             int64_t              streamPos = -1,
-                             int64_t              streamLen = -1,
                              uint32_t             segsize = 0,
                              uint32_t             segcount = 0,
                              bool                 closeWhenDone = false,
                              nsIEventTarget      *mainThreadTarget = nullptr);
 
     typedef void (*PeekSegmentFun)(void *closure, const uint8_t *buf,
                                    uint32_t bufLen);
     /**
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -704,29 +704,27 @@ NS_NewInputStreamChannel(nsIChannel     
                                           aSecurityFlags,
                                           aContentPolicyType,
                                           aIsSrcdocChannel);
 }
 
 nsresult
 NS_NewInputStreamPump(nsIInputStreamPump **result,
                       nsIInputStream      *stream,
-                      int64_t              streamPos /* = int64_t(-1) */,
-                      int64_t              streamLen /* = int64_t(-1) */,
                       uint32_t             segsize /* = 0 */,
                       uint32_t             segcount /* = 0 */,
                       bool                 closeWhenDone /* = false */,
                       nsIEventTarget      *mainThreadTarget /* = nullptr */)
 {
     nsresult rv;
     nsCOMPtr<nsIInputStreamPump> pump =
         do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
     if (NS_SUCCEEDED(rv)) {
-        rv = pump->Init(stream, streamPos, streamLen,
-                        segsize, segcount, closeWhenDone, mainThreadTarget);
+        rv = pump->Init(stream, segsize, segcount, closeWhenDone,
+                        mainThreadTarget);
         if (NS_SUCCEEDED(rv)) {
             *result = nullptr;
             pump.swap(*result);
         }
     }
     return rv;
 }
 
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -297,18 +297,16 @@ nsresult NS_NewInputStreamChannel(nsICha
                                   const nsACString   &aContentType,
                                   nsIPrincipal       *aLoadingPrincipal,
                                   nsSecurityFlags     aSecurityFlags,
                                   nsContentPolicyType aContentPolicyType,
                                   bool                aIsSrcdocChannel = false);
 
 nsresult NS_NewInputStreamPump(nsIInputStreamPump **result,
                                nsIInputStream      *stream,
-                               int64_t              streamPos = int64_t(-1),
-                               int64_t              streamLen = int64_t(-1),
                                uint32_t             segsize = 0,
                                uint32_t             segcount = 0,
                                bool                 closeWhenDone = false,
                                nsIEventTarget      *mainThreadTarget = nullptr);
 
 // NOTE: you will need to specify whether or not your streams are buffered
 // (i.e., do they implement ReadSegments/WriteSegments).  the default
 // assumption of TRUE for both streams might not be right for you!
--- a/netwerk/base/nsStreamTransportService.cpp
+++ b/netwerk/base/nsStreamTransportService.cpp
@@ -34,43 +34,37 @@ class nsInputStreamTransport : public ns
                              , public nsIInputStream
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSITRANSPORT
     NS_DECL_NSIINPUTSTREAM
 
     nsInputStreamTransport(nsIInputStream *source,
-                           uint64_t offset,
-                           uint64_t limit,
                            bool closeWhenDone)
         : mSource(source)
-        , mOffset(offset)
-        , mLimit(limit)
+        , mOffset(0)
         , mCloseWhenDone(closeWhenDone)
-        , mFirstTime(true)
         , mInProgress(false)
     {
     }
 
 private:
     virtual ~nsInputStreamTransport()
     {
     }
 
     nsCOMPtr<nsIAsyncInputStream>   mPipeIn;
 
     // while the copy is active, these members may only be accessed from the
     // nsIInputStream implementation.
     nsCOMPtr<nsITransportEventSink> mEventSink;
     nsCOMPtr<nsIInputStream>        mSource;
     int64_t                         mOffset;
-    int64_t                         mLimit;
     bool                            mCloseWhenDone;
-    bool                            mFirstTime;
 
     // this variable serves as a lock to prevent the state of the transport
     // from being modified once the copy is in progress.
     bool                            mInProgress;
 };
 
 NS_IMPL_ISUPPORTS(nsInputStreamTransport,
                   nsITransport,
@@ -155,63 +149,36 @@ nsInputStreamTransport::SetEventSink(nsI
 
 NS_IMETHODIMP
 nsInputStreamTransport::Close()
 {
     if (mCloseWhenDone)
         mSource->Close();
 
     // make additional reads return early...
-    mOffset = mLimit = 0;
+    mOffset = 0;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamTransport::Available(uint64_t *result)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsInputStreamTransport::Read(char *buf, uint32_t count, uint32_t *result)
 {
-    if (mFirstTime) {
-        mFirstTime = false;
-        if (mOffset != 0) {
-            // read from current position if offset equal to max
-            if (mOffset != -1) {
-                nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mSource);
-                if (seekable)
-                    seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
-            }
-            // reset offset to zero so we can use it to enforce limit
-            mOffset = 0;
-        }
-    }
-
-    // limit amount read
-    uint64_t max = count;
-    if (mLimit != -1) {
-        max = mLimit - mOffset;
-        if (max == 0) {
-            *result = 0;
-            return NS_OK;
-        }
-    }
-
-    if (count > max)
-        count = static_cast<uint32_t>(max);
-
     nsresult rv = mSource->Read(buf, count, result);
 
     if (NS_SUCCEEDED(rv)) {
         mOffset += *result;
         if (mEventSink)
             mEventSink->OnTransportStatus(this, NS_NET_STATUS_READING, mOffset,
-                                          mLimit);
+                                          -1);
     }
     return rv;
 }
 
 NS_IMETHODIMP
 nsInputStreamTransport::ReadSegments(nsWriteSegmentFun writer, void *closure,
                                      uint32_t count, uint32_t *result)
 {
@@ -221,225 +188,16 @@ nsInputStreamTransport::ReadSegments(nsW
 NS_IMETHODIMP
 nsInputStreamTransport::IsNonBlocking(bool *result)
 {
     *result = false;
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// nsOutputStreamTransport
-//
-// Implements nsIOutputStream as a wrapper around the real input stream.  This
-// allows the transport to support seeking, range-limiting, progress reporting,
-// and close-when-done semantics while utilizing NS_AsyncCopy.
-//-----------------------------------------------------------------------------
-
-class nsOutputStreamTransport : public nsITransport
-                              , public nsIOutputStream
-{
-public:
-    NS_DECL_THREADSAFE_ISUPPORTS
-    NS_DECL_NSITRANSPORT
-    NS_DECL_NSIOUTPUTSTREAM
-
-    nsOutputStreamTransport(nsIOutputStream *sink,
-                            int64_t offset,
-                            int64_t limit,
-                            bool closeWhenDone)
-        : mSink(sink)
-        , mOffset(offset)
-        , mLimit(limit)
-        , mCloseWhenDone(closeWhenDone)
-        , mFirstTime(true)
-        , mInProgress(false)
-    {
-    }
-
-private:
-    virtual ~nsOutputStreamTransport()
-    {
-    }
-
-    nsCOMPtr<nsIAsyncOutputStream>  mPipeOut;
-
-    // while the copy is active, these members may only be accessed from the
-    // nsIOutputStream implementation.
-    nsCOMPtr<nsITransportEventSink> mEventSink;
-    nsCOMPtr<nsIOutputStream>       mSink;
-    int64_t                         mOffset;
-    int64_t                         mLimit;
-    bool                            mCloseWhenDone;
-    bool                            mFirstTime;
-
-    // this variable serves as a lock to prevent the state of the transport
-    // from being modified once the copy is in progress.
-    bool                            mInProgress;
-};
-
-NS_IMPL_ISUPPORTS(nsOutputStreamTransport,
-                  nsITransport,
-                  nsIOutputStream)
-
-/** nsITransport **/
-
-NS_IMETHODIMP
-nsOutputStreamTransport::OpenInputStream(uint32_t flags,
-                                         uint32_t segsize,
-                                         uint32_t segcount,
-                                         nsIInputStream **result)
-{
-    // this transport only supports writing!
-    NS_NOTREACHED("nsOutputStreamTransport::OpenInputStream");
-    return NS_ERROR_UNEXPECTED;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::OpenOutputStream(uint32_t flags,
-                                          uint32_t segsize,
-                                          uint32_t segcount,
-                                          nsIOutputStream **result)
-{
-    NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
-
-    nsresult rv;
-    nsCOMPtr<nsIEventTarget> target =
-            do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) return rv;
-
-    // XXX if the caller requests an unbuffered stream, then perhaps
-    //     we'd want to simply return mSink; however, then we would
-    //     not be writing to mSink on a background thread.  is this ok?
-
-    bool nonblocking = !(flags & OPEN_BLOCKING);
-
-    net_ResolveSegmentParams(segsize, segcount);
-
-    nsCOMPtr<nsIAsyncInputStream> pipeIn;
-    rv = NS_NewPipe2(getter_AddRefs(pipeIn),
-                     getter_AddRefs(mPipeOut),
-                     true, nonblocking,
-                     segsize, segcount);
-    if (NS_FAILED(rv)) return rv;
-
-    mInProgress = true;
-
-    // startup async copy process...
-    rv = NS_AsyncCopy(pipeIn, this, target,
-                      NS_ASYNCCOPY_VIA_READSEGMENTS, segsize);
-    if (NS_SUCCEEDED(rv))
-        NS_ADDREF(*result = mPipeOut);
-
-    return rv;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::Close(nsresult reason)
-{
-    if (NS_SUCCEEDED(reason))
-        reason = NS_BASE_STREAM_CLOSED;
-
-    return mPipeOut->CloseWithStatus(reason);
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::SetEventSink(nsITransportEventSink *sink,
-                                      nsIEventTarget *target)
-{
-    NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
-
-    if (target)
-        return net_NewTransportEventSinkProxy(getter_AddRefs(mEventSink),
-                                              sink, target);
-
-    mEventSink = sink;
-    return NS_OK;
-}
-
-/** nsIOutputStream **/
-
-NS_IMETHODIMP
-nsOutputStreamTransport::Close()
-{
-    if (mCloseWhenDone)
-        mSink->Close();
-
-    // make additional writes return early...
-    mOffset = mLimit = 0;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::Flush()
-{
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::Write(const char *buf, uint32_t count, uint32_t *result)
-{
-    if (mFirstTime) {
-        mFirstTime = false;
-        if (mOffset != 0) {
-            // write to current position if offset equal to max
-            if (mOffset != -1) {
-                nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mSink);
-                if (seekable)
-                    seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
-            }
-            // reset offset to zero so we can use it to enforce limit
-            mOffset = 0;
-        }
-    }
-
-    // limit amount written
-    uint64_t max = count;
-    if (mLimit != -1) {
-        max = mLimit - mOffset;
-        if (max == 0) {
-            *result = 0;
-            return NS_OK;
-        }
-    }
-
-    if (count > max)
-        count = static_cast<uint32_t>(max);
-
-    nsresult rv = mSink->Write(buf, count, result);
-
-    if (NS_SUCCEEDED(rv)) {
-        mOffset += *result;
-        if (mEventSink)
-            mEventSink->OnTransportStatus(this, NS_NET_STATUS_WRITING, mOffset,
-                                          mLimit);
-    }
-    return rv;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::WriteSegments(nsReadSegmentFun reader, void *closure,
-                                       uint32_t count, uint32_t *result)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::WriteFrom(nsIInputStream *in, uint32_t count, uint32_t *result)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsOutputStreamTransport::IsNonBlocking(bool *result)
-{
-    *result = false;
-    return NS_OK;
-}
-
-//-----------------------------------------------------------------------------
 // nsStreamTransportService
 //-----------------------------------------------------------------------------
 
 nsStreamTransportService::~nsStreamTransportService()
 {
     NS_ASSERTION(!mPool, "thread pool wasn't shutdown");
 }
 
@@ -522,38 +280,21 @@ nsStreamTransportService::IsOnCurrentThr
         pool = mPool;
     }
     NS_ENSURE_TRUE(pool, NS_ERROR_NOT_INITIALIZED);
     return pool->IsOnCurrentThread(result);
 }
 
 NS_IMETHODIMP
 nsStreamTransportService::CreateInputTransport(nsIInputStream *stream,
-                                               int64_t offset,
-                                               int64_t limit,
                                                bool closeWhenDone,
                                                nsITransport **result)
 {
     nsInputStreamTransport *trans =
-        new nsInputStreamTransport(stream, offset, limit, closeWhenDone);
-    if (!trans)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(*result = trans);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsStreamTransportService::CreateOutputTransport(nsIOutputStream *stream,
-                                                int64_t offset,
-                                                int64_t limit,
-                                                bool closeWhenDone,
-                                                nsITransport **result)
-{
-    nsOutputStreamTransport *trans =
-        new nsOutputStreamTransport(stream, offset, limit, closeWhenDone);
+        new nsInputStreamTransport(stream, closeWhenDone);
     if (!trans)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(*result = trans);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStreamTransportService::Observe(nsISupports *subject, const char *topic,
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -3532,19 +3532,17 @@ HttpChannelChild::OverrideWithSynthesize
   } else {
     mSynthesizedStreamLength = int64_t(available);
   }
 
   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
   MOZ_ASSERT(neckoTarget);
 
   rv = nsInputStreamPump::Create(getter_AddRefs(mSynthesizedResponsePump),
-                                 aSynthesizedInput,
-                                 int64_t(-1), int64_t(-1), 0, 0, true,
-                                 neckoTarget);
+                                 aSynthesizedInput, 0, 0, true, neckoTarget);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aSynthesizedInput->Close();
     return;
   }
 
   rv = mSynthesizedResponsePump->AsyncRead(aStreamListener, nullptr);
   NS_ENSURE_SUCCESS_VOID(rv);
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4971,18 +4971,17 @@ nsHttpChannel::OpenCacheInputStream(nsIC
     // background threads.
 
     nsCOMPtr<nsITransport> transport;
     nsCOMPtr<nsIInputStream> wrapper;
 
     nsCOMPtr<nsIStreamTransportService> sts(services::GetStreamTransportService());
     rv = sts ? NS_OK : NS_ERROR_NOT_AVAILABLE;
     if (NS_SUCCEEDED(rv)) {
-        rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1),
-                                        true, getter_AddRefs(transport));
+        rv = sts->CreateInputTransport(stream, true, getter_AddRefs(transport));
     }
     if (NS_SUCCEEDED(rv)) {
         rv = transport->OpenInputStream(0, 0, 0, getter_AddRefs(wrapper));
     }
     if (NS_SUCCEEDED(rv)) {
         LOG(("Opened cache input stream [channel=%p, wrapper=%p, "
               "transport=%p, stream=%p]", this, wrapper.get(),
               transport.get(), stream.get()));
@@ -5111,17 +5110,17 @@ nsHttpChannel::ReadFromCache(bool alread
         NS_ERROR("mCacheInputStream is null but we're expecting to "
                         "be able to read from it.");
         return NS_ERROR_UNEXPECTED;
     }
 
     nsCOMPtr<nsIInputStream> inputStream = mCacheInputStream.forget();
 
     rv = nsInputStreamPump::Create(getter_AddRefs(mCachePump), inputStream,
-                                   int64_t(-1), int64_t(-1), 0, 0, true);
+                                   0, 0, true);
     if (NS_FAILED(rv)) {
         inputStream->Close();
         return rv;
     }
 
     rv = mCachePump->AsyncRead(this, mListenerContext);
     if (NS_FAILED(rv)) return rv;
 
--- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -271,18 +271,18 @@ ExtensionStreamGetter::OnStream(nsIInput
     // The parent didn't send us back a stream.
     listener->OnStartRequest(mChannel, nullptr);
     listener->OnStopRequest(mChannel, nullptr, NS_ERROR_FILE_ACCESS_DENIED);
     mChannel->Cancel(NS_BINDING_ABORTED);
     return;
   }
 
   nsCOMPtr<nsIInputStreamPump> pump;
-  nsresult rv = NS_NewInputStreamPump(getter_AddRefs(pump), aStream, -1, -1, 0,
-                                      0, false, mMainThreadEventTarget);
+  nsresult rv = NS_NewInputStreamPump(getter_AddRefs(pump), aStream, 0, 0,
+                                      false, mMainThreadEventTarget);
   if (NS_FAILED(rv)) {
     mChannel->Cancel(NS_BINDING_ABORTED);
     return;
   }
 
   rv = pump->AsyncRead(listener, nullptr);
   if (NS_FAILED(rv)) {
     mChannel->Cancel(NS_BINDING_ABORTED);
--- a/netwerk/test/unit/head_cache2.js
+++ b/netwerk/test/unit/head_cache2.js
@@ -53,17 +53,17 @@ function LOG_C2(o, m)
 }
 
 function pumpReadStream(inputStream, goon)
 {
   if (inputStream.isNonBlocking()) {
     // non-blocking stream, must read via pump
     var pump = Cc["@mozilla.org/network/input-stream-pump;1"]
                .createInstance(Ci.nsIInputStreamPump);
-    pump.init(inputStream, -1, -1, 0, 0, true);
+    pump.init(inputStream, 0, 0, true);
     var data = "";
     pump.asyncRead({
       onStartRequest: function (aRequest, aContext) { },
       onDataAvailable: function (aRequest, aContext, aInputStream, aOffset, aCount)
       {
         var wrapper = Cc["@mozilla.org/scriptableinputstream;1"].
                       createInstance(Ci.nsIScriptableInputStream);
         wrapper.init(aInputStream);
--- a/netwerk/test/unit/test_backgroundfilesaver.js
+++ b/netwerk/test/unit/test_backgroundfilesaver.js
@@ -207,17 +207,17 @@ function promiseCopyToSaver(aSourceStrin
  */
 function promisePumpToSaver(aSourceString, aSaverStreamListener,
                             aCloseWhenDone) {
   return new Promise((resolve, reject) => {
     aSaverStreamListener.QueryInterface(Ci.nsIStreamListener);
     let inputStream = new StringInputStream(aSourceString, aSourceString.length);
     let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
                .createInstance(Ci.nsIInputStreamPump);
-    pump.init(inputStream, -1, -1, 0, 0, true);
+    pump.init(inputStream, 0, 0, true);
     pump.asyncRead({
       onStartRequest: function PPTS_onStartRequest(aRequest, aContext)
       {
         aSaverStreamListener.onStartRequest(aRequest, aContext);
       },
       onStopRequest: function PPTS_onStopRequest(aRequest, aContext, aStatusCode)
       {
         aSaverStreamListener.onStopRequest(aRequest, aContext, aStatusCode);
--- a/netwerk/test/unit/test_bug376865.js
+++ b/netwerk/test/unit/test_bug376865.js
@@ -1,16 +1,16 @@
 function run_test() {
   var stream = Cc["@mozilla.org/io/string-input-stream;1"].
     createInstance(Ci.nsISupportsCString);
   stream.data = "foo bar baz";
 
   var pump = Cc["@mozilla.org/network/input-stream-pump;1"].
     createInstance(Ci.nsIInputStreamPump);
-  pump.init(stream, -1, -1, 0, 0, false);
+  pump.init(stream, 0, 0, false);
 
   // When we pass a null listener argument too asyncRead we expect it to throw
   // instead of crashing.
   try {
     pump.asyncRead(null, null);
   }
   catch (e) {
     return;
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -23,16 +23,21 @@
 #include "nsIProperties.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/security_level.h"
 #include "WinUtils.h"
 
+// We're just blocking one DLL for the moment because of problems with the
+// Alternate Desktop. If and when we expand this we'll make this a static list
+// and add checking to see if DLL is loaded in the parent.
+#define WEBROOT_DLL L"WRusr.dll"
+
 namespace mozilla
 {
 
 sandbox::BrokerServices *SandboxBroker::sBrokerService = nullptr;
 
 // This is set to true in Initialize when our exe file name has a drive type of
 // DRIVE_REMOTE, so that we can tailor the sandbox policy as some settings break
 // fundamental things when running from a network drive. We default to false in
@@ -427,16 +432,22 @@ SandboxBroker::SetSecurityLevelForConten
     sandbox::MITIGATION_DEP |
     sandbox::MITIGATION_EXTENSION_POINT_DISABLE;
 
   if (aSandboxLevel > 3) {
     result = mPolicy->SetAlternateDesktop(false);
     MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
                        "Failed to create alternate desktop for sandbox.");
 
+    // Webroot SecureAnywhere causes crashes when we use an Alternate Desktop,
+    // so block the DLL from loading in the child process. (bug 1400637)
+    result = mPolicy->AddDllToUnload(WEBROOT_DLL);
+    MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
+                       "AddDllToUnload should never fail, what happened?");
+
     mitigations |= sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL;
     // If we're running from a network drive then we can't block loading from
     // remote locations.
     if (!sRunningFromNetworkDrive) {
       mitigations |= sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE;
     }
   }
 
@@ -799,16 +810,22 @@ SandboxBroker::SetSecurityLevelForGMPlug
   result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, level);
   SANDBOX_ENSURE_SUCCESS(result,
                          "SetTokenLevel should never fail with these arguments, what happened?");
 
   result = mPolicy->SetAlternateDesktop(true);
   SANDBOX_ENSURE_SUCCESS(result,
                          "Failed to create alternate desktop for sandbox.");
 
+  // Webroot SecureAnywhere causes crashes when we use an Alternate Desktop,
+  // so block the DLL from loading in the child process. (bug 1400637)
+  result = mPolicy->AddDllToUnload(WEBROOT_DLL);
+  MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
+                     "AddDllToUnload should never fail, what happened?");
+
   result = mPolicy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   MOZ_ASSERT(sandbox::SBOX_ALL_OK == result,
              "SetIntegrityLevel should never fail with these arguments, what happened?");
 
   result =
     mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
   SANDBOX_ENSURE_SUCCESS(result,
                          "SetIntegrityLevel should never fail with these arguments, what happened?");
--- a/taskcluster/taskgraph/transforms/job/mozharness_test.py
+++ b/taskcluster/taskgraph/transforms/job/mozharness_test.py
@@ -54,16 +54,17 @@ BUILDER_NAME_PREFIX = {
 }
 
 VARIANTS = [
     'nightly',
     'devedition',
     'pgo',
     'asan',
     'stylo',
+    'stylo disabled',
     'stylo-sequential',
     'qr',
     'ccov',
     'jsdcov',
 ]
 
 
 def get_variant(test_platform):
@@ -468,17 +469,17 @@ def mozharness_test_buildbot_bridge(conf
         variant = get_variant(test['test-platform'])
 
         # On beta and release, we run nightly builds on-push; the talos
         # builders need to run against non-nightly buildernames
         if variant == 'nightly':
             variant = ''
 
         # this variant name has branch after the variant type in BBB bug 1338871
-        if variant in ('qr', 'stylo', 'stylo-sequential', 'devedition'):
+        if variant in ('qr', 'stylo', 'stylo-sequential', 'devedition', 'stylo disabled'):
             name = '{prefix} {variant} {branch} talos {test_name}'
         elif variant:
             name = '{prefix} {branch} {variant} talos {test_name}'
         else:
             name = '{prefix} {branch} talos {test_name}'
 
         buildername = name.format(
             prefix=BUILDER_NAME_PREFIX[test_platform],
--- a/testing/mozharness/configs/merge_day/beta_to_release.py
+++ b/testing/mozharness/configs/merge_day/beta_to_release.py
@@ -16,23 +16,16 @@ config = {
         "ac_add_options --with-branding=mobile/android/branding/beta",
         "ac_add_options --with-branding=mobile/android/branding/official")
         for d in ["mobile/android/config/mozconfigs/android-api-16/",
                   "mobile/android/config/mozconfigs/android-x86/",
                   "mobile/android/config/mozconfigs/android-aarch64/"]
         for f in ["debug", "nightly", "l10n-nightly"]
     ] + [
         # File, from, to
-        (f, "ac_add_options --with-l10n-base=../../mozilla-beta",
-        "ac_add_options --with-l10n-base=../../mozilla-release")
-        for f in ["mobile/android/config/mozconfigs/android-api-16/l10n-nightly",
-                  "mobile/android/config/mozconfigs/android-x86/l10n-nightly",
-                  "mobile/android/config/mozconfigs/android-aarch64/l10n-nightly"]
-    ] + [
-        # File, from, to
         ("browser/confvars.sh",
          "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-beta,firefox-mozilla-release",
          "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-release"),
         ("browser/confvars.sh",
          "MAR_CHANNEL_ID=firefox-mozilla-beta",
          "MAR_CHANNEL_ID=firefox-mozilla-release"),
     ],
 
--- a/testing/mozharness/configs/merge_day/central_to_beta.py
+++ b/testing/mozharness/configs/merge_day/central_to_beta.py
@@ -24,23 +24,16 @@ config = {
         "ac_add_options --enable-official-branding")
         for f in ["browser/config/mozconfigs/linux32/l10n-mozconfig",
                   "browser/config/mozconfigs/linux64/l10n-mozconfig",
                   "browser/config/mozconfigs/win32/l10n-mozconfig",
                   "browser/config/mozconfigs/win64/l10n-mozconfig",
                   "browser/config/mozconfigs/macosx64/l10n-mozconfig"]
     ] + [
         # File, from, to
-        (f, "ac_add_options --with-l10n-base=../../l10n-central",
-        "ac_add_options --with-l10n-base=../../mozilla-beta")
-        for f in ["mobile/android/config/mozconfigs/android-api-16/l10n-nightly",
-                  "mobile/android/config/mozconfigs/android-x86/l10n-nightly",
-                  "mobile/android/config/mozconfigs/android-aarch64/l10n-nightly"]
-    ] + [
-        # File, from, to
         (f, "ac_add_options --enable-profiling", "") for f in
         ["mobile/android/config/mozconfigs/android-api-16/nightly",
          "mobile/android/config/mozconfigs/android-x86/nightly",
          "mobile/android/config/mozconfigs/android-aarch64/nightly",
          "browser/config/mozconfigs/linux32/nightly",
          "browser/config/mozconfigs/linux64/nightly",
          "browser/config/mozconfigs/macosx64/nightly",
          "browser/config/mozconfigs/win32/nightly",
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -155132,28 +155132,16 @@
       [
        "/css/selectors4/selector-read-write-type-change-002-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
-   "css/selectors4/selector-required.html": [
-    [
-     "/css/selectors4/selector-required.html",
-     [
-      [
-       "/css/selectors4/selector-required-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/selectors4/selector-required-type-change-001.html": [
     [
      "/css/selectors4/selector-required-type-change-001.html",
      [
       [
        "/css/selectors4/selector-required-type-change-001-ref.html",
        "=="
       ]
@@ -155168,16 +155156,28 @@
       [
        "/css/selectors4/selector-required-type-change-002-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
+   "css/selectors4/selector-required.html": [
+    [
+     "/css/selectors4/selector-required.html",
+     [
+      [
+       "/css/selectors4/selector-required-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/selectors4/selectors-dir-selector-ltr-001.html": [
     [
      "/css/selectors4/selectors-dir-selector-ltr-001.html",
      [
       [
        "/css/reference/ref-filled-green-100px-square.xht",
        "=="
       ]
@@ -337716,16 +337716,22 @@
     ]
    ],
    "cssom-view/offsetParent_element_test.html": [
     [
      "/cssom-view/offsetParent_element_test.html",
      {}
     ]
    ],
+   "cssom-view/offsetTopLeftInScrollableParent.html": [
+    [
+     "/cssom-view/offsetTopLeftInScrollableParent.html",
+     {}
+    ]
+   ],
    "cssom-view/scrollIntoView-empty-args.html": [
     [
      "/cssom-view/scrollIntoView-empty-args.html",
      {}
     ]
    ],
    "cssom-view/scrollIntoView-shadow.html": [
     [
@@ -548962,74 +548968,74 @@
    "59f848418882c75898c422a9600c14ffab64c3d9",
    "support"
   ],
   "css/selectors4/of-type-selectors.xhtml": [
    "607553f41a33ce3630752cdf027c9f904833a19d",
    "reftest"
   ],
   "css/selectors4/selector-placeholder-shown-type-change-001-ref.html": [
-    "92303d06943581738f58ff5d342ef1336539f66a",
-    "support"
+   "92303d06943581738f58ff5d342ef1336539f66a",
+   "support"
+  ],
+  "css/selectors4/selector-placeholder-shown-type-change-001.html": [
+   "afb7a260d6f1c7da337a1f20a62778d1d6e302c4",
+   "reftest"
   ],
   "css/selectors4/selector-placeholder-shown-type-change-002-ref.html": [
-    "ac3a88a758fd0ccc67077993d59bfb34eadf3931",
-    "support"
-  ],
-  "css/selectors4/selector-placeholder-shown-type-change-003-ref.html": [
-    "ac3a88a758fd0ccc67077993d59bfb34eadf3931",
-    "support"
-  ],
-  "css/selectors4/selector-placeholder-shown-type-change-001.html": [
-    "afb7a260d6f1c7da337a1f20a62778d1d6e302c4",
-    "reftest"
+   "ac3a88a758fd0ccc67077993d59bfb34eadf3931",
+   "support"
   ],
   "css/selectors4/selector-placeholder-shown-type-change-002.html": [
-    "df0cbd1b178d72de9f70d0e603c30858508c2edd",
-    "reftest"
+   "a0872a296c81ab57649c963304269c7f38e7e4b7",
+   "reftest"
+  ],
+  "css/selectors4/selector-placeholder-shown-type-change-003-ref.html": [
+   "ac3a88a758fd0ccc67077993d59bfb34eadf3931",
+   "support"
   ],
   "css/selectors4/selector-placeholder-shown-type-change-003.html": [
-    "36046107e0f3763e219a2316ab6232785a325257",
-    "reftest"
+   "37ba577eeb816bec60a2ee44569001b1a6f76bcf",
+   "reftest"
   ],
   "css/selectors4/selector-read-write-type-change-001-ref.html": [
-    "812f07e03f5bbf86feb2d8eefe17aeaa7bd69970",
-    "support"
+   "812f07e03f5bbf86feb2d8eefe17aeaa7bd69970",
+   "support"
   ],
   "css/selectors4/selector-read-write-type-change-001.html": [
-    "95da0fbd6aafb8dcecb6f39e5cc8572f536e7eb5",
-    "reftest"
+   "95da0fbd6aafb8dcecb6f39e5cc8572f536e7eb5",
+   "reftest"
   ],
   "css/selectors4/selector-read-write-type-change-002-ref.html": [
-    "3579aa13253d99a430ce17ba1acd629a22261097",
-    "support"
+   "3579aa13253d99a430ce17ba1acd629a22261097",
+   "support"
   ],
   "css/selectors4/selector-read-write-type-change-002.html": [
-    "0bb1111fd76582a433204bce32852fc0a5dc5458",
-    "reftest"
+   "0bb1111fd76582a433204bce32852fc0a5dc5458",
+   "reftest"
   ],
   "css/selectors4/selector-required-ref.html": [
    "815bc765614b4c2e3d8f8f6303e6bb2ee0989c23",
    "support"
   ],
   "css/selectors4/selector-required-type-change-001-ref.html": [
-    "812f07e03f5bbf86feb2d8eefe17aeaa7bd69970",
-    "support"
+   "812f07e03f5bbf86feb2d8eefe17aeaa7bd69970",
+   "support"
   ],
   "css/selectors4/selector-required-type-change-001.html": [
-    "211b7b71cf1073dd15491b78b0152f9b7a5e9aec",
-    "reftest"
+   "211b7b71cf1073dd15491b78b0152f9b7a5e9aec",
+   "reftest"
   ],
   "css/selectors4/selector-required-type-change-002-ref.html": [
-    "3579aa13253d99a430ce17ba1acd629a22261097",
-    "support"
+   "3579aa13253d99a430ce17ba1acd629a22261097",
+   "support"
   ],
   "css/selectors4/selector-required-type-change-002.html": [
-    "f27dbc7bd1e2aa0753bcae73fdf2d83f7248118a",
-    "reftest"
+   "f27dbc7bd1e2aa0753bcae73fdf2d83f7248118a",
+   "reftest"
   ],
   "css/selectors4/selector-required.html": [
    "601b8b8426c64717f82831e6258f8fe4188c797c",
    "reftest"
   ],
   "css/selectors4/selectors-dir-selector-ltr-001.html": [
    "3682f8a499ad2a1348f620b33b83944c0dc90788",
    "reftest"
@@ -578653,16 +578659,20 @@
   "cssom-view/negativeMargins.html": [
    "ad44e3f4ba132bfb4a522b14a4ff5356dbbbad14",
    "testharness"
   ],
   "cssom-view/offsetParent_element_test.html": [
    "b2261ec702116c211ab5ac6fbb53698dfe60a7be",
    "testharness"
   ],
+  "cssom-view/offsetTopLeftInScrollableParent.html": [
+   "79b4a278f0e35646cfdffeebf8f0523e2772bc9b",
+   "testharness"
+  ],
   "cssom-view/resources/elementsFromPoint.js": [
    "0c31158817d4d6f9e59df0d2ebe0e41c6ce41bb5",
    "support"
   ],
   "cssom-view/resources/iframe1.html": [
    "ec93f617bdc7b0055d96c7b00ab7832cca1c1af0",
    "support"
   ],
@@ -624014,17 +624024,17 @@
    "4db5bfbf0f1afcace2a4ea79451c2ff5fc09ab3c",
    "testharness"
   ],
   "service-workers/service-worker/postmessage.https.html": [
    "ea380417fcad1583f764473c554bf519e5beecde",
    "testharness"
   ],
   "service-workers/service-worker/ready.https.html": [
-   "ff14496607e396281d28fb9a8bfdcbb46b8a7e9c",
+   "1f479de232c8e847fcaa31bb5ed869fe070054b6",
    "testharness"
   ],
   "service-workers/service-worker/redirected-response.https.html": [
    "38b406b1d9fd32296a72b264e2d7ccb0effed619",
    "testharness"
   ],
   "service-workers/service-worker/referer.https.html": [
    "a9e4073192f5b69984624ad7376ec7787101dfea",
--- a/testing/web-platform/meta/custom-elements/adopted-callback.html.ini
+++ b/testing/web-platform/meta/custom-elements/adopted-callback.html.ini
@@ -1,13 +1,10 @@
 [adopted-callback.html]
   type: testharness
-  [Inserting a custom element into the owner document must not enqueue and invoke adoptedCallback]
-    expected: FAIL
-
   [Inserting a custom element into the document of the template elements must enqueue and invoke adoptedCallback]
     expected: FAIL
 
   [Moving a custom element from the owner document into the document of the template elements must enqueue and invoke adoptedCallback]
     expected: FAIL
 
   [Inserting an ancestor of custom element into the document of the template elements must enqueue and invoke adoptedCallback]
     expected: FAIL
--- a/testing/web-platform/meta/custom-elements/connected-callbacks.html.ini
+++ b/testing/web-platform/meta/custom-elements/connected-callbacks.html.ini
@@ -1,121 +1,73 @@
 [connected-callbacks.html]
   type: testharness
-  [Inserting a custom element into the document must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into the document must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in the document must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into the document must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to the document must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into the document of the template elements must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into the document of the template elements must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in the document of the template elements must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into the document of the template elements must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to the document of the template elements must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into a new document must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into a new document must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in a new document must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into a new document must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to a new document must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into a cloned document must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into a cloned document must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in a cloned document must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into a cloned document must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to a cloned document must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into a document created by createHTMLDocument must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into a document created by createHTMLDocument must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in a document created by createHTMLDocument must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into a document created by createHTMLDocument must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to a document created by createHTMLDocument must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into an HTML document created by createDocument must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into an HTML document created by createDocument must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in an HTML document created by createDocument must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into an HTML document created by createDocument must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to an HTML document created by createDocument must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into the document of an iframe must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into the document of an iframe must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in the document of an iframe must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into the document of an iframe must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to the document of an iframe must not enqueue and invoke connectedCallback]
     expected: FAIL
 
-  [Inserting a custom element into an HTML document fetched by XHR must enqueue and invoke connectedCallback]
-    expected: FAIL
-
-  [Inserting an ancestor of custom element into an HTML document fetched by XHR must enqueue and invoke connectedCallback]
-    expected: FAIL
-
   [Inserting a custom element into a shadow tree in an HTML document fetched by XHR must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting the shadow host of a custom element into an HTML document fetched by XHR must enqueue and invoke connectedCallback]
     expected: FAIL
 
   [Inserting a custom element into a detached shadow tree that belongs to an HTML document fetched by XHR must not enqueue and invoke connectedCallback]
     expected: FAIL
--- a/testing/web-platform/meta/custom-elements/custom-element-reaction-queue.html.ini
+++ b/testing/web-platform/meta/custom-elements/custom-element-reaction-queue.html.ini
@@ -1,11 +1,5 @@
 [custom-element-reaction-queue.html]
   type: testharness
-  [Upgrading a custom element must invoke attributeChangedCallback and connectedCallback before start upgrading another element]
-    expected: FAIL
-
-  [Mutating a undefined custom element while upgrading a custom element must not enqueue or invoke reactions on the mutated element]
-    expected: FAIL
-
   [Mutating another custom element inside adopted callback must invoke all pending callbacks on the mutated element]
     expected: FAIL
 
--- a/testing/web-platform/meta/custom-elements/disconnected-callbacks.html.ini
+++ b/testing/web-platform/meta/custom-elements/disconnected-callbacks.html.ini
@@ -1,121 +1,73 @@
 [disconnected-callbacks.html]
   type: testharness
-  [Removing a custom element from the document must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from the document must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in the document must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from athe document must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to the document must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from the document of the template elements must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from the document of the template elements must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in the document of the template elements must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from athe document of the template elements must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to the document of the template elements must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from a new document must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from a new document must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in a new document must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from aa new document must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to a new document must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from a cloned document must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from a cloned document must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in a cloned document must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from aa cloned document must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to a cloned document must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from a document created by createHTMLDocument must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from a document created by createHTMLDocument must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in a document created by createHTMLDocument must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from aa document created by createHTMLDocument must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to a document created by createHTMLDocument must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from an HTML document created by createDocument must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from an HTML document created by createDocument must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in an HTML document created by createDocument must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from aan HTML document created by createDocument must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to an HTML document created by createDocument must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from the document of an iframe must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from the document of an iframe must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in the document of an iframe must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from athe document of an iframe must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to the document of an iframe must not enqueue and invoke disconnectedCallback]
     expected: FAIL
 
-  [Removing a custom element from an HTML document fetched by XHR must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
-  [Removing an ancestor of custom element from an HTML document fetched by XHR must enqueue and invoke disconnectedCallback]
-    expected: FAIL
-
   [Removing a custom element from a shadow tree in an HTML document fetched by XHR must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing the shadow host of a custom element from aan HTML document fetched by XHR must enqueue and invoke disconnectedCallback]
     expected: FAIL
 
   [Removing a custom element from a detached shadow tree that belongs to an HTML document fetched by XHR must not enqueue and invoke disconnectedCallback]
     expected: FAIL
--- a/testing/web-platform/meta/custom-elements/reactions/ChildNode.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/ChildNode.html.ini
@@ -1,26 +1,10 @@
 [ChildNode.html]
   type: testharness
-  [before on ChildNode must enqueue a connected reaction]
-    expected: FAIL
-
   [before on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
-  [after on ChildNode must enqueue a connected reaction]
-    expected: FAIL
-
   [after on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
-  [replaceWith on ChildNode must enqueue a connected reaction]
-    expected: FAIL
-
   [replaceWith on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
-
-  [replaceWith on ChildNode must enqueue a disconnected reaction]
-    expected: FAIL
-
-  [remove on ChildNode must enqueue a disconnected reaction]
-    expected: FAIL
-
--- a/testing/web-platform/meta/custom-elements/reactions/Document.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/Document.html.ini
@@ -7,25 +7,19 @@
     expected: FAIL
 
   [importNode on Document must construct a new custom element when importing a custom element from a template]
     expected: FAIL
 
   [execCommand on Document must enqueue a disconnected reaction when deleting a custom element from a contenteditable element]
     expected: FAIL
 
-  [title on Document must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
   [body on Document must enqueue disconnectedCallback when removing a custom element]
     expected: FAIL
 
-  [body on Document must enqueue connectedCallback when inserting a custom element]
-    expected: FAIL
-
   [open on Document must enqueue disconnectedCallback when removing a custom element]
     expected: FAIL
 
   [write on Document must enqueue disconnectedCallback when removing a custom element]
     expected: FAIL
 
   [write on Document must enqueue connectedCallback after constructing a custom element]
     expected: FAIL
--- a/testing/web-platform/meta/custom-elements/reactions/Element.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/Element.html.ini
@@ -14,40 +14,31 @@
 
   [removeAttributeNode on Element must not enqueue an attributeChanged reaction when removing an attribute that does not exist]
     expected: FAIL
 
   [undefined must enqueue a connected reaction]
     expected: FAIL
 
   [undefined must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
-    expected: FAIL
-
-  [insertAdjacentElement on Element must enqueue a connected reaction]
-    expected: FAIL
+    expected: FAIL 
 
   [insertAdjacentElement on Element must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
   [innerHTML on Element must enqueue a connected reaction for a newly constructed custom element]
     expected: FAIL
 
   [innerHTML on Element must enqueue a attributeChanged reaction for a newly constructed custom element]
     expected: FAIL
 
-  [innerHTML on Element must enqueue a disconnected reaction]
-    expected: FAIL
-
   [outerHTML on Element must enqueue a connected reaction for a newly constructed custom element]
     expected: FAIL
 
   [outerHTML on Element must enqueue a attributeChanged reaction for a newly constructed custom element]
     expected: FAIL
 
-  [outerHTML on Element must enqueue a disconnected reaction]
-    expected: FAIL
-
   [insertAdjacentHTML on Element must enqueue a connected reaction for a newly constructed custom element]
     expected: FAIL
 
   [insertAdjacentHTML on Element must enqueue a attributeChanged reaction for a newly constructed custom element]
     expected: FAIL
 
--- a/testing/web-platform/meta/custom-elements/reactions/HTMLElement.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/HTMLElement.html.ini
@@ -13,11 +13,8 @@
     expected: FAIL
 
   [contextMenu on HTMLElement must enqueue an attributeChanged reaction when adding contextmenu content attribute]
     expected: FAIL
 
   [contextMenu on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
     expected: FAIL
 
-  [innerText on HTMLElement must enqueue a disconnected reaction]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/reactions/HTMLOptionsCollection.html.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[HTMLOptionsCollection.html]
-  type: testharness
-  [length on HTMLOptionsCollection must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
-  [The indexed setter on HTMLOptionsCollection must enqueue connectedCallback when inserting a custom element]
-    expected: FAIL
-
-  [The indexed setter on HTMLOptionsCollection must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
-  [add on HTMLOptionsCollection must enqueue connectedCallback when inserting a custom element]
-    expected: FAIL
-
-  [remove on HTMLOptionsCollection must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/reactions/HTMLSelectElement.html.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[HTMLSelectElement.html]
-  type: testharness
-  [length on HTMLSelectElement must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
-  [The indexed setter on HTMLSelectElement must enqueue connectedCallback when inserting a custom element]
-    expected: FAIL
-
-  [The indexed setter on HTMLSelectElement must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
-  [add on HTMLSelectElement must enqueue connectedCallback when inserting a custom element]
-    expected: FAIL
-
-  [remove on HTMLSelectElement must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/reactions/HTMLTitleElement.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[HTMLTitleElement.html]
-  type: testharness
-  [text on HTMLTitleElement must enqueue disconnectedCallback when removing a custom element]
-    expected: FAIL
-
--- a/testing/web-platform/meta/custom-elements/reactions/Node.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/Node.html.ini
@@ -4,29 +4,16 @@
     expected: FAIL
 
   [cloneNode on Node must not enqueue an attributeChanged reaction when cloning an element with an unobserved attribute]
     expected: FAIL
 
   [cloneNode on Node must enqueue an attributeChanged reaction when cloning an element only for observed attributes]
     expected: FAIL
 
-  [insertBefore on ChildNode must enqueue a connected reaction]
-    expected: FAIL
-
   [insertBefore on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
-  [appendChild on ChildNode must enqueue a connected reaction]
-    expected: FAIL
-
   [appendChild on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
-  [replaceChild on ChildNode must enqueue a connected reaction]
-    expected: FAIL
-
   [replaceChild on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
-
-  [removeChild on ChildNode must enqueue a disconnected reaction]
-    expected: FAIL
-
--- a/testing/web-platform/meta/custom-elements/reactions/ParentNode.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/ParentNode.html.ini
@@ -1,14 +1,8 @@
 [ParentNode.html]
   type: testharness
-  [prepend on ParentNode must enqueue a connected reaction]
-    expected: FAIL
-
   [prepend on ParentNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
-  [append on ParentNode must enqueue a connected reaction]
-    expected: FAIL
-
   [append on ParentNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
--- a/testing/web-platform/meta/custom-elements/reactions/Range.html.ini
+++ b/testing/web-platform/meta/custom-elements/reactions/Range.html.ini
@@ -1,32 +1,20 @@
 [Range.html]
   type: testharness
-  [deleteContents on Range must enqueue a disconnected reaction]
-    expected: FAIL
-
-  [extractContents on Range must enqueue a disconnected reaction]
-    expected: FAIL
-
   [cloneContents on Range must enqueue an attributeChanged reaction when cloning an element with an observed attribute]
     expected: FAIL
 
   [cloneContents on Range must not enqueue an attributeChanged reaction when cloning an element with an unobserved attribute]
     expected: FAIL
 
   [cloneContents on Range must enqueue an attributeChanged reaction when cloning an element only for observed attributes]
     expected: FAIL
 
-  [insertNode on Range must enqueue a connected reaction]
-    expected: FAIL
-
   [insertNode on Range must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
-  [surroundContents on Range must enqueue a connected reaction]
-    expected: FAIL
-
   [surroundContents on Range must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
     expected: FAIL
 
   [createContextualFragment on Range must construct a custom element]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/reactions/Selection.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[Selection.html]
-  type: testharness
-  [deleteFromDocument on Selection must enqueue a disconnected reaction]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/custom-elements/upgrading/upgrading-enqueue-reactions.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[upgrading-enqueue-reactions.html]
-  type: testharness
-  [Upgrading a custom element must enqueue connectedCallback if the element in the document]
-    expected: FAIL
-
-  [Upgrading a custom element must enqueue attributeChangedCallback before connectedCallback]
-    expected: FAIL
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/cssom-view/offsetTopLeftInScrollableParent.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<div id="parent" style="overflow:scroll; height: 100px; position: relative">
+  <div id="spacer" style="height: 200px"></div>
+  <div id="child"></div>
+  <div id="absolute-child" style="position: absolute; top: 41px; left: 43px"></div>
+</div>
+<script>
+test(function() {
+    var child = document.getElementById("child");
+    assert_equals(child.offsetTop, 200, "Child is after spacer");
+    assert_equals(child.offsetLeft, 0, "Child is flush left");
+    var absChild = document.getElementById("absolute-child");
+    assert_equals(absChild.offsetTop, 41, "Abspos child is y-positioned");
+    assert_equals(absChild.offsetLeft, 43, "Abspos child is x-positioned");
+}, "Basic functionality");
+
+test(function() {
+    var parent = document.getElementById("parent");
+    parent.scrollTop = 100;
+    var child = document.getElementById("child");
+    assert_equals(child.offsetTop, 200, "Child is after spacer");
+    assert_equals(child.offsetLeft, 0, "Child is flush left");
+    var absChild = document.getElementById("absolute-child");
+    assert_equals(absChild.offsetTop, 41, "Abspos child is y-positioned");
+    assert_equals(absChild.offsetLeft, 43, "Abspos child is x-positioned");
+}, "Basic functionality in scrolled parent");
+
+test(function() {
+    var child = document.getElementById("child");
+    child.style.marginTop = "20px"
+    child.style.marginLeft = "100px";
+    assert_equals(child.offsetTop, 220, "Child is after spacer and margin");
+    assert_equals(child.offsetLeft, 100, "Child is 100px from left");
+    var absChild = document.getElementById("absolute-child");
+    absChild.style.marginTop = "20px"
+    absChild.style.marginLeft = "100px";
+    assert_equals(absChild.offsetTop, 61, "Abspos child is y-positioned and has margin");
+    assert_equals(absChild.offsetLeft, 143, "Abspos child is x-positioned and has margin");
+}, "Margins on child");
+
+test(function() {
+    var parent = document.getElementById("parent");
+    parent.style.marginTop = "66px"
+    parent.style.marginLeft = "33px";
+    var child = document.getElementById("child");
+    assert_equals(child.offsetTop, 220, "Child is after spacer and margin");
+    assert_equals(child.offsetLeft, 100, "Child is 100px from left");
+    var absChild = document.getElementById("absolute-child");
+    assert_equals(absChild.offsetTop, 61, "Abspos child is y-positioned and has margin");
+    assert_equals(absChild.offsetLeft, 143, "Abspos child is x-positioned and has margin");
+}, "Margins on child and parent");
+
+test(function() {
+    var child = document.getElementById("child");
+    child.style.borderTop = "13px solid green";
+    child.style.borderLeft = "7px solid green";
+    assert_equals(child.offsetTop, 220, "Child is after spacer and margin");
+    assert_equals(child.offsetLeft, 100, "Child is 100px from left");
+    var absChild = document.getElementById("absolute-child");
+    absChild.style.borderTop = "13px solid green";
+    absChild.style.borderLeft = "7px solid green";
+    assert_equals(absChild.offsetTop, 61, "Abspos child is y-positioned and has margin");
+    assert_equals(absChild.offsetLeft, 143, "Abspos child is x-positioned and has margin");
+}, "Margins on child and parent, border on child");
+
+test(function() {
+    var parent = document.getElementById("parent");
+    parent.style.borderTop = "23px solid yellow";
+    parent.style.borderLeft = "19px solid yellow";
+    var child = document.getElementById("child");
+    assert_equals(child.offsetTop, 220, "Child is after spacer and margin");
+    assert_equals(child.offsetLeft, 100, "Child is 100px from left");
+    var absChild = document.getElementById("absolute-child");
+    assert_equals(absChild.offsetTop, 61, "Abspos child is y-positioned and has margin");
+    assert_equals(absChild.offsetLeft, 143, "Abspos child is x-positioned and has margin");
+}, "Margins on child and parent, border on child and parent");
+
+
+test(function() {
+    var child = document.getElementById("child");
+    child.style.paddingTop = "31px";
+    child.style.paddingLeft = "37px";
+    assert_equals(child.offsetTop, 220, "Child is after spacer and margin");
+    assert_equals(child.offsetLeft, 100, "Child is 100px from left");
+    var absChild = document.getElementById("absolute-child");
+    absChild.style.paddingTop = "31px";
+    absChild.style.paddingLeft = "37px";
+    assert_equals(absChild.offsetTop, 61, "Abspos child is y-positioned and has margin");
+    assert_equals(absChild.offsetLeft, 143, "Abspos child is x-positioned and has margin");
+}, "Margins on child and parent, border on child and parent, padding on child");
+
+
+test(function() {
+    var parent = document.getElementById("parent");
+    parent.style.paddingTop = "31px";
+    parent.style.paddingLeft = "37px";
+    var child = document.getElementById("child");
+    assert_equals(child.offsetTop, 251, "Child is after spacer and margin and parent padding");
+    assert_equals(child.offsetLeft, 137, "Child is 100px + parent padding from left");
+    var absChild = document.getElementById("absolute-child");
+    // Padding on the parent does not affect the position of the absolute containing block.
+    assert_equals(absChild.offsetTop, 61, "Abspos child is y-positioned and has margin");
+    assert_equals(absChild.offsetLeft, 143, "Abspos child is x-positioned and has margin");
+}, "Margins on child and parent, border on child and parent, padding on child and parent");
+
+</script>
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -165,17 +165,17 @@ private:
   // as part of our nsIStreamListener implementation and may contain embedded
   // NULLs.
   nsCString mResponse;
 
   // Returns true if the file is likely to be binary.
   bool IsBinaryFile();
 
   // Returns the type of download binary for the file.
-  ClientDownloadRequest::DownloadType GetDownloadType(const nsAString& aFilename);
+  ClientDownloadRequest::DownloadType GetDownloadType(const nsACString& aFilename);
 
   // Clean up and call the callback. PendingLookup must not be used after this
   // function is called.
   nsresult OnComplete(bool shouldBlock, nsresult rv,
     uint32_t verdict = nsIApplicationReputationService::VERDICT_SAFE);
 
   // Wrapper function for nsIStreamListener.onStopRequest to make it easy to
   // guarantee calling the callback
@@ -396,356 +396,356 @@ PendingLookup::PendingLookup(nsIApplicat
   LOG(("Created pending lookup [this = %p]", this));
 }
 
 PendingLookup::~PendingLookup()
 {
   LOG(("Destroying pending lookup [this = %p]", this));
 }
 
-static const char16_t* const kBinaryFileExtensions[] = {
+static const char* const kBinaryFileExtensions[] = {
     // Extracted from the "File Type Policies" Chrome extension
-    //u".001",
-    //u".7z",
-    //u".ace",
-    //u".action", // Mac script
-    //u".ad", // Windows
-    u".ade", // MS Access
-    u".adp", // MS Access
-    u".apk", // Android package
-    u".app", // Executable application
-    u".application", // MS ClickOnce
-    u".appref-ms", // MS ClickOnce
-    //u".arc",
-    //u".arj",
-    u".as", // Mac archive
-    u".asp", // Windows Server script
-    u".asx", // Windows Media Player
-    //u".b64",
-    //u".balz",
-    u".bas", // Basic script
-    u".bash", // Linux shell
-    u".bat", // Windows shell
-    //u".bhx",
-    //u".bin",
-    u".bz", // Linux archive (bzip)
-    u".bz2", // Linux archive (bzip2)
-    u".bzip2", // Linux archive (bzip2)
-    u".cab", // Windows archive
-    u".cdr", // Mac disk image
-    u".cfg", // Windows
-    u".chi", // Windows Help
-    u".chm", // Windows Help
-    u".class", // Java
-    u".cmd", // Windows executable
-    u".com", // Windows executable
-    u".command", // Mac script
-    u".cpgz", // Mac archive
-    //u".cpio",
-    u".cpl", // Windows executable
-    u".crt", // Windows signed certificate
-    u".crx", // Chrome extensions
-    u".csh", // Linux shell
-    u".dart", // Mac disk image
-    u".dc42", // Apple DiskCopy Image
-    u".deb", // Linux package
-    u".dex", // Android
-    u".diskcopy42", // Apple DiskCopy Image
-    u".dll", // Windows executable
-    u".dmg", // Mac disk image
-    u".dmgpart", // Mac disk image
-    //u".docb", // MS Office
-    //u".docm", // MS Word
-    //u".docx", // MS Word
-    //u".dotm", // MS Word
-    //u".dott", // MS Office
-    u".drv", // Windows driver
-    u".dvdr", // Mac Disk image
-    u".efi", // Firmware
-    u".eml", // MS Outlook
-    u".exe", // Windows executable
-    //u".fat",
-    u".fon", // Windows font
-    u".fxp", // MS FoxPro
-    u".gadget", // Windows
-    u".grp", // Windows
-    u".gz", // Linux archive (gzip)
-    u".gzip", // Linux archive (gzip)
-    u".hfs", // Mac disk image
-    u".hlp", // Windows Help
-    u".hqx", // Mac archive
-    u".hta", // HTML trusted application
-    u".htm",
-    u".html",
-    u".htt", // MS HTML template
-    u".img", // Mac disk image
-    u".imgpart", // Mac disk image
-    u".inf", // Windows installer
-    u".ini", // Generic config file
-    u".ins", // IIS config
-    //u".inx", // InstallShield
-    u".iso", // CD image
-    u".isp", // IIS config
-    //u".isu", // InstallShield
-    u".jar", // Java
-    u".jnlp", // Java
-    //u".job", // Windows
-    u".js", // JavaScript script
-    u".jse", // JScript
-    u".ksh", // Linux shell
-    //u".lha",
-    u".lnk", // Windows
-    u".local", // Windows
-    //u".lpaq1",
-    //u".lpaq5",
-    //u".lpaq8",
-    //u".lzh",
-    //u".lzma",
-    u".mad", // MS Access
-    u".maf", // MS Access
-    u".mag", // MS Access
-    u".mam", // MS Access
-    u".manifest", // Windows
-    u".maq", // MS Access
-    u".mar", // MS Access
-    u".mas", // MS Access
-    u".mat", // MS Access
-    u".mau", // Media attachment
-    u".mav", // MS Access
-    u".maw", // MS Access
-    u".mda", // MS Access
-    u".mdb", // MS Access
-    u".mde", // MS Access
-    u".mdt", // MS Access
-    u".mdw", // MS Access
-    u".mdz", // MS Access
-    u".mht", // MS HTML
-    u".mhtml", // MS HTML
-    u".mim", // MS Mail
-    u".mmc", // MS Office
-    u".mof", // Windows
-    u".mpkg", // Mac installer
-    u".msc", // Windows executable
-    u".msg", // MS Outlook
-    u".msh", // Windows shell
-    u".msh1", // Windows shell
-    u".msh1xml", // Windows shell
-    u".msh2", // Windows shell
-    u".msh2xml", // Windows shell
-    u".mshxml", // Windows
-    u".msi", // Windows installer
-    u".msp", // Windows installer
-    u".mst", // Windows installer
-    u".ndif", // Mac disk image
-    //u".ntfs", // 7z
-    u".ocx", // ActiveX
-    u".ops", // MS Office
-    //u".out", // Linux binary
-    //u".paf", // PortableApps package
-    //u".paq8f",
-    //u".paq8jd",
-    //u".paq8l",
-    //u".paq8o",
-    u".partial", // Downloads
-    u".pax", // Mac archive
-    u".pcd", // Microsoft Visual Test
-    u".pdf", // Adobe Acrobat
-    //u".pea",
-    u".pet", // Linux package
-    u".pif", // Windows
-    u".pkg", // Mac installer
-    u".pl", // Perl script
-    u".plg", // MS Visual Studio
-    //u".potx", // MS PowerPoint
-    //u".ppam", // MS PowerPoint
-    //u".ppsx", // MS PowerPoint
-    //u".pptm", // MS PowerPoint
-    //u".pptx", // MS PowerPoint
-    u".prf", // MS Outlook
-    u".prg", // Windows
-    u".ps1", // Windows shell
-    u".ps1xml", // Windows shell
-    u".ps2", // Windows shell
-    u".ps2xml", // Windows shell
-    u".psc1", // Windows shell
-    u".psc2", // Windows shell
-    u".pst", // MS Outlook
-    u".pup", // Linux package
-    u".py", // Python script
-    u".pyc", // Python binary
-    u".pyw", // Python GUI
-    //u".quad",
-    //u".r00",
-    //u".r01",
-    //u".r02",
-    //u".r03",
-    //u".r04",
-    //u".r05",
-    //u".r06",
-    //u".r07",
-    //u".r08",
-    //u".r09",
-    //u".r10",
-    //u".r11",
-    //u".r12",
-    //u".r13",
-    //u".r14",
-    //u".r15",
-    //u".r16",
-    //u".r17",
-    //u".r18",
-    //u".r19",
-    //u".r20",
-    //u".r21",
-    //u".r22",
-    //u".r23",
-    //u".r24",
-    //u".r25",
-    //u".r26",
-    //u".r27",
-    //u".r28",
-    //u".r29",
-    //u".rar",
-    u".rb", // Ruby script
-    u".reg", // Windows Registry
-    u".rels", // MS Office
-    //u".rgs", // Windows Registry
-    u".rpm", // Linux package
-    //u".rtf", // MS Office
-    //u".run", // Linux shell
-    u".scf", // Windows shell
-    u".scr", // Windows
-    u".sct", // Windows shell
-    u".search-ms", // Windows
-    u".sh", // Linux shell
-    u".shar", // Linux shell
-    u".shb", // Windows
-    u".shs", // Windows shell
-    //u".sldm", // MS PowerPoint
-    //u".sldx", // MS PowerPoint
-    u".slp", // Linux package
-    u".smi", // Mac disk image
-    u".sparsebundle", // Mac disk image
-    u".sparseimage", // Mac disk image
-    u".spl", // Adobe Flash
-    //u".squashfs",
-    u".svg",
-    u".swf", // Adobe Flash
-    u".swm", // Windows Imaging
-    u".sys", // Windows
-    u".tar", // Linux archive
-    u".taz", // Linux archive (bzip2)
-    u".tbz", // Linux archive (bzip2)
-    u".tbz2", // Linux archive (bzip2)
-    u".tcsh", // Linux shell
-    u".tgz", // Linux archive (gzip)
-    //u".toast", // Roxio disk image
-    //u".torrent", // Bittorrent
-    u".tpz", // Linux archive (gzip)
-    u".txz", // Linux archive (xz)
-    u".tz", // Linux archive (gzip)
-    //u".u3p", // U3 Smart Apps
-    u".udf", // MS Excel
-    u".udif", // Mac disk image
-    u".url", // Windows
-    //u".uu",
-    //u".uue",
-    u".vb", // Visual Basic script
-    u".vbe", // Visual Basic script
-    u".vbs", // Visual Basic script
-    //u".vbscript", // Visual Basic script
-    u".vhd", // Windows virtual hard drive
-    u".vhdx", // Windows virtual hard drive
-    u".vmdk", // VMware virtual disk
-    u".vsd", // MS Visio
-    u".vsmacros", // MS Visual Studio
-    u".vss", // MS Visio
-    u".vst", // MS Visio
-    u".vsw", // MS Visio
-    u".website",  // Windows
-    u".wim", // Windows Imaging
-    //u".workflow", // Mac Automator
-    //u".wrc", // FreeArc archive
-    u".ws", // Windows script
-    u".wsc", // Windows script
-    u".wsf", // Windows script
-    u".wsh", // Windows script
-    u".xar", // MS Excel
-    u".xbap", // XAML Browser Application
-    u".xhtml",
-    u".xhtm",
-    u".xht",
-    u".xip", // Mac archive
-    //u".xlsm", // MS Excel
-    //u".xlsx", // MS Excel
-    //u".xltm", // MS Excel
-    //u".xltx", // MS Excel
-    u".xml",
-    u".xnk", // MS Exchange
-    u".xrm-ms", // Windows
-    u".xsl", // XML Stylesheet
-    //u".xxe",
-    u".xz", // Linux archive (xz)
-    u".z", // InstallShield
+    //".001",
+    //".7z",
+    //".ace",
+    //".action", // Mac script
+    //".ad", // Windows
+    ".ade", // MS Access
+    ".adp", // MS Access
+    ".apk", // Android package
+    ".app", // Executable application
+    ".application", // MS ClickOnce
+    ".appref-ms", // MS ClickOnce
+    //".arc",
+    //".arj",
+    ".as", // Mac archive
+    ".asp", // Windows Server script
+    ".asx", // Windows Media Player
+    //".b64",
+    //".balz",
+    ".bas", // Basic script
+    ".bash", // Linux shell
+    ".bat", // Windows shell
+    //".bhx",
+    //".bin",
+    ".bz", // Linux archive (bzip)
+    ".bz2", // Linux archive (bzip2)
+    ".bzip2", // Linux archive (bzip2)
+    ".cab", // Windows archive
+    ".cdr", // Mac disk image
+    ".cfg", // Windows
+    ".chi", // Windows Help
+    ".chm", // Windows Help
+    ".class", // Java
+    ".cmd", // Windows executable
+    ".com", // Windows executable
+    ".command", // Mac script
+    ".cpgz", // Mac archive
+    //".cpio",
+    ".cpl", // Windows executable
+    ".crt", // Windows signed certificate
+    ".crx", // Chrome extensions
+    ".csh", // Linux shell
+    ".dart", // Mac disk image
+    ".dc42", // Apple DiskCopy Image
+    ".deb", // Linux package
+    ".dex", // Android
+    ".diskcopy42", // Apple DiskCopy Image
+    ".dll", // Windows executable
+    ".dmg", // Mac disk image
+    ".dmgpart", // Mac disk image
+    //".docb", // MS Office
+    //".docm", // MS Word
+    //".docx", // MS Word
+    //".dotm", // MS Word
+    //".dott", // MS Office
+    ".drv", // Windows driver
+    ".dvdr", // Mac Disk image
+    ".efi", // Firmware
+    ".eml", // MS Outlook
+    ".exe", // Windows executable
+    //".fat",
+    ".fon", // Windows font
+    ".fxp", // MS FoxPro
+    ".gadget", // Windows
+    ".grp", // Windows
+    ".gz", // Linux archive (gzip)
+    ".gzip", // Linux archive (gzip)
+    ".hfs", // Mac disk image
+    ".hlp", // Windows Help
+    ".hqx", // Mac archive
+    ".hta", // HTML trusted application
+    ".htm",
+    ".html",
+    ".htt", // MS HTML template
+    ".img", // Mac disk image
+    ".imgpart", // Mac disk image
+    ".inf", // Windows installer
+    ".ini", // Generic config file
+    ".ins", // IIS config
+    //".inx", // InstallShield
+    ".iso", // CD image
+    ".isp", // IIS config
+    //".isu", // InstallShield
+    ".jar", // Java
+    ".jnlp", // Java
+    //".job", // Windows
+    ".js", // JavaScript script
+    ".jse", // JScript
+    ".ksh", // Linux shell
+    //".lha",
+    ".lnk", // Windows
+    ".local", // Windows
+    //".lpaq1",
+    //".lpaq5",
+    //".lpaq8",
+    //".lzh",
+    //".lzma",
+    ".mad", // MS Access
+    ".maf", // MS Access
+    ".mag", // MS Access
+    ".mam", // MS Access
+    ".manifest", // Windows
+    ".maq", // MS Access
+    ".mar", // MS Access
+    ".mas", // MS Access
+    ".mat", // MS Access
+    ".mau", // Media attachment
+    ".mav", // MS Access
+    ".maw", // MS Access
+    ".mda", // MS Access
+    ".mdb", // MS Access
+    ".mde", // MS Access
+    ".mdt", // MS Access
+    ".mdw", // MS Access
+    ".mdz", // MS Access
+    ".mht", // MS HTML
+    ".mhtml", // MS HTML
+    ".mim", // MS Mail
+    ".mmc", // MS Office
+    ".mof", // Windows
+    ".mpkg", // Mac installer
+    ".msc", // Windows executable
+    ".msg", // MS Outlook
+    ".msh", // Windows shell
+    ".msh1", // Windows shell
+    ".msh1xml", // Windows shell
+    ".msh2", // Windows shell
+    ".msh2xml", // Windows shell
+    ".mshxml", // Windows
+    ".msi", // Windows installer
+    ".msp", // Windows installer
+    ".mst", // Windows installer
+    ".ndif", // Mac disk image
+    //".ntfs", // 7z
+    ".ocx", // ActiveX
+    ".ops", // MS Office
+    //".out", // Linux binary
+    //".paf", // PortableApps package
+    //".paq8f",
+    //".paq8jd",
+    //".paq8l",
+    //".paq8o",
+    ".partial", // Downloads
+    ".pax", // Mac archive
+    ".pcd", // Microsoft Visual Test
+    ".pdf", // Adobe Acrobat
+    //".pea",
+    ".pet", // Linux package
+    ".pif", // Windows
+    ".pkg", // Mac installer
+    ".pl", // Perl script
+    ".plg", // MS Visual Studio
+    //".potx", // MS PowerPoint
+    //".ppam", // MS PowerPoint
+    //".ppsx", // MS PowerPoint
+    //".pptm", // MS PowerPoint
+    //".pptx", // MS PowerPoint
+    ".prf", // MS Outlook
+    ".prg", // Windows
+    ".ps1", // Windows shell
+    ".ps1xml", // Windows shell
+    ".ps2", // Windows shell
+    ".ps2xml", // Windows shell
+    ".psc1", // Windows shell
+    ".psc2", // Windows shell
+    ".pst", // MS Outlook
+    ".pup", // Linux package
+    ".py", // Python script
+    ".pyc", // Python binary
+    ".pyw", // Python GUI
+    //".quad",
+    //".r00",
+    //".r01",
+    //".r02",
+    //".r03",
+    //".r04",
+    //".r05",
+    //".r06",
+    //".r07",
+    //".r08",
+    //".r09",
+    //".r10",
+    //".r11",
+    //".r12",
+    //".r13",
+    //".r14",
+    //".r15",
+    //".r16",
+    //".r17",
+    //".r18",
+    //".r19",
+    //".r20",
+    //".r21",
+    //".r22",
+    //".r23",
+    //".r24",
+    //".r25",
+    //".r26",
+    //".r27",
+    //".r28",
+    //".r29",
+    //".rar",
+    ".rb", // Ruby script
+    ".reg", // Windows Registry
+    ".rels", // MS Office
+    //".rgs", // Windows Registry
+    ".rpm", // Linux package
+    //".rtf", // MS Office
+    //".run", // Linux shell
+    ".scf", // Windows shell
+    ".scr", // Windows
+    ".sct", // Windows shell
+    ".search-ms", // Windows
+    ".sh", // Linux shell
+    ".shar", // Linux shell
+    ".shb", // Windows
+    ".shs", // Windows shell
+    //".sldm", // MS PowerPoint
+    //".sldx", // MS PowerPoint
+    ".slp", // Linux package
+    ".smi", // Mac disk image
+    ".sparsebundle", // Mac disk image
+    ".sparseimage", // Mac disk image
+    ".spl", // Adobe Flash
+    //".squashfs",
+    ".svg",
+    ".swf", // Adobe Flash
+    ".swm", // Windows Imaging
+    ".sys", // Windows
+    ".tar", // Linux archive
+    ".taz", // Linux archive (bzip2)
+    ".tbz", // Linux archive (bzip2)
+    ".tbz2", // Linux archive (bzip2)
+    ".tcsh", // Linux shell
+    ".tgz", // Linux archive (gzip)
+    //".toast", // Roxio disk image
+    //".torrent", // Bittorrent
+    ".tpz", // Linux archive (gzip)
+    ".txz", // Linux archive (xz)
+    ".tz", // Linux archive (gzip)
+    //".u3p", // U3 Smart Apps
+    ".udf", // MS Excel
+    ".udif", // Mac disk image
+    ".url", // Windows
+    //".uu",
+    //".uue",
+    ".vb", // Visual Basic script
+    ".vbe", // Visual Basic script
+    ".vbs", // Visual Basic script
+    //".vbscript", // Visual Basic script
+    ".vhd", // Windows virtual hard drive
+    ".vhdx", // Windows virtual hard drive
+    ".vmdk", // VMware virtual disk
+    ".vsd", // MS Visio
+    ".vsmacros", // MS Visual Studio
+    ".vss", // MS Visio
+    ".vst", // MS Visio
+    ".vsw", // MS Visio
+    ".website",  // Windows
+    ".wim", // Windows Imaging
+    //".workflow", // Mac Automator
+    //".wrc", // FreeArc archive
+    ".ws", // Windows script
+    ".wsc", // Windows script
+    ".wsf", // Windows script
+    ".wsh", // Windows script
+    ".xar", // MS Excel
+    ".xbap", // XAML Browser Application
+    ".xhtml",
+    ".xhtm",
+    ".xht",
+    ".xip", // Mac archive
+    //".xlsm", // MS Excel
+    //".xlsx", // MS Excel
+    //".xltm", // MS Excel
+    //".xltx", // MS Excel
+    ".xml",
+    ".xnk", // MS Exchange
+    ".xrm-ms", // Windows
+    ".xsl", // XML Stylesheet
+    //".xxe",
+    ".xz", // Linux archive (xz)
+    ".z", // InstallShield
 #ifdef XP_WIN // disable on Mac/Linux, see 1167493
-    u".zip", // Generic archive
+    ".zip", // Generic archive
 #endif
-    u".zipx", // WinZip
-    //u".zpaq",
+    ".zipx", // WinZip
+    //".zpaq",
 };
 
 bool
 PendingLookup::IsBinaryFile()
 {
-  nsString fileName;
+  nsCString fileName;
   nsresult rv = mQuery->GetSuggestedFileName(fileName);
   if (NS_FAILED(rv)) {
     LOG(("No suggested filename [this = %p]", this));
     return false;
   }
-  LOG(("Suggested filename: %s [this = %p]",
-       NS_ConvertUTF16toUTF8(fileName).get(), this));
+  LOG(("Suggested filename: %s [this = %p]", fileName.get(), this));
 
   for (size_t i = 0; i < ArrayLength(kBinaryFileExtensions); ++i) {
-    if (StringEndsWith(fileName, nsDependentString(kBinaryFileExtensions[i]))) {
+    if (StringEndsWith(fileName,
+                       nsDependentCString(kBinaryFileExtensions[i]))) {
       return true;
     }
   }
 
   return false;
 }
 
 ClientDownloadRequest::DownloadType
-PendingLookup::GetDownloadType(const nsAString& aFilename) {
+PendingLookup::GetDownloadType(const nsACString& aFilename) {
   MOZ_ASSERT(IsBinaryFile());
 
   // From https://cs.chromium.org/chromium/src/chrome/common/safe_browsing/download_protection_util.cc?l=17
-  if (StringEndsWith(aFilename, NS_LITERAL_STRING(".zip"))) {
+  if (StringEndsWith(aFilename, NS_LITERAL_CSTRING(".zip"))) {
     return ClientDownloadRequest::ZIPPED_EXECUTABLE;
-  } else if (StringEndsWith(aFilename, NS_LITERAL_STRING(".apk"))) {
+  } else if (StringEndsWith(aFilename, NS_LITERAL_CSTRING(".apk"))) {
     return ClientDownloadRequest::ANDROID_APK;
-  } else if (StringEndsWith(aFilename, NS_LITERAL_STRING(".app")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".cdr")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".dart")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".dc42")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".diskcopy42")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".dmg")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".dmgpart")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".dvdr")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".img")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".imgpart")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".iso")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".mpkg")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".ndif")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".pkg")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".smi")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".sparsebundle")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".sparseimage")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".toast")) ||
-             StringEndsWith(aFilename, NS_LITERAL_STRING(".udif"))) {
+  } else if (StringEndsWith(aFilename, NS_LITERAL_CSTRING(".app")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".cdr")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".dart")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".dc42")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".diskcopy42")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".dmg")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".dmgpart")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".dvdr")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".img")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".imgpart")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".iso")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".mpkg")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".ndif")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".pkg")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".smi")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".sparsebundle")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".sparseimage")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".toast")) ||
+             StringEndsWith(aFilename, NS_LITERAL_CSTRING(".udif"))) {
     return ClientDownloadRequest::MAC_EXECUTABLE;
   }
 
   return ClientDownloadRequest::WIN_EXECUTABLE; // default to Windows binaries
 }
 
 nsresult
 PendingLookup::LookupNext()
@@ -1313,20 +1313,20 @@ PendingLookup::SendRemoteQueryInternal()
   nsCString locale;
   rv = LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale);
   NS_ENSURE_SUCCESS(rv, rv);
   mRequest.set_locale(locale.get());
   nsCString sha256Hash;
   rv = mQuery->GetSha256Hash(sha256Hash);
   NS_ENSURE_SUCCESS(rv, rv);
   mRequest.mutable_digests()->set_sha256(sha256Hash.Data());
-  nsString fileName;
+  nsCString fileName;
   rv = mQuery->GetSuggestedFileName(fileName);
   NS_ENSURE_SUCCESS(rv, rv);
-  mRequest.set_file_basename(NS_ConvertUTF16toUTF8(fileName).get());
+  mRequest.set_file_basename(fileName.get());
   mRequest.set_download_type(GetDownloadType(fileName));
 
   if (mRequest.signature().trusted()) {
     LOG(("Got signed binary for remote application reputation check "
          "[this = %p]", this));
   } else {
     LOG(("Got unsigned binary for remote application reputation check "
          "[this = %p]", this));
--- a/toolkit/components/downloads/nsIApplicationReputation.idl
+++ b/toolkit/components/downloads/nsIApplicationReputation.idl
@@ -66,17 +66,17 @@ interface nsIApplicationReputationQuery 
   readonly attribute nsIURI referrerURI;
 
   /*
    * The target filename for the downloaded file, as inferred from the source
    * URI or provided by the Content-Disposition attachment file name. If this
    * is not set by the caller, it will be passed as an empty string but the
    * query won't produce any useful information.
    */
-  readonly attribute AString suggestedFileName;
+  readonly attribute AUTF8String suggestedFileName;
 
   /*
    * The size of the downloaded file in bytes.
    */
   readonly attribute unsigned long fileSize;
 
   /*
    * The SHA256 hash of the downloaded file in raw bytes. If this is not set by
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -90,18 +90,19 @@ function promiseBrowserLoaded(browser, u
     // use one. But we also need to make sure it stays alive until we're
     // done with it, so thunk away a strong reference to keep it alive.
     kungFuDeathGrip.add(listener);
     browser.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
   });
 }
 
 class ContentPage {
-  constructor(remote = REMOTE_CONTENT_SCRIPTS) {
+  constructor(remote = REMOTE_CONTENT_SCRIPTS, extension = null) {
     this.remote = remote;
+    this.extension = extension;
 
     this.browserReady = this._initBrowser();
   }
 
   async _initBrowser() {
     this.windowlessBrowser = Services.appShell.createWindowlessBrowser(true);
 
     let system = Services.scriptSecurityManager.getSystemPrincipal();
@@ -118,16 +119,23 @@ class ContentPage {
                           win => win.document == chromeShell.document);
 
     let chromeDoc = await promiseDocumentLoaded(chromeShell.document);
 
     let browser = chromeDoc.createElement("browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
 
+    if (this.extension && this.extension.remote) {
+      this.remote = true;
+      browser.setAttribute("remote", "true");
+      browser.setAttribute("remoteType", "extension");
+      browser.sameProcessAsFrameLoader = this.extension.groupFrameLoader;
+    }
+
     let awaitFrameLoader = Promise.resolve();
     if (this.remote) {
       awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
       browser.setAttribute("remote", "true");
     }
 
     chromeDoc.documentElement.appendChild(browser);
 
@@ -683,16 +691,34 @@ var ExtensionTestUtils = {
   get remoteContentScripts() {
     return REMOTE_CONTENT_SCRIPTS;
   },
 
   set remoteContentScripts(val) {
     REMOTE_CONTENT_SCRIPTS = !!val;
   },
 
-  loadContentPage(url, remote = undefined, redirectUrl = undefined) {
-    let contentPage = new ContentPage(remote);
+  /**
+   * Loads a content page into a hidden docShell.
+   *
+   * @param {string} url
+   *        The URL to load.
+   * @param {object} [options = {}]
+   * @param {ExtensionWrapper} [options.extension]
+   *        If passed, load the URL as an extension page for the given
+   *        extension.
+   * @param {boolean} [options.remote]
+   *        If true, load the URL in a content process. If false, load
+   *        it in the parent process.
+   * @param {string} [options.redirectUrl]
+   *        An optional URL that the initial page is expected to
+   *        redirect to.
+   *
+   * @returns {ContentPage}
+   */
+  loadContentPage(url, {extension = undefined, remote = undefined, redirectUrl = undefined} = {}) {
+    let contentPage = new ContentPage(remote, extension && extension.extension);
 
     return contentPage.loadURL(url, redirectUrl).then(() => {
       return contentPage;
     });
   },
 };
--- a/toolkit/components/extensions/Schemas.jsm
+++ b/toolkit/components/extensions/Schemas.jsm
@@ -2713,26 +2713,35 @@ this.Schemas = {
 
       Services.cpmm.addMessageListener("Schema:Add", this);
     }
 
     this.flushSchemas();
   },
 
   receiveMessage(msg) {
+    let {data} = msg;
     switch (msg.name) {
       case "Schema:Add":
-        for (let [url, schema] of msg.data) {
+        // If we're given a Map, the ordering of the initial items
+        // matters, so swap with our current data to make sure its
+        // entries appear first.
+        if (typeof data.get === "function") {
+          // Create a new Map so we're sure it's in the same compartment.
+          [this.schemaJSON, data] = [new Map(data), this.schemaJSON];
+        }
+
+        for (let [url, schema] of data) {
           this.schemaJSON.set(url, schema);
         }
         this.flushSchemas();
         break;
 
       case "Schema:Delete":
-        this.schemaJSON.delete(msg.data.url);
+        this.schemaJSON.delete(data.url);
         this.flushSchemas();
         break;
     }
   },
 
   _needFlush: true,
   flushSchemas() {
     if (this._needFlush) {
--- a/toolkit/components/extensions/extension-process-script.js
+++ b/toolkit/components/extensions/extension-process-script.js
@@ -375,16 +375,26 @@ ExtensionManager = {
 
       case "Extension:FlushJarCache": {
         ExtensionUtils.flushJarCache(data.path);
         Services.cpmm.sendAsyncMessage("Extension:FlushJarCacheComplete");
         break;
       }
 
       case "Schema:Add": {
+        // If we're given a Map, the ordering of the initial items
+        // matters, so swap with our current data to make sure its
+        // entries appear first.
+        if (typeof data.get === "function") {
+          [this.schemaJSON, data] = [data, this.schemaJSON];
+
+          Services.cpmm.initialProcessData["Extension:Schemas"] =
+            this.schemaJSON;
+        }
+
         for (let [url, schema] of data) {
           this.schemaJSON.set(url, schema);
         }
         break;
       }
     }
   },
 };
--- a/toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
@@ -1,36 +1,52 @@
 "use strict";
 
-XPCOMUtils.defineLazyGetter(this, "ExtensionManager", () => {
-  const {ExtensionManager}
-    = Cu.import("resource://gre/modules/ExtensionChild.jsm", {});
-  return ExtensionManager;
-});
 Cu.import("resource://gre/modules/ExtensionPermissions.jsm");
+Cu.import("resource://gre/modules/MessageChannel.jsm");
 
 const BROWSER_PROPERTIES = "chrome://browser/locale/browser.properties";
 
 AddonTestUtils.init(this);
 AddonTestUtils.overrideCertDB();
 AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
 
-// Find the DOMWindowUtils for the background page for the given
-// extension (wrapper)
-function findWinUtils(extension) {
-  let extensionChild = ExtensionManager.extensions.get(extension.extension.id);
-  let bgwin = null;
-  for (let view of extensionChild.views) {
-    if (view.viewType == "background") {
-      bgwin = view.contentWindow;
-    }
+let extensionHandlers = new WeakSet();
+
+function frameScript() {
+  /* globals content */
+  const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+  Cu.import("resource://gre/m