Merge inbound to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Thu, 17 May 2018 18:28:27 +0300
changeset 418704 24bae072acb09114c367e6b9ffde9261b2ad8a58
parent 418703 a3c1c7193202da24804ee0cb6dfbaf7925d3b28d (current diff)
parent 418684 786865568ed76134a3f9724956949e5d48f34210 (diff)
child 418705 6e8f6ea0688c22366ed6618aecde3d0bfb4f1805
child 418732 77be4f72addfcadf5694d62f7c64248c5d9ceb46
push id103373
push usercsabou@mozilla.com
push dateThu, 17 May 2018 15:36:32 +0000
treeherdermozilla-inbound@6e8f6ea0688c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
24bae072acb0 / 62.0a1 / 20180517220057 / files
nightly linux64
24bae072acb0 / 62.0a1 / 20180517220057 / files
nightly mac
24bae072acb0 / 62.0a1 / 20180517220057 / files
nightly win32
24bae072acb0 / 62.0a1 / 20180517220057 / files
nightly win64
24bae072acb0 / 62.0a1 / 20180517220057 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
browser/base/content/test/general/browser_bug678392-1.html
browser/base/content/test/general/browser_bug678392-2.html
browser/base/content/test/general/browser_bug678392.js
browser/themes/osx/subtle-pattern.png
--- a/browser/app/LauncherProcessWin.cpp
+++ b/browser/app/LauncherProcessWin.cpp
@@ -49,17 +49,17 @@ SetProcessMitigationPolicy(PROCESS_MITIG
 
 /**
  * Any mitigation policies that should be set on the browser process should go
  * here.
  */
 static void
 SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs, const bool aIsSafeMode)
 {
-  if (mozilla::IsWin10November2015UpdateOrLater()) {
+  if (mozilla::IsWin10AnniversaryUpdateOrLater()) {
     aAttrs.AddMitigationPolicy(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON);
   }
 }
 
 static void
 ShowError(DWORD aError = ::GetLastError())
 {
   if (aError == ERROR_SUCCESS) {
@@ -117,17 +117,17 @@ RunAsLauncherProcess(int& argc, wchar_t*
                   static_cast<const wchar_t**>(nullptr),
                   CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
 }
 
 int
 LauncherMain(int argc, wchar_t* argv[])
 {
   // Make sure that the launcher process itself has image load policies set
-  if (IsWin10November2015UpdateOrLater()) {
+  if (IsWin10AnniversaryUpdateOrLater()) {
     const DynamicallyLinkedFunctionPtr<decltype(&SetProcessMitigationPolicy)>
       pSetProcessMitigationPolicy(L"kernel32.dll", "SetProcessMitigationPolicy");
     if (pSetProcessMitigationPolicy) {
       PROCESS_MITIGATION_IMAGE_LOAD_POLICY imgLoadPol = {};
       imgLoadPol.PreferSystem32Images = 1;
 
       DebugOnly<BOOL> setOk = pSetProcessMitigationPolicy(ProcessImageLoadPolicy,
                                                           &imgLoadPol,
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -615,17 +615,17 @@ pref("browser.gesture.pinch.in.shift", "
 #endif
 pref("browser.gesture.twist.latched", false);
 pref("browser.gesture.twist.threshold", 0);
 pref("browser.gesture.twist.right", "cmd_gestureRotateRight");
 pref("browser.gesture.twist.left", "cmd_gestureRotateLeft");
 pref("browser.gesture.twist.end", "cmd_gestureRotateEnd");
 pref("browser.gesture.tap", "cmd_fullZoomReset");
 
-pref("browser.snapshots.limit", 0);
+pref("browser.history_swipe_animation.disabled", false);
 
 // 0: Nothing happens
 // 1: Scrolling contents
 // 2: Go back or go forward, in your history
 // 3: Zoom in or out (reflowing zoom).
 // 4: Treat vertical wheel as horizontal scroll
 // 5: Zoom in or out (pinch zoom).
 #ifdef XP_MACOSX
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -231,17 +231,17 @@ var gGestureSupport = {
    * gesture, if enabled.
    *
    * @param aEvent
    *        The swipe gesture start event.
    * @return true if swipe gestures could successfully be set up, false
    *         othwerwise.
    */
   _setupSwipeGesture: function GS__setupSwipeGesture() {
-    gHistorySwipeAnimation.startAnimation(false);
+    gHistorySwipeAnimation.startAnimation();
 
     this._doUpdate = function GS__doUpdate(aEvent) {
       gHistorySwipeAnimation.updateAnimation(aEvent.delta);
     };
 
     this._doEnd = function GS__doEnd(aEvent) {
       gHistorySwipeAnimation.swipeEndEventReceived();
 
@@ -400,22 +400,18 @@ var gGestureSupport = {
    *
    * @param aEvent
    *        The swipe event to handle
    * @param aDir
    *        The direction for the swipe event
    */
   _coordinateSwipeEventWithAnimation:
   function GS__coordinateSwipeEventWithAnimation(aEvent, aDir) {
-    if ((gHistorySwipeAnimation.isAnimationRunning()) &&
-        (aDir == "RIGHT" || aDir == "LEFT")) {
-      gHistorySwipeAnimation.processSwipeEvent(aEvent, aDir);
-    } else {
-      this.processSwipeEvent(aEvent, aDir);
-    }
+    gHistorySwipeAnimation.stopAnimation();
+    this.processSwipeEvent(aEvent, aDir);
   },
 
   /**
    * Get a gesture preference or use a default if it doesn't exist
    *
    * @param aPref
    *        Name of the preference to load under the gesture branch
    * @param aDef
@@ -579,358 +575,191 @@ var gHistorySwipeAnimation = {
   active: false,
   isLTR: false,
 
   /**
    * Initializes the support for history swipe animations, if it is supported
    * by the platform/configuration.
    */
   init: function HSA_init() {
-    if (!this._isSupported())
+    if (!this._isSupported()) {
       return;
+    }
 
-    this.active = false;
     this.isLTR = document.documentElement.matches(":-moz-locale-dir(ltr)");
-    this._trackedSnapshots = [];
-    this._startingIndex = -1;
-    this._historyIndex = -1;
-    this._boxWidth = -1;
-    this._boxHeight = -1;
-    this._maxSnapshots = this._getMaxSnapshots();
-    this._lastSwipeDir = "";
-    this._direction = "horizontal";
-
-    // We only want to activate history swipe animations if we store snapshots.
-    // If we don't store any, we handle horizontal swipes without animations.
-    if (this._maxSnapshots > 0) {
+    this._isStoppingAnimation = false;
+    if (!Services.prefs.getBoolPref("browser.history_swipe_animation.disabled",
+                                    false)) {
       this.active = true;
-      gBrowser.addEventListener("pagehide", this);
-      gBrowser.addEventListener("pageshow", this);
-      gBrowser.addEventListener("popstate", this);
-      gBrowser.addEventListener("DOMModalDialogClosed", this);
-      gBrowser.tabContainer.addEventListener("TabClose", this);
     }
   },
 
   /**
    * Uninitializes the support for history swipe animations.
    */
   uninit: function HSA_uninit() {
-    gBrowser.removeEventListener("pagehide", this);
-    gBrowser.removeEventListener("pageshow", this);
-    gBrowser.removeEventListener("popstate", this);
-    gBrowser.removeEventListener("DOMModalDialogClosed", this);
-    gBrowser.tabContainer.removeEventListener("TabClose", this);
-
     this.active = false;
     this.isLTR = false;
+    this._removeBoxes();
   },
 
   /**
-   * Starts the swipe animation and handles fast swiping (i.e. a swipe animation
-   * is already in progress when a new one is initiated).
+   * Starts the swipe animation.
    *
    * @param aIsVerticalSwipe
    *        Whether we're dealing with a vertical swipe or not.
    */
-  startAnimation: function HSA_startAnimation(aIsVerticalSwipe) {
-    this._direction = aIsVerticalSwipe ? "vertical" : "horizontal";
-
+  startAnimation: function HSA_startAnimation() {
     if (this.isAnimationRunning()) {
-      // If this is a horizontal scroll, or if this is a vertical scroll that
-      // was started while a horizontal scroll was still running, handle it as
-      // as a fast swipe. In the case of the latter scenario, this allows us to
-      // start the vertical animation without first loading the final page, or
-      // taking another snapshot. If vertical scrolls are initiated repeatedly
-      // without prior horizontal scroll we skip this and restart the animation
-      // from 0.
-      if (this._direction == "horizontal" || this._lastSwipeDir != "") {
-        gBrowser.stop();
-        this._lastSwipeDir = "RELOAD"; // just ensure that != ""
-        this._canGoBack = this.canGoBack();
-        this._canGoForward = this.canGoForward();
-        this._handleFastSwiping();
-      }
-      this.updateAnimation(0);
-    } else {
-      // Get the session history from SessionStore.
-      let updateSessionHistory = sessionHistory => {
-        this._startingIndex = sessionHistory.index;
-        this._historyIndex = this._startingIndex;
-        this._canGoBack = this.canGoBack();
-        this._canGoForward = this.canGoForward();
-        if (this.active) {
-          this._addBoxes();
-          this._takeSnapshot();
-          this._installPrevAndNextSnapshots();
-          this._lastSwipeDir = "";
-        }
-        this.updateAnimation(0);
-      };
-      SessionStore.getSessionHistory(gBrowser.selectedTab, updateSessionHistory);
+      return;
     }
+
+    this._isStoppingAnimation = false;
+    this._canGoBack = this.canGoBack();
+    this._canGoForward = this.canGoForward();
+    if (this.active) {
+      this._addBoxes();
+    }
+    this.updateAnimation(0);
   },
 
   /**
    * Stops the swipe animation.
    */
   stopAnimation: function HSA_stopAnimation() {
-    gHistorySwipeAnimation._removeBoxes();
-    this._historyIndex = this._getCurrentHistoryIndex();
+    if (!this.isAnimationRunning()) {
+      return;
+    }
+    this._isStoppingAnimation = true;
+    let box = this._prevBox.style.opacity > 0 ? this._prevBox : this._nextBox;
+    if (box.style.opacity > 0) {
+      box.style.transition = "opacity 0.2s cubic-bezier(.07,.95,0,1)";
+      box.addEventListener("transitionend", this._completeFadeOut);
+      box.style.opacity = 0;
+    } else {
+      this._removeBoxes();
+    }
   },
 
   /**
    * Updates the animation between two pages in history.
    *
    * @param aVal
    *        A floating point value that represents the progress of the
    *        swipe gesture.
    */
   updateAnimation: function HSA_updateAnimation(aVal) {
-    if (!this.isAnimationRunning()) {
+    if (!this.isAnimationRunning() || this._isStoppingAnimation) {
       return;
     }
 
-    // We use the following value to decrease the bounce effect when scrolling
-    // to the top or bottom of the page, or when swiping back/forward past the
-    // browsing history. This value was determined experimentally.
-    let dampValue = 4;
-    if (this._direction == "vertical") {
-      this._prevBox.collapsed = true;
-      this._nextBox.collapsed = true;
-      this._positionBox(this._curBox, -1 * aVal / dampValue);
-    } else if ((aVal >= 0 && this.isLTR) ||
-               (aVal <= 0 && !this.isLTR)) {
-      let tempDampValue = 1;
+    // We use the following value to set the opacity of the swipe arrows. It was
+    // determined experimentally that absolute values of 0.25 (or greater)
+    // trigger history navigation, hence the multiplier 4 to set the arrows to
+    // full opacity at 0.25 or greater.
+    let opacity = Math.abs(aVal) * 4;
+    if ((aVal >= 0 && this.isLTR) ||
+        (aVal <= 0 && !this.isLTR)) {
+      // The intention is to go back.
       if (this._canGoBack) {
         this._prevBox.collapsed = false;
-      } else {
-        tempDampValue = dampValue;
-        this._prevBox.collapsed = true;
+        this._nextBox.collapsed = true;
+        this._prevBox.style.opacity = opacity > 1 ? 1 : opacity;
       }
-
-      // The current page is pushed to the right (LTR) or left (RTL),
-      // the intention is to go back.
-      // If there is a page to go back to, it should show in the background.
-      this._positionBox(this._curBox, aVal / tempDampValue);
-
-      // The forward page should be pushed offscreen all the way to the right.
-      this._positionBox(this._nextBox, 1);
     } else if (this._canGoForward) {
-      // The intention is to go forward. If there is a page to go forward to,
-      // it should slide in from the right (LTR) or left (RTL).
-      // Otherwise, the current page should slide to the left (LTR) or
-      // right (RTL) and the backdrop should appear in the background.
-      // For the backdrop to be visible in that case, the previous page needs
-      // to be hidden (if it exists).
+      // The intention is to go forward.
       this._nextBox.collapsed = false;
-      let offset = this.isLTR ? 1 : -1;
-      this._positionBox(this._curBox, 0);
-      this._positionBox(this._nextBox, offset + aVal);
-    } else {
       this._prevBox.collapsed = true;
-      this._positionBox(this._curBox, aVal / dampValue);
-    }
-  },
-
-  _getCurrentHistoryIndex() {
-    return SessionStore.getSessionHistory(gBrowser.selectedTab).index;
-  },
-
-  /**
-   * Event handler for events relevant to the history swipe animation.
-   *
-   * @param aEvent
-   *        An event to process.
-   */
-  handleEvent: function HSA_handleEvent(aEvent) {
-    let browser = gBrowser.selectedBrowser;
-    switch (aEvent.type) {
-      case "TabClose":
-        let browserForTab = gBrowser.getBrowserForTab(aEvent.target);
-        this._removeTrackedSnapshot(-1, browserForTab);
-        break;
-      case "DOMModalDialogClosed":
-        this.stopAnimation();
-        break;
-      case "pageshow":
-        if (aEvent.target == browser.contentDocument) {
-          this.stopAnimation();
-        }
-        break;
-      case "popstate":
-        if (aEvent.target == browser.contentDocument.defaultView) {
-          this.stopAnimation();
-        }
-        break;
-      case "pagehide":
-        if (aEvent.target == browser.contentDocument) {
-          // Take and compress a snapshot of a page whenever it's about to be
-          // navigated away from. We already have a snapshot of the page if an
-          // animation is running, so we're left with compressing it.
-          if (!this.isAnimationRunning()) {
-            this._takeSnapshot();
-          }
-          this._compressSnapshotAtCurrentIndex();
-        }
-        break;
+      this._nextBox.style.opacity = opacity > 1 ? 1 : opacity;
     }
   },
 
   /**
    * Checks whether the history swipe animation is currently running or not.
    *
    * @return true if the animation is currently running, false otherwise.
    */
   isAnimationRunning: function HSA_isAnimationRunning() {
     return !!this._container;
   },
 
   /**
-   * Process a swipe event based on the given direction.
-   *
-   * @param aEvent
-   *        The swipe event to handle
-   * @param aDir
-   *        The direction for the swipe event
-   */
-  processSwipeEvent: function HSA_processSwipeEvent(aEvent, aDir) {
-    if (aDir == "RIGHT")
-      this._historyIndex += this.isLTR ? 1 : -1;
-    else if (aDir == "LEFT")
-      this._historyIndex += this.isLTR ? -1 : 1;
-    else
-      return;
-    this._lastSwipeDir = aDir;
-  },
-
-  /**
    * Checks if there is a page in the browser history to go back to.
    *
    * @return true if there is a previous page in history, false otherwise.
    */
   canGoBack: function HSA_canGoBack() {
-    if (this.isAnimationRunning())
-      return this._doesIndexExistInHistory(this._historyIndex - 1);
     return gBrowser.webNavigation.canGoBack;
   },
 
   /**
    * Checks if there is a page in the browser history to go forward to.
    *
    * @return true if there is a next page in history, false otherwise.
    */
   canGoForward: function HSA_canGoForward() {
-    if (this.isAnimationRunning())
-      return this._doesIndexExistInHistory(this._historyIndex + 1);
     return gBrowser.webNavigation.canGoForward;
   },
 
   /**
    * Used to notify the history swipe animation that the OS sent a swipe end
    * event and that we should navigate to the page that the user swiped to, if
    * any. This will also result in the animation overlay to be torn down.
    */
   swipeEndEventReceived: function HSA_swipeEndEventReceived() {
-    // Update the session history before continuing.
-    let updateSessionHistory = sessionHistory => {
-      if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex)
-        this._navigateToHistoryIndex();
-      else
-        this.stopAnimation();
-    };
-    SessionStore.getSessionHistory(gBrowser.selectedTab, updateSessionHistory);
-  },
-
-  /**
-   * Checks whether a particular index exists in the browser history or not.
-   *
-   * @param aIndex
-   *        The index to check for availability for in the history.
-   * @return true if the index exists in the browser history, false otherwise.
-   */
-  _doesIndexExistInHistory: function HSA__doesIndexExistInHistory(aIndex) {
-    try {
-      return SessionStore.getSessionHistory(gBrowser.selectedTab).entries[aIndex] != null;
-    } catch (ex) {
-      return false;
-    }
-  },
-
-  /**
-   * Navigates to the index in history that is currently being tracked by
-   * |this|.
-   */
-  _navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
-    if (this._doesIndexExistInHistory(this._historyIndex))
-      gBrowser.webNavigation.gotoIndex(this._historyIndex);
-    else
-      this.stopAnimation();
+    this.stopAnimation();
   },
 
   /**
    * Checks to see if history swipe animations are supported by this
    * platform/configuration.
    *
    * return true if supported, false otherwise.
    */
   _isSupported: function HSA__isSupported() {
     return window.matchMedia("(-moz-swipe-animation-enabled)").matches;
   },
 
-  /**
-   * Handle fast swiping (i.e. a swipe animation is already in
-   * progress when a new one is initiated). This will swap out the snapshots
-   * used in the previous animation with the appropriate new ones.
-   */
-  _handleFastSwiping: function HSA__handleFastSwiping() {
-    this._installCurrentPageSnapshot(null);
-    this._installPrevAndNextSnapshots();
+  _completeFadeOut: function HSA__completeFadeOut(aEvent) {
+    gHistorySwipeAnimation._removeBoxes();
   },
 
   /**
-   * Adds the boxes that contain the snapshots used during the swipe animation.
+   * Adds the boxes that contain the arrows used during the swipe animation.
    */
   _addBoxes: function HSA__addBoxes() {
     let browserStack =
       document.getAnonymousElementByAttribute(gBrowser.getNotificationBox(),
                                               "class", "browserStack");
     this._container = this._createElement("historySwipeAnimationContainer",
                                           "stack");
     browserStack.appendChild(this._container);
 
-    this._prevBox = this._createElement("historySwipeAnimationPreviousPage",
+    this._prevBox = this._createElement("historySwipeAnimationPreviousArrow",
                                         "box");
+    this._prevBox.collapsed = true;
+    this._prevBox.style.opacity = 0;
     this._container.appendChild(this._prevBox);
 
-    this._curBox = this._createElement("historySwipeAnimationCurrentPage",
-                                       "box");
-    this._container.appendChild(this._curBox);
-
-    this._nextBox = this._createElement("historySwipeAnimationNextPage",
+    this._nextBox = this._createElement("historySwipeAnimationNextArrow",
                                         "box");
+    this._nextBox.collapsed = true;
+    this._nextBox.style.opacity = 0;
     this._container.appendChild(this._nextBox);
-
-    // Cache width and height.
-    this._boxWidth = this._curBox.getBoundingClientRect().width;
-    this._boxHeight = this._curBox.getBoundingClientRect().height;
   },
 
   /**
    * Removes the boxes.
    */
   _removeBoxes: function HSA__removeBoxes() {
-    this._curBox = null;
     this._prevBox = null;
     this._nextBox = null;
     if (this._container)
       this._container.remove();
     this._container = null;
-    this._boxWidth = -1;
-    this._boxHeight = -1;
   },
 
   /**
    * Creates an element with a given identifier and tag name.
    *
    * @param aID
    *        An identifier to create the element with.
    * @param aTagName
@@ -938,305 +767,9 @@ var gHistorySwipeAnimation = {
    * @return the newly created element.
    */
   _createElement: function HSA__createElement(aID, aTagName) {
     let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     let element = document.createElementNS(XULNS, aTagName);
     element.id = aID;
     return element;
   },
-
-  /**
-   * Moves a given box to a given X coordinate position.
-   *
-   * @param aBox
-   *        The box element to position.
-   * @param aPosition
-   *        The position (in X coordinates) to move the box element to.
-   */
-  _positionBox: function HSA__positionBox(aBox, aPosition) {
-    let transform = "";
-
-    if (this._direction == "vertical")
-      transform = "translateY(" + this._boxHeight * aPosition + "px)";
-    else
-      transform = "translateX(" + this._boxWidth * aPosition + "px)";
-
-    aBox.style.transform = transform;
-  },
-
-  /**
-   * Verifies that we're ready to take snapshots based on the global pref and
-   * the current index in history.
-   *
-   * @return true if we're ready to take snapshots, false otherwise.
-   */
-  _readyToTakeSnapshots: function HSA__readyToTakeSnapshots() {
-    return (this._maxSnapshots >= 1 && this._getCurrentHistoryIndex() >= 0);
-  },
-
-  /**
-   * Takes a snapshot of the page the browser is currently on.
-   */
-  _takeSnapshot: function HSA__takeSnapshot() {
-    if (!this._readyToTakeSnapshots()) {
-      return;
-    }
-
-    let canvas = null;
-
-    let browser = gBrowser.selectedBrowser;
-    let r = browser.getBoundingClientRect();
-    canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
-                                      "canvas");
-    canvas.mozOpaque = true;
-    let scale = window.devicePixelRatio;
-    canvas.width = r.width * scale;
-    canvas.height = r.height * scale;
-    let ctx = canvas.getContext("2d");
-    let zoom = browser.markupDocumentViewer.fullZoom * scale;
-    ctx.scale(zoom, zoom);
-    ctx.drawWindow(browser.contentWindow,
-                   0, 0, canvas.width / zoom, canvas.height / zoom, "white",
-                   ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
-                   ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
-                   ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
-
-    TelemetryStopwatch.start("FX_GESTURE_INSTALL_SNAPSHOT_OF_PAGE");
-    try {
-      this._installCurrentPageSnapshot(canvas);
-      this._assignSnapshotToCurrentBrowser(canvas);
-    } finally {
-      TelemetryStopwatch.finish("FX_GESTURE_INSTALL_SNAPSHOT_OF_PAGE");
-    }
-  },
-
-  /**
-   * Retrieves the maximum number of snapshots that should be kept in memory.
-   * This limit is a global limit and is valid across all open tabs.
-   */
-  _getMaxSnapshots: function HSA__getMaxSnapshots() {
-    return Services.prefs.getIntPref("browser.snapshots.limit");
-  },
-
-  /**
-   * Adds a snapshot to the list and initiates the compression of said snapshot.
-   * Once the compression is completed, it will replace the uncompressed
-   * snapshot in the list.
-   *
-   * @param aCanvas
-   *        The snapshot to add to the list and compress.
-   */
-  _assignSnapshotToCurrentBrowser:
-  function HSA__assignSnapshotToCurrentBrowser(aCanvas) {
-    let browser = gBrowser.selectedBrowser;
-    let currIndex = this._getCurrentHistoryIndex();
-
-    this._removeTrackedSnapshot(currIndex, browser);
-    this._addSnapshotRefToArray(currIndex, browser);
-
-    if (!("snapshots" in browser))
-      browser.snapshots = [];
-    let snapshots = browser.snapshots;
-    // Temporarily store the canvas as the compressed snapshot.
-    // This avoids a blank page if the user swipes quickly
-    // between pages before the compression could complete.
-    snapshots[currIndex] = {
-      image: aCanvas,
-      scale: window.devicePixelRatio
-    };
-  },
-
-  /**
-   * Compresses the HTMLCanvasElement that's stored at the current history
-   * index in the snapshot array and stores the compressed image in its place.
-   */
-  _compressSnapshotAtCurrentIndex:
-  function HSA__compressSnapshotAtCurrentIndex() {
-    if (!this._readyToTakeSnapshots()) {
-      // We didn't take a snapshot earlier because we weren't ready to, so
-      // there's nothing to compress.
-      return;
-    }
-
-    TelemetryStopwatch.start("FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE");
-    try {
-      let browser = gBrowser.selectedBrowser;
-      let snapshots = browser.snapshots;
-      let currIndex = this._getCurrentHistoryIndex();
-
-      // Kick off snapshot compression.
-      let canvas = snapshots[currIndex].image;
-      canvas.toBlob(function(aBlob) {
-          if (snapshots[currIndex]) {
-            snapshots[currIndex].image = aBlob;
-          }
-        }, "image/png"
-      );
-    } finally {
-      TelemetryStopwatch.finish("FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE");
-    }
-  },
-
-  /**
-   * Removes a snapshot identified by the browser and index in the array of
-   * snapshots for that browser, if present. If no snapshot could be identified
-   * the method simply returns without taking any action. If aIndex is negative,
-   * all snapshots for a particular browser will be removed.
-   *
-   * @param aIndex
-   *        The index in history of the new snapshot, or negative value if all
-   *        snapshots for a browser should be removed.
-   * @param aBrowser
-   *        The browser the new snapshot was taken in.
-   */
-  _removeTrackedSnapshot: function HSA__removeTrackedSnapshot(aIndex, aBrowser) {
-    let arr = this._trackedSnapshots;
-    let requiresExactIndexMatch = aIndex >= 0;
-    for (let i = 0; i < arr.length; i++) {
-      if ((arr[i].browser == aBrowser) &&
-          (aIndex < 0 || aIndex == arr[i].index)) {
-        delete aBrowser.snapshots[arr[i].index];
-        arr.splice(i, 1);
-        if (requiresExactIndexMatch)
-          return; // Found and removed the only element.
-        i--; // Make sure to revisit the index that we just removed an
-             // element at.
-      }
-    }
-  },
-
-  /**
-   * Adds a new snapshot reference for a given index and browser to the array
-   * of references to tracked snapshots.
-   *
-   * @param aIndex
-   *        The index in history of the new snapshot.
-   * @param aBrowser
-   *        The browser the new snapshot was taken in.
-   */
-  _addSnapshotRefToArray:
-  function HSA__addSnapshotRefToArray(aIndex, aBrowser) {
-    let id = { index: aIndex,
-               browser: aBrowser };
-    let arr = this._trackedSnapshots;
-    arr.unshift(id);
-
-    while (arr.length > this._maxSnapshots) {
-      let lastElem = arr[arr.length - 1];
-      delete lastElem.browser.snapshots[lastElem.index].image;
-      delete lastElem.browser.snapshots[lastElem.index];
-      arr.splice(-1, 1);
-    }
-  },
-
-  /**
-   * Converts a compressed blob to an Image object. In some situations
-   * (especially during fast swiping) aBlob may still be a canvas, not a
-   * compressed blob. In this case, we simply return the canvas.
-   *
-   * @param aBlob
-   *        The compressed blob to convert, or a canvas if a blob compression
-   *        couldn't complete before this method was called.
-   * @return A new Image object representing the converted blob.
-   */
-  _convertToImg: function HSA__convertToImg(aBlob) {
-    if (!aBlob)
-      return null;
-
-    // Return aBlob if it's still a canvas and not a compressed blob yet.
-    if (aBlob instanceof HTMLCanvasElement)
-      return aBlob;
-
-    let img = new Image();
-    let url = "";
-    try {
-      url = URL.createObjectURL(aBlob);
-      img.onload = function() {
-        URL.revokeObjectURL(url);
-      };
-    } finally {
-      img.src = url;
-    }
-    return img;
-  },
-
-  /**
-   * Scales the background of a given box element (which uses a given snapshot
-   * as background) based on a given scale factor.
-   * @param aSnapshot
-   *        The snapshot that is used as background of aBox.
-   * @param aScale
-   *        The scale factor to use.
-   * @param aBox
-   *        The box element that uses aSnapshot as background.
-   */
-  _scaleSnapshot: function HSA__scaleSnapshot(aSnapshot, aScale, aBox) {
-    if (aSnapshot && aScale != 1 && aBox) {
-      if (aSnapshot instanceof HTMLCanvasElement) {
-        aBox.style.backgroundSize =
-          aSnapshot.width / aScale + "px " + aSnapshot.height / aScale + "px";
-      } else {
-        // snapshot is instanceof HTMLImageElement
-        aSnapshot.addEventListener("load", function() {
-          aBox.style.backgroundSize =
-            aSnapshot.width / aScale + "px " + aSnapshot.height / aScale + "px";
-        });
-      }
-    }
-  },
-
-  /**
-   * Sets the snapshot of the current page to the snapshot passed as parameter,
-   * or to the one previously stored for the current index in history if the
-   * parameter is null.
-   *
-   * @param aCanvas
-   *        The snapshot to set the current page to. If this parameter is null,
-   *        the previously stored snapshot for this index (if any) will be used.
-   */
-  _installCurrentPageSnapshot:
-  function HSA__installCurrentPageSnapshot(aCanvas) {
-    let currSnapshot = aCanvas;
-    let scale = window.devicePixelRatio;
-    if (!currSnapshot) {
-      let snapshots = gBrowser.selectedBrowser.snapshots || {};
-      let currIndex = this._historyIndex;
-      if (currIndex in snapshots) {
-        currSnapshot = this._convertToImg(snapshots[currIndex].image);
-        scale = snapshots[currIndex].scale;
-      }
-    }
-    this._scaleSnapshot(currSnapshot, scale, this._curBox ? this._curBox :
-                                                            null);
-    document.mozSetImageElement("historySwipeAnimationCurrentPageSnapshot",
-                                currSnapshot);
-  },
-
-  /**
-   * Sets the snapshots of the previous and next pages to the snapshots
-   * previously stored for their respective indeces.
-   */
-  _installPrevAndNextSnapshots:
-  function HSA__installPrevAndNextSnapshots() {
-    let snapshots = gBrowser.selectedBrowser.snapshots || [];
-    let currIndex = this._historyIndex;
-    let prevIndex = currIndex - 1;
-    let prevSnapshot = null;
-    if (prevIndex in snapshots) {
-      prevSnapshot = this._convertToImg(snapshots[prevIndex].image);
-      this._scaleSnapshot(prevSnapshot, snapshots[prevIndex].scale,
-                          this._prevBox);
-    }
-    document.mozSetImageElement("historySwipeAnimationPreviousPageSnapshot",
-                                prevSnapshot);
-
-    let nextIndex = currIndex + 1;
-    let nextSnapshot = null;
-    if (nextIndex in snapshots) {
-      nextSnapshot = this._convertToImg(snapshots[nextIndex].image);
-      this._scaleSnapshot(nextSnapshot, snapshots[nextIndex].scale,
-                          this._nextBox);
-    }
-    document.mozSetImageElement("historySwipeAnimationNextPageSnapshot",
-                                nextSnapshot);
-  },
 };
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -882,34 +882,27 @@ window[chromehidden~="toolbar"] toolbar:
 #mainPopupSet {
   min-width: 1px;
 }
 
 /* History Swipe Animation */
 
 #historySwipeAnimationContainer {
   overflow: hidden;
-}
-
-#historySwipeAnimationPreviousPage,
-#historySwipeAnimationCurrentPage,
-#historySwipeAnimationNextPage {
-  background: none top left no-repeat white;
+  pointer-events: none;
 }
 
-#historySwipeAnimationPreviousPage {
-  background-image: -moz-element(#historySwipeAnimationPreviousPageSnapshot);
+#historySwipeAnimationPreviousArrow {
+  background: url("chrome://browser/content/history-swipe-arrow.svg")
+              center left / 64px 128px no-repeat transparent;
 }
-
-#historySwipeAnimationCurrentPage {
-  background-image: -moz-element(#historySwipeAnimationCurrentPageSnapshot);
-}
-
-#historySwipeAnimationNextPage {
-  background-image: -moz-element(#historySwipeAnimationNextPageSnapshot);
+#historySwipeAnimationNextArrow {
+  background: url("chrome://browser/content/history-swipe-arrow.svg")
+              center left / 64px 128px no-repeat transparent;
+  transform: rotate(180deg);
 }
 
 /*  Full Screen UI */
 
 #fullscr-toggler {
   height: 1px;
   background: black;
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/history-swipe-arrow.svg
@@ -0,0 +1,4 @@
+<svg width="256" height="512" xmlns="http://www.w3.org/2000/svg">
+  <ellipse ry="256" rx="256" cy="256" cx="0" stroke-width="0" stroke="#000" fill="#38383d"/>
+  <path d="m181.335236,247.749695l-96.549957,0l35.774963,-35.774994a8.33333,8.33333 0 0 0 -11.783325,-11.783325l-49.999969,49.999954a8.33333,8.33333 0 0 0 0,11.782944l49.999969,50a8.33333,8.33333 0 0 0 11.783325,-11.783325l-35.774963,-35.774994l96.549957,0a8.33333,8.33333 0 0 0 0,-16.66626z" fill="rgba(249, 249, 250, .8)"/>
+</svg>
\ No newline at end of file
--- a/browser/base/content/moz.build
+++ b/browser/base/content/moz.build
@@ -29,16 +29,19 @@ with Files("test/chrome/**"):
     BUG_COMPONENT = ("Firefox", "General")
 
 with Files("test/contextMenu/**"):
     BUG_COMPONENT = ("Firefox", "Menus")
 
 with Files("test/forms/**"):
     BUG_COMPONENT = ("Core", "Layout: Form Controls")
 
+with Files("test/historySwipeAnimation/**"):
+    BUG_COMPONENT = ("Core", "Widget: Cocoa")
+
 with Files("test/pageinfo/**"):
     BUG_COMPONENT = ("Firefox", "Page Info Window")
 
 with Files("test/performance/**"):
     BUG_COMPONENT = ("Firefox", "General")
 
 with Files("test/performance/browser_appmenu.js"):
     BUG_COMPONENT = ("Firefox", "Menus")
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -9,18 +9,16 @@
 prefs = browser.cache.offline.insecure.enable=true
 support-files =
   POSTSearchEngine.xml
   alltabslistener.html
   app_bug575561.html
   app_subframe_bug575561.html
   audio.ogg
   browser_bug479408_sample.html
-  browser_bug678392-1.html
-  browser_bug678392-2.html
   browser_bug970746.xhtml
   browser_registerProtocolHandler_notification.html
   browser_star_hsts.sjs
   browser_tab_dragdrop2_frame1.xul
   browser_tab_dragdrop_embed.html
   browser_web_channel.html
   browser_web_channel_iframe.html
   bug592338.html
@@ -227,19 +225,16 @@ skip-if = toolkit != "cocoa" # Because o
 [browser_bug647886.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug655584.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug664672.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug676619.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_bug678392.js]
-skip-if = os == "mac" # Bug 1102331 - does focus things on the content window which break in e10s mode (still causes orange on Mac 10.10)
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug710878.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug719271.js]
 skip-if = os == "win" && debug && e10s # Bug 1315042
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug724239.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug734076.js]
deleted file mode 100644
--- a/browser/base/content/test/general/browser_bug678392-1.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-  <head>
-    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
-    <meta content="utf-8" http-equiv="encoding">
-    <title>bug678392 - 1</title>
-  </head>
-  <body>
-bug 678392 test page 1
-  </body>
-</html>
deleted file mode 100644
--- a/browser/base/content/test/general/browser_bug678392-2.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-  <head>
-    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
-    <meta content="utf-8" http-equiv="encoding">
-    <title>bug678392 - 2</title>
-  </head>
-  <body>
-bug 678392 test page 2
-  </body>
-</html>
deleted file mode 100644
--- a/browser/base/content/test/general/browser_bug678392.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var HTTPROOT = "http://example.com/browser/browser/base/content/test/general/";
-
-function maxSnapshotOverride() {
-  return 5;
-}
-
-function test() {
-  waitForExplicitFinish();
-
-  BrowserOpenTab();
-  let tab = gBrowser.selectedTab;
-  registerCleanupFunction(function() { gBrowser.removeTab(tab); });
-
-  ok(gHistorySwipeAnimation, "gHistorySwipeAnimation exists.");
-
-  if (!gHistorySwipeAnimation._isSupported()) {
-    is(gHistorySwipeAnimation.active, false, "History swipe animation is not " +
-       "active when not supported by the platform.");
-    finish();
-    return;
-  }
-
-  gHistorySwipeAnimation._getMaxSnapshots = maxSnapshotOverride;
-  gHistorySwipeAnimation.init();
-
-  is(gHistorySwipeAnimation.active, true, "History swipe animation support " +
-     "was successfully initialized when supported.");
-
-  cleanupArray();
-  load(gBrowser.selectedTab, HTTPROOT + "browser_bug678392-2.html", test0);
-}
-
-function load(aTab, aUrl, aCallback) {
-  aTab.linkedBrowser.addEventListener("load", function(aEvent) {
-    waitForFocus(aCallback, content);
-  }, {capture: true, once: true});
-  aTab.linkedBrowser.loadURI(aUrl);
-}
-
-function cleanupArray() {
-  let arr = gHistorySwipeAnimation._trackedSnapshots;
-  while (arr.length > 0) {
-    delete arr[0].browser.snapshots[arr[0].index]; // delete actual snapshot
-    arr.splice(0, 1);
-  }
-}
-
-function testArrayCleanup() {
-  // Test cleanup of array of tracked snapshots.
-  let arr = gHistorySwipeAnimation._trackedSnapshots;
-  is(arr.length, 0, "Snapshots were removed correctly from the array of " +
-                    "tracked snapshots.");
-}
-
-function test0() {
-  // Test growing of array of tracked snapshots.
-  let tab = gBrowser.selectedTab;
-
-  load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-    ok(gHistorySwipeAnimation._trackedSnapshots, "Array for snapshot " +
-      "tracking is initialized.");
-    is(gHistorySwipeAnimation._trackedSnapshots.length, 1, "Snapshot array " +
-       "has correct length of 1 after loading one page.");
-    load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
-      is(gHistorySwipeAnimation._trackedSnapshots.length, 2, "Snapshot array " +
-         " has correct length of 2 after loading two pages.");
-      load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-        is(gHistorySwipeAnimation._trackedSnapshots.length, 3, "Snapshot " +
-           "array has correct length of 3 after loading three pages.");
-        load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
-          is(gHistorySwipeAnimation._trackedSnapshots.length, 4, "Snapshot " +
-             "array has correct length of 4 after loading four pages.");
-          cleanupArray();
-          testArrayCleanup();
-          test1();
-        });
-      });
-    });
-  });
-}
-
-function verifyRefRemoved(aIndex, aBrowser) {
-  let wasFound = false;
-  let arr = gHistorySwipeAnimation._trackedSnapshots;
-  for (let i = 0; i < arr.length; i++) {
-    if (arr[i].index == aIndex && arr[i].browser == aBrowser)
-      wasFound = true;
-  }
-  is(wasFound, false, "The reference that was previously removed was " +
-     "still found in the array of tracked snapshots.");
-}
-
-function test1() {
-  // Test presence of snpashots in per-tab array of snapshots and removal of
-  // individual snapshots (and corresponding references in the array of
-  // tracked snapshots).
-  let tab = gBrowser.selectedTab;
-
-  load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-    var historyIndex = gBrowser.webNavigation.sessionHistory.index - 1;
-    load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
-      load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-        load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
-          let browser = gBrowser.selectedBrowser;
-          ok(browser.snapshots, "Array of snapshots exists in browser.");
-          ok(browser.snapshots[historyIndex], "First page exists in snapshot " +
-                                              "array.");
-          ok(browser.snapshots[historyIndex + 1], "Second page exists in " +
-                                                  "snapshot array.");
-          ok(browser.snapshots[historyIndex + 2], "Third page exists in " +
-                                                  "snapshot array.");
-          ok(browser.snapshots[historyIndex + 3], "Fourth page exists in " +
-                                                  "snapshot array.");
-          is(gHistorySwipeAnimation._trackedSnapshots.length, 4, "Length of " +
-             "array of tracked snapshots is equal to 4 after loading four " +
-             "pages.");
-
-          // Test removal of reference in the middle of the array.
-          gHistorySwipeAnimation._removeTrackedSnapshot(historyIndex + 1,
-                                                        browser);
-          verifyRefRemoved(historyIndex + 1, browser);
-          is(gHistorySwipeAnimation._trackedSnapshots.length, 3, "Length of " +
-             "array of tracked snapshots is equal to 3 after removing one" +
-             "reference from the array with length 4.");
-
-          // Test removal of reference at end of array.
-          gHistorySwipeAnimation._removeTrackedSnapshot(historyIndex + 3,
-                                                        browser);
-          verifyRefRemoved(historyIndex + 3, browser);
-          is(gHistorySwipeAnimation._trackedSnapshots.length, 2, "Length of " +
-             "array of tracked snapshots is equal to 2 after removing two" +
-             "references from the array with length 4.");
-
-          // Test removal of reference at head of array.
-          gHistorySwipeAnimation._removeTrackedSnapshot(historyIndex,
-                                                        browser);
-          verifyRefRemoved(historyIndex, browser);
-          is(gHistorySwipeAnimation._trackedSnapshots.length, 1, "Length of " +
-             "array of tracked snapshots is equal to 1 after removing three" +
-             "references from the array with length 4.");
-
-          cleanupArray();
-          test2();
-        });
-      });
-    });
-  });
-}
-
-function test2() {
-  // Test growing of snapshot array across tabs.
-  let tab = gBrowser.selectedTab;
-
-  load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-    load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
-      is(gHistorySwipeAnimation._trackedSnapshots.length, 2, "Length of " +
-         "snapshot array is equal to 2 after loading two pages");
-      let prevTab = tab;
-      tab = BrowserTestUtils.addTab(gBrowser, "about:newtab");
-      gBrowser.selectedTab = tab;
-      load(tab, HTTPROOT + "browser_bug678392-2.html" /* initial page */,
-           function() {
-        load(tab, HTTPROOT + "browser_bug678392-1.html", function() {
-          load(tab, HTTPROOT + "browser_bug678392-2.html", function() {
-            is(gHistorySwipeAnimation._trackedSnapshots.length, 4, "Length " +
-               "of snapshot array is equal to 4 after loading two pages in " +
-               "two tabs each.");
-            gBrowser.removeCurrentTab();
-            gBrowser.selectedTab = prevTab;
-            cleanupArray();
-            test3();
-          });
-        });
-      });
-    });
-  });
-}
-
-function test3() {
-  // Test uninit of gHistorySwipeAnimation.
-  // This test MUST be the last one to execute.
-  gHistorySwipeAnimation.uninit();
-  is(gHistorySwipeAnimation.active, false, "History swipe animation support " +
-     "was successfully uninitialized");
-  finish();
-}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/historySwipeAnimation/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+  ]
+};
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/historySwipeAnimation/browser.ini
@@ -0,0 +1,1 @@
+[browser_historySwipeAnimation.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/historySwipeAnimation/browser_historySwipeAnimation.js
@@ -0,0 +1,36 @@
+/* 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/. */
+
+function test() {
+  waitForExplicitFinish();
+
+  BrowserOpenTab();
+  let tab = gBrowser.selectedTab;
+  registerCleanupFunction(function() { gBrowser.removeTab(tab); });
+
+  ok(gHistorySwipeAnimation, "gHistorySwipeAnimation exists.");
+
+  if (!gHistorySwipeAnimation._isSupported()) {
+    is(gHistorySwipeAnimation.active, false, "History swipe animation is not " +
+       "active when not supported by the platform.");
+    finish();
+    return;
+  }
+
+  gHistorySwipeAnimation.init();
+
+  is(gHistorySwipeAnimation.active, true, "History swipe animation support " +
+     "was successfully initialized when supported.");
+
+  test0();
+
+  function test0() {
+    // Test uninit of gHistorySwipeAnimation.
+    // This test MUST be the last one to execute.
+    gHistorySwipeAnimation.uninit();
+    is(gHistorySwipeAnimation.active, false, "History swipe animation support " +
+       "was successfully uninitialized");
+    finish();
+  }
+}
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -91,16 +91,17 @@ browser.jar:
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
         content/browser/defaultthemes/dark.icon.svg   (content/defaultthemes/dark.icon.svg)
         content/browser/defaultthemes/light.icon.svg  (content/defaultthemes/light.icon.svg)
+        content/browser/history-swipe-arrow.svg       (content/history-swipe-arrow.svg)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
         content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
         content/browser/pageinfo/security.js          (content/pageinfo/security.js)
         content/browser/robot.ico                     (content/robot.ico)
         content/browser/static-robot.png              (content/static-robot.png)
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -28,16 +28,17 @@ TESTING_JS_MODULES += [
 BROWSER_CHROME_MANIFESTS += [
     'content/test/about/browser.ini',
     'content/test/alerts/browser.ini',
     'content/test/captivePortal/browser.ini',
     'content/test/contextMenu/browser.ini',
     'content/test/favicons/browser.ini',
     'content/test/forms/browser.ini',
     'content/test/general/browser.ini',
+    'content/test/historySwipeAnimation/browser.ini',
     'content/test/metaTags/browser.ini',
     'content/test/pageinfo/browser.ini',
     'content/test/performance/browser.ini',
     'content/test/performance/hidpi/browser.ini',
     'content/test/performance/lowdpi/browser.ini',
     'content/test/permissions/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
--- a/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js
@@ -10,17 +10,17 @@ ChromeUtils.defineModuleGetter(this, "de
 /* globals getExtensionSidebarActors, expectNoSuchActorIDs, testSetExpressionSidebarPanel */
 
 // Import the shared test helpers from the related devtools tests.
 Services.scriptloader.loadSubScript(
   new URL("head_devtools_inspector_sidebar.js", gTestPath).href,
   this);
 
 function isActiveSidebarTabTitle(inspector, expectedTabTitle, message) {
-  const actualTabTitle = inspector.panelDoc.querySelector(".tabs-menu-item.is-active").innerText;
+  const actualTabTitle = inspector.panelDoc.querySelector("#inspector-sidebar .tabs-menu-item.is-active").innerText;
   is(actualTabTitle, expectedTabTitle, message);
 }
 
 function testSetObjectSidebarPanel(panel, expectedCellType, expectedTitle) {
   is(panel.querySelectorAll("table.treeTable").length, 1,
      "The sidebar panel contains a rendered TreeView component");
 
   is(panel.querySelectorAll(`table.treeTable .${expectedCellType}Cell`).length, 1,
--- a/browser/components/payments/moz.build
+++ b/browser/components/payments/moz.build
@@ -2,17 +2,17 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 with Files('**'):
-    BUG_COMPONENT = ('Toolkit', 'WebPayments UI')
+    BUG_COMPONENT = ('Firefox', 'WebPayments UI')
 
 EXTRA_COMPONENTS += [
     'payments.manifest',
     'paymentUIService.js',
 ]
 
 JAR_MANIFESTS += ['jar.mn']
 
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -633,28 +633,16 @@ html|input.urlbar-input {
   opacity: 1.0;
   color: #bbb;
 }
 
 .editBMPanel_rowLabel {
   text-align: end;
 }
 
-/* History Swipe Animation */
-
-#historySwipeAnimationCurrentPage,
-#historySwipeAnimationNextPage {
-  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
-}
-
-#historySwipeAnimationContainer {
-  background: url("chrome://browser/skin/subtle-pattern.png") #B3B9C1;
-}
-
-
 /* ----- SIDEBAR ELEMENTS ----- */
 
 %include ../shared/sidebar.inc.css
 
 #sidebar-box {
   -moz-appearance: -moz-mac-source-list;
   -moz-font-smoothing-background-color: -moz-mac-source-list;
   /* Default font size is 11px on mac, so this is 12px */
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -4,17 +4,16 @@
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
 * skin/classic/browser/syncedtabs/sidebar.css          (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
-  skin/classic/browser/subtle-pattern.png
   skin/classic/browser/panel-expander-closed.png
   skin/classic/browser/panel-expander-closed@2x.png
   skin/classic/browser/panel-expander-open.png
   skin/classic/browser/panel-expander-open@2x.png
   skin/classic/browser/panel-plus-sign.png
   skin/classic/browser/page-livemarks.png
 * skin/classic/browser/pageInfo.css
 * skin/classic/browser/searchbar.css
deleted file mode 100644
index f0597b6a151c2dc73515799387e720dec49483a5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/devtools/client/inspector/animation-old/test/browser_animation_refresh_when_active.js
+++ b/devtools/client/inspector/animation-old/test/browser_animation_refresh_when_active.js
@@ -4,16 +4,18 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the panel only refreshes when it is visible in the sidebar.
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to see if the panel only refreshes when visible");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
   await addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {inspector, panel} = await openAnimationInspector();
   await testRefresh(inspector, panel);
 });
 
 async function testRefresh(inspector, panel) {
   info("Select a non animated node");
--- a/devtools/client/inspector/animation-old/test/browser_animation_refresh_when_active_after_mutations.js
+++ b/devtools/client/inspector/animation-old/test/browser_animation_refresh_when_active_after_mutations.js
@@ -10,16 +10,19 @@ requestLongerTimeout(2);
 
 const EXPECTED_GRAPH_PATH_SEGMENTS = [{ x: 0, y: 0 },
                                       { x: 49999, y: 0.0 },
                                       { x: 50000, y: 0.5 },
                                       { x: 99999, y: 0.5 },
                                       { x: 100000, y: 0 }];
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to see if the panel only refreshes when visible");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+
   info("Open animation inspector once so that activate animation mutations listener");
   await addTab("data:text/html;charset=utf8,<div id='target'>test</div>");
   const { controller, inspector, panel } = await openAnimationInspector();
 
   info("Select other tool to hide animation inspector");
   await inspector.sidebar.select("ruleview");
 
   // Count players-updated event in controller.
--- a/devtools/client/inspector/animation-old/test/browser_animation_timeline_header.js
+++ b/devtools/client/inspector/animation-old/test/browser_animation_timeline_header.js
@@ -10,16 +10,17 @@ requestLongerTimeout(2);
 
 const {findOptimalTimeInterval, TimeScale} = require("devtools/client/inspector/animation-old/utils");
 
 // Should be kept in sync with TIME_GRADUATION_MIN_SPACING in
 // animation-timeline.js
 const TIME_GRADUATION_MIN_SPACING = 40;
 
 add_task(async function() {
+  await pushPref("devtools.inspector.three-pane-enabled", false);
   await addTab(URL_ROOT + "doc_simple_animation.html");
 
   // System scrollbar is enabled by default on our testing envionment and it
   // would shrink width of inspector and affect number of time-ticks causing
   // unexpected results. So, we set it wider to avoid this kind of edge case.
   await pushPref("devtools.toolsidebar-width.inspector", 350);
 
   let {panel} = await openAnimationInspector();
--- a/devtools/client/inspector/animation/test/browser_animation_animation-timeline-tick.js
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-timeline-tick.js
@@ -12,16 +12,17 @@ const TimeScale = require("devtools/clie
 const { findOptimalTimeInterval } =
   require("devtools/client/inspector/animation/utils/utils");
 
 // Should be kept in sync with TIME_GRADUATION_MIN_SPACING in
 // AnimationTimeTickList component.
 const TIME_GRADUATION_MIN_SPACING = 40;
 
 add_task(async function() {
+  await pushPref("devtools.inspector.three-pane-enabled", false);
   await addTab(URL_ROOT + "doc_simple_animation.html");
   await removeAnimatedElementsExcept([".end-delay", ".negative-delay"]);
   const { animationInspector, inspector, panel } = await openAnimationInspector();
   const timeScale = new TimeScale(animationInspector.state.animations);
 
   info("Checking animation list header element existence");
   const listContainerEl = panel.querySelector(".animation-list-container");
   const listHeaderEl = listContainerEl.querySelector(".devtools-toolbar");
--- a/devtools/client/inspector/animation/test/browser_animation_logic_avoid-updating-during-hiding.js
+++ b/devtools/client/inspector/animation/test/browser_animation_logic_avoid-updating-during-hiding.js
@@ -5,16 +5,18 @@
 
 // Animation inspector should not update when hidden.
 // Test for followings:
 // * whether the UIs update after selecting another inspector
 // * whether the UIs update after selecting another tool
 // * whether the UIs update after selecting animation inspector again
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to see if the animation only refreshes when visible");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
   await addTab(URL_ROOT + "doc_custom_playback_rate.html");
   const { animationInspector, inspector, panel } = await openAnimationInspector();
 
   info("Checking the UIs update after selecting another inspector");
   await selectNodeAndWaitForAnimations("head", inspector);
   inspector.sidebar.select("ruleview");
   await selectNode("div", inspector);
   is(animationInspector.state.animations.length, 0,
--- a/devtools/client/inspector/boxmodel/test/browser_boxmodel_sync.js
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_sync.js
@@ -16,29 +16,21 @@ add_task(async function() {
 
   await selectNode("p", inspector);
 
   info("Modify padding-bottom in box model view");
   let span = boxmodel.document.querySelector(".boxmodel-padding.boxmodel-bottom > span");
   EventUtils.synthesizeMouseAtCenter(span, {}, boxmodel.document.defaultView);
   let editor = boxmodel.document.querySelector(".styleinspector-propertyeditor");
 
+  let onRuleViewRefreshed = once(inspector, "rule-view-refreshed");
   EventUtils.synthesizeKey("7", {}, boxmodel.document.defaultView);
   await waitForUpdate(inspector);
+  await onRuleViewRefreshed;
   is(editor.value, "7", "Should have the right value in the editor.");
   EventUtils.synthesizeKey("VK_RETURN", {}, boxmodel.document.defaultView);
 
-  let onRuleViewRefreshed = once(inspector, "rule-view-refreshed");
-  let onRuleViewSelected = once(inspector.sidebar, "ruleview-selected");
-  info("Select the rule view and check that the property was synced there");
+  info("Check that the property was synced with the rule view");
   let ruleView = selectRuleView(inspector);
-
-  info("Wait for the rule view to be selected");
-  await onRuleViewSelected;
-
-  info("Wait for the rule view to be refreshed");
-  await onRuleViewRefreshed;
-  ok(true, "The rule view was refreshed");
-
   let ruleEditor = getRuleViewRuleEditor(ruleView, 0);
   let textProp = ruleEditor.rule.textProps[0];
   is(textProp.value, "7px", "The property has the right value");
 });
--- a/devtools/client/inspector/computed/test/browser_computed_keybindings_02.js
+++ b/devtools/client/inspector/computed/test/browser_computed_keybindings_02.js
@@ -33,17 +33,18 @@ const TEST_URI = `
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = await openComputedView();
   await selectNode("span", inspector);
 
   info("Selecting the first computed style in the list");
-  let firstStyle = view.styleDocument.querySelector(".computed-property-view");
+  let firstStyle = view.styleDocument.querySelector(
+    "#computed-container .computed-property-view");
   ok(firstStyle, "First computed style found in panel");
   firstStyle.focus();
 
   info("Tab to select the 2nd style and press return");
   let onExpanded = inspector.once("computed-view-property-expanded");
   EventUtils.synthesizeKey("KEY_Tab");
   EventUtils.synthesizeKey("KEY_Enter");
   await onExpanded;
--- a/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
+++ b/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
@@ -63,17 +63,18 @@ async function testCollapseOnTwistyClick
   ok(div.childNodes.length === 0,
     "Matched selectors are collapsed on twisty click");
 }
 
 async function testExpandOnDblClick({styleDocument, styleWindow}, inspector) {
   info("Testing that a property expands on container dbl-click");
 
   info("Getting computed property container");
-  let container = styleDocument.querySelector(".computed-property-view");
+  let container = styleDocument.querySelector(
+    "#computed-container .computed-property-view");
   ok(container, "Container found");
 
   container.scrollIntoView();
 
   let onExpand = inspector.once("computed-view-property-expanded");
   info("Dbl-clicking on the container");
   EventUtils.synthesizeMouseAtCenter(container, {clickCount: 2}, styleWindow);
 
@@ -83,17 +84,18 @@ async function testExpandOnDblClick({sty
   let div = styleDocument.querySelector(".computed-property-content .matchedselectors");
   ok(div.childNodes.length > 0, "Matched selectors are expanded on dblclick");
 }
 
 async function testCollapseOnDblClick({styleDocument, styleWindow}, inspector) {
   info("Testing that a property collapses on container dbl-click");
 
   info("Getting computed property container");
-  let container = styleDocument.querySelector(".computed-property-view");
+  let container = styleDocument.querySelector(
+    "#computed-container .computed-property-view");
   ok(container, "Container found");
 
   let onCollapse = inspector.once("computed-view-property-collapsed");
   info("Dbl-clicking on the container");
   EventUtils.synthesizeMouseAtCenter(container, {clickCount: 2}, styleWindow);
 
   await onCollapse;
 
--- a/devtools/client/inspector/computed/test/head.js
+++ b/devtools/client/inspector/computed/test/head.js
@@ -30,17 +30,18 @@ function fireCopyEvent(element) {
  * @param {CssComputedView} view
  *        The instance of the computed view panel
  * @param {String} name
  *        The name of the property to retrieve
  * @return an object {nameSpan, valueSpan}
  */
 function getComputedViewProperty(view, name) {
   let prop;
-  for (let property of view.styleDocument.querySelectorAll(".computed-property-view")) {
+  for (let property of view.styleDocument.querySelectorAll(
+      "#computed-container .computed-property-view")) {
     let nameSpan = property.querySelector(".computed-property-name");
     let valueSpan = property.querySelector(".computed-property-value");
 
     if (nameSpan.firstChild.textContent === name) {
       prop = {nameSpan: nameSpan, valueSpan: valueSpan};
       break;
     }
   }
@@ -80,17 +81,18 @@ function getComputedViewPropertyView(vie
  * @param {String} name
  *        The name of the property to retrieve
  * @return {Promise} A promise that resolves to the property matched rules
  * container
  */
 var getComputedViewMatchedRules = async function(view, name) {
   let expander;
   let propertyContent;
-  for (let property of view.styleDocument.querySelectorAll(".computed-property-view")) {
+  for (let property of view.styleDocument.querySelectorAll(
+      "#computed-container .computed-property-view")) {
     let nameSpan = property.querySelector(".computed-property-name");
     if (nameSpan.firstChild.textContent === name) {
       expander = property.querySelector(".computed-expandable");
       propertyContent = property.nextSibling;
       break;
     }
   }
 
@@ -173,17 +175,17 @@ function selectAllText(view) {
  * @param {CssComputedView} view
  *        The instance of the computed view panel
  * @param {String} expectedPattern
  *        A regular expression used to check the content of the clipboard
  */
 async function copyAllAndCheckClipboard(view, expectedPattern) {
   selectAllText(view);
   let contentDoc = view.styleDocument;
-  let prop = contentDoc.querySelector(".computed-property-view");
+  let prop = contentDoc.querySelector("#computed-container .computed-property-view");
 
   try {
     info("Trigger a copy event and wait for the clipboard content");
     await waitForClipboardPromise(() => fireCopyEvent(prop),
                                   () => checkClipboard(expectedPattern));
   } catch (e) {
     failClipboardCheck(expectedPattern);
   }
@@ -200,17 +202,18 @@ async function copyAllAndCheckClipboard(
  *        { start: {prop: 1, offset: 0}, end: {prop: 3, offset: 5} }
  * @param {String} expectedPattern
  *        A regular expression used to check the content of the clipboard
  */
 async function copySomeTextAndCheckClipboard(view, positions, expectedPattern) {
   info("Testing selection copy");
 
   let contentDocument = view.styleDocument;
-  let props = contentDocument.querySelectorAll(".computed-property-view");
+  let props = contentDocument.querySelectorAll(
+    "#computed-container .computed-property-view");
 
   info("Create the text selection range");
   let range = contentDocument.createRange();
   range.setStart(props[positions.start.prop], positions.start.offset);
   range.setEnd(props[positions.end.prop], positions.end.offset);
   contentDocument.defaultView.getSelection().addRange(range);
 
   try {
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_development_15.4.1.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_development_15.4.1.js
@@ -123,10 +123,13 @@ const TEST_DATA = [
 }`
       }
     ]
   }
 ];
 /* eslint-enable */
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to avoid sidebar width issues with opening events");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+  await pushPref("devtools.toolsidebar-width.inspector", 350);
   await runEventPopupTests(TEST_URL, TEST_DATA);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_development_15.4.1_jsx.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_development_15.4.1_jsx.js
@@ -123,10 +123,13 @@ const TEST_DATA = [
 }`
       }
     ]
   }
 ];
 /* eslint-enable */
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to avoid sidebar width issues with opening events");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+  await pushPref("devtools.toolsidebar-width.inspector", 350);
   await runEventPopupTests(TEST_URL, TEST_DATA);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_production_15.3.1.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_production_15.3.1.js
@@ -123,10 +123,13 @@ const TEST_DATA = [
 }`
       }
     ]
   }
 ];
 /* eslint-enable */
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to avoid sidebar width issues with opening events");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+  await pushPref("devtools.toolsidebar-width.inspector", 350);
   await runEventPopupTests(TEST_URL, TEST_DATA);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_production_15.3.1_jsx.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_production_15.3.1_jsx.js
@@ -123,10 +123,13 @@ const TEST_DATA = [
 }`
       }
     ]
   }
 ];
 /* eslint-enable */
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to avoid sidebar width issues with opening events");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+  await pushPref("devtools.toolsidebar-width.inspector", 350);
   await runEventPopupTests(TEST_URL, TEST_DATA);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_production_16.2.0.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_production_16.2.0.js
@@ -123,10 +123,13 @@ const TEST_DATA = [
 }`
       }
     ]
   }
 ];
 /* eslint-enable */
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to avoid sidebar width issues with opening events");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+  await pushPref("devtools.toolsidebar-width.inspector", 350);
   await runEventPopupTests(TEST_URL, TEST_DATA);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_events_react_production_16.2.0_jsx.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events_react_production_16.2.0_jsx.js
@@ -123,10 +123,13 @@ const TEST_DATA = [
 }`
       }
     ]
   }
 ];
 /* eslint-enable */
 
 add_task(async function() {
+  info("Switch to 2 pane inspector to avoid sidebar width issues with opening events");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
+  await pushPref("devtools.toolsidebar-width.inspector", 350);
   await runEventPopupTests(TEST_URL, TEST_DATA);
 });
--- a/devtools/client/inspector/markup/test/helper_events_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_events_test_runner.js
@@ -69,16 +69,17 @@ async function checkEventsForNode(test, 
 
   let sourceMapPromise = null;
   if (isSourceMapped) {
     sourceMapPromise = tooltip.once("event-tooltip-source-map-ready");
   }
 
   // Click button to show tooltip
   info("Clicking evHolder");
+  evHolder.scrollIntoView();
   EventUtils.synthesizeMouseAtCenter(evHolder, {},
     inspector.markup.doc.defaultView);
   await tooltip.once("shown");
   info("tooltip shown");
 
   if (isSourceMapped) {
     info("Waiting for source map to be applied");
     await sourceMapPromise;
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -189,17 +189,19 @@ RuleEditor.prototype = {
           title: l10n("rule.selectorHighlighter.tooltip")
         });
         selectorHighlighter.addEventListener("click", () => {
           this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
         });
 
         this.uniqueSelector = selector;
         this.emit("selector-icon-created");
-      }.bind(this))();
+      }.bind(this))().catch(error => {
+        console.error("Exception while getting unique selector", error);
+      });
     }
 
     this.openBrace = createChild(header, "span", {
       class: "ruleview-ruleopen",
       textContent: " {"
     });
 
     this.propertyList = createChild(code, "ul", {
--- a/devtools/client/inspector/shared/test/browser_styleinspector_refresh_when_active.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_refresh_when_active.js
@@ -1,15 +1,15 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// Test that the style-inspector views only refresh when they are active.
+// Test that the rule and computed view refreshes when they are active.
 
 const TEST_URI = `
   <div id="one" style="color:red;">one</div>
   <div id="two" style="color:blue;">two</div>
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
@@ -29,12 +29,11 @@ add_task(async function() {
   ok(getComputedViewPropertyValue(cView, "color"), "#F00",
     "The computed-view shows the properties for test node one");
 
   info("Selecting test node two");
   await selectNode("#two", inspector);
 
   ok(getComputedViewPropertyValue(cView, "color"), "#00F",
     "The computed-view shows the properties for test node two");
-
-  is(getRuleViewPropertyValue(view, "element", "color"), "red",
-    "The rule-view doesn't the properties for test node two");
+  is(getRuleViewPropertyValue(view, "element", "color"), "blue",
+    "The rule-view shows the properties for test node two");
 });
--- a/devtools/client/inspector/test/browser_inspector_pane-toggle-01.js
+++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-01.js
@@ -3,17 +3,18 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the inspector panel has a 3 pane toggle button, and that
 // this button is visible both in BOTTOM and SIDE hosts.
 
 add_task(async function() {
-  await pushPref("devtools.inspector.three-pane-toggle", true);
+  info("Switch to 2 pane inspector to test that 3 pane toggle button behavior");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
 
   info("Open the inspector in a bottom toolbox host");
   const { inspector, toolbox } = await openInspectorForURL("about:blank", "bottom");
 
   const button = inspector.panelDoc.querySelector(".sidebar-toggle");
   ok(button, "The toggle button exists in the DOM");
   ok(button.getAttribute("title"), "The title tooltip has initial state");
   ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state");
--- a/devtools/client/inspector/test/browser_inspector_pane-toggle-02.js
+++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-02.js
@@ -3,17 +3,18 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the 3 pane toggle button can toggle on and off the inspector's 3 pane mode,
 // and the 3 panes rendered are all of equal widths in the BOTTOM host.
 
 add_task(async function() {
-  await pushPref("devtools.inspector.three-pane-toggle", true);
+  info("Switch to 2 pane inspector to test that 3 pane toggle button behavior");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
 
   const { inspector } = await openInspectorForURL("about:blank");
   const { panelDoc: doc } = inspector;
   const button = doc.querySelector(".sidebar-toggle");
   const ruleViewSidebar = inspector.sidebarSplitBox.startPanelContainer;
   const toolboxWidth = doc.getElementById("inspector-splitter-box").clientWidth;
 
   ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state");
--- a/devtools/client/inspector/test/browser_inspector_pane-toggle-03.js
+++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-03.js
@@ -6,17 +6,18 @@
 
 // Tests that the 3 pane inspector toggle can render the middle and right panels of equal
 // sizes when the original sidebar can be doubled in width and be smaller than half the
 // toolbox's width in the BOTTOM host.
 
 const SIDEBAR_WIDTH = 200;
 
 add_task(async function() {
-  await pushPref("devtools.inspector.three-pane-toggle", true);
+  info("Switch to 2 pane inspector to test that 3 pane toggle button behavior");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
 
   const { inspector } = await openInspectorForURL("about:blank");
   const { panelDoc: doc } = inspector;
   const button = doc.querySelector(".sidebar-toggle");
   const toolboxWidth = doc.getElementById("inspector-splitter-box").clientWidth;
 
   if (toolboxWidth < 600) {
     ok(true, "Can't run the full test because the toolbox width is too small.");
--- a/devtools/client/inspector/test/browser_inspector_pane-toggle-04.js
+++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-04.js
@@ -3,17 +3,18 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the 3 pane inspector toggle button can render the bottom-left and
 // bottom-right panels of equal sizes in the SIDE host.
 
 add_task(async function() {
-  await pushPref("devtools.inspector.three-pane-toggle", true);
+  info("Switch to 2 pane inspector to test that 3 pane toggle button behavior");
+  await pushPref("devtools.inspector.three-pane-enabled", false);
 
   const { inspector, toolbox } = await openInspectorForURL("about:blank");
   const { panelDoc: doc } = inspector;
 
   info("Switch the host to side type");
   await toolbox.switchHost("side");
 
   const button = doc.querySelector(".sidebar-toggle");
--- a/devtools/client/inspector/test/browser_inspector_sidebarstate.js
+++ b/devtools/client/inspector/test/browser_inspector_sidebarstate.js
@@ -4,35 +4,34 @@
 "use strict";
 
 const TEST_URI = "data:text/html;charset=UTF-8," +
   "<h1>browser_inspector_sidebarstate.js</h1>";
 
 add_task(async function() {
   let { inspector, toolbox } = await openInspectorForURL(TEST_URI);
 
-  info("Selecting ruleview.");
-  inspector.sidebar.select("ruleview");
-
-  is(inspector.sidebar.getCurrentTabID(), "ruleview",
-     "Rule View is selected by default");
-
   info("Selecting computed view.");
   inspector.sidebar.select("computedview");
 
-  // Finish initialization of the computed panel before
-  // destroying the toolbox.
-  await waitForTick();
+  is(inspector.sidebar.getCurrentTabID(), "computedview",
+    "Computed View is selected");
+
+  info("Selecting layout view.");
+  inspector.sidebar.select("layoutview");
+
+  is(inspector.sidebar.getCurrentTabID(), "layoutview",
+    "Layout View is selected");
 
   info("Closing inspector.");
   await toolbox.destroy();
 
   info("Re-opening inspector.");
   inspector = (await openInspector()).inspector;
 
   if (!inspector.sidebar.getCurrentTabID()) {
     info("Default sidebar still to be selected, adding select listener.");
     await inspector.sidebar.once("select");
   }
 
-  is(inspector.sidebar.getCurrentTabID(), "computedview",
-     "Computed view is selected by default.");
+  is(inspector.sidebar.getCurrentTabID(), "layoutview",
+     "Layout view is selected by default.");
 });
--- a/devtools/client/inspector/test/shared-head.js
+++ b/devtools/client/inspector/test/shared-head.js
@@ -73,17 +73,17 @@ var openInspectorSidebarTab = async func
 /**
  * Open the toolbox, with the inspector tool visible, and the rule-view
  * sidebar tab selected.
  *
  * @return a promise that resolves when the inspector is ready and the rule view
  * is visible and ready
  */
 function openRuleView() {
-  return openInspectorSidebarTab("ruleview").then(data => {
+  return openInspector().then(data => {
     // Replace the view to use a custom debounce function that can be triggered manually
     // through an additional ".flush()" property.
     data.inspector.getPanel("ruleview").view.debounce = manualDebounce();
 
     return {
       toolbox: data.toolbox,
       inspector: data.inspector,
       testActor: data.testActor,
@@ -144,17 +144,16 @@ function openLayoutView() {
 /**
  * Select the rule view sidebar tab on an already opened inspector panel.
  *
  * @param {InspectorPanel} inspector
  *        The opened inspector panel
  * @return {CssRuleView} the rule view
  */
 function selectRuleView(inspector) {
-  inspector.sidebar.select("ruleview");
   return inspector.getPanel("ruleview").view;
 }
 
 /**
  * Select the computed view sidebar tab on an already opened inspector panel.
  *
  * @param {InspectorPanel} inspector
  *        The opened inspector panel
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -44,30 +44,30 @@ pref("devtools.command-button-measure.en
 pref("devtools.command-button-noautohide.enabled", false);
 
 // Inspector preferences
 // Enable the Inspector
 pref("devtools.inspector.enabled", true);
 // What was the last active sidebar in the inspector
 pref("devtools.inspector.activeSidebar", "ruleview");
 pref("devtools.inspector.remote", false);
+
+#if defined(NIGHTLY_BUILD)
+// Show the 3 pane onboarding tooltip in the inspector
+pref("devtools.inspector.show-three-pane-tooltip", true);
+// Enable the 3 pane mode in the inspector
+pref("devtools.inspector.three-pane-enabled", true);
 // Enable the 3 pane mode toggle in the inspector
-#if defined(NIGHTLY_BUILD)
 pref("devtools.inspector.three-pane-toggle", true);
 #else
+pref("devtools.inspector.show-three-pane-tooltip", false);
+pref("devtools.inspector.three-pane-enabled", false);
 pref("devtools.inspector.three-pane-toggle", false);
 #endif
-// Enable the 3 pane mode in the inspector
-pref("devtools.inspector.three-pane-enabled", false);
-// Show the 3 pane onboarding tooltip in the inspector
-#if defined(NIGHTLY_BUILD)
-pref("devtools.inspector.show-three-pane-tooltip", true);
-#else
-pref("devtools.inspector.show-three-pane-tooltip", false);
-#endif
+
 // Collapse pseudo-elements by default in the rule-view
 pref("devtools.inspector.show_pseudo_elements", false);
 // The default size for image preview tooltips in the rule-view/computed-view/markup-view
 pref("devtools.inspector.imagePreviewTooltipSize", 300);
 // Enable user agent style inspection in rule-view
 pref("devtools.inspector.showUserAgentStyles", false);
 // Show all native anonymous content (like controls in <video> tags)
 pref("devtools.inspector.showAllAnonymousContent", false);
--- a/devtools/client/shared/test/browser_telemetry_sidebar.js
+++ b/devtools/client/shared/test/browser_telemetry_sidebar.js
@@ -24,17 +24,17 @@ add_task(async function() {
   await gDevTools.closeToolbox(target);
   gBrowser.removeCurrentTab();
 });
 
 function testSidebar(toolbox) {
   info("Testing sidebar");
 
   let inspector = toolbox.getCurrentPanel();
-  let sidebarTools = ["ruleview", "computedview", "layoutview", "fontinspector",
+  let sidebarTools = ["computedview", "layoutview", "fontinspector",
                       "animationinspector"];
 
   // Concatenate the array with itself so that we can open each tool twice.
   sidebarTools = [...sidebarTools, ...sidebarTools];
 
   return new Promise(resolve => {
     // See TOOL_DELAY for why we need setTimeout here
     setTimeout(function selectSidebarTab() {
@@ -50,17 +50,16 @@ function testSidebar(toolbox) {
     }, TOOL_DELAY);
   });
 }
 
 function checkResults() {
   // For help generating these tests use generateTelemetryTests("DEVTOOLS_")
   // here.
   checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_COUNT", "", [1, 0, 0], "array");
-  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_COUNT", "", [3, 0, 0], "array");
-  checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT", "", [2, 0, 0], "array");
+  checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_COUNT", "", [1, 0, 0], "array");
+  checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT", "", [3, 0, 0], "array");
   checkTelemetry("DEVTOOLS_LAYOUTVIEW_OPENED_COUNT", "", [2, 0, 0], "array");
   checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_COUNT", "", [2, 0, 0], "array");
-  checkTelemetry("DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");
   checkTelemetry("DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");
   checkTelemetry("DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");
   checkTelemetry("DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS", "", null, "hasentries");
 }
--- a/devtools/client/shared/test/shared-head.js
+++ b/devtools/client/shared/test/shared-head.js
@@ -106,19 +106,23 @@ function loadFrameScriptUtils(browser = 
   info("Loading the helper frame script " + frameURL);
   mm.loadFrameScript(frameURL, false);
   SimpleTest.registerCleanupFunction(() => {
     mm = null;
   });
   return mm;
 }
 
+Services.prefs.setBoolPref("devtools.inspector.three-pane-enabled", true);
+Services.prefs.setBoolPref("devtools.inspector.three-pane-toggle", true);
 Services.prefs.setBoolPref("devtools.inspector.show-three-pane-tooltip", false);
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
+  Services.prefs.clearUserPref("devtools.inspector.three-pane-enabled");
+  Services.prefs.clearUserPref("devtools.inspector.three-pane-toggle");
   Services.prefs.clearUserPref("devtools.inspector.show-three-pane-tooltip");
   Services.prefs.clearUserPref("devtools.toolbox.host");
   Services.prefs.clearUserPref("devtools.toolbox.previousHost");
   Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
   Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight");
 });
 
 registerCleanupFunction(async function cleanup() {
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -336,17 +336,17 @@ subsuite = clipboard
 [browser_webconsole_shows_reqs_from_netmonitor.js]
 [browser_webconsole_shows_reqs_in_netmonitor.js]
 [browser_webconsole_sidebar_object_expand_when_message_pruned.js]
 [browser_webconsole_sourcemap_css.js]
 [browser_webconsole_sourcemap_error.js]
 [browser_webconsole_sourcemap_invalid.js]
 [browser_webconsole_sourcemap_nosource.js]
 [browser_webconsole_split.js]
-skip-if = os == 'osx' || (os == 'win' && !debug) # Bug 1454123 disabled on OS X and Win for frequent failures
+skip-if = (os == 'mac') || (os == 'linux' && !debug && bits == 64) || (os == 'win') # Bug 1454123 disabled on OS X, Windows and Linux64 for frequent failures
 [browser_webconsole_split_escape_key.js]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
 [browser_webconsole_stacktrace_location_debugger_link.js]
 [browser_webconsole_stacktrace_location_scratchpad_link.js]
 [browser_webconsole_strict_mode_errors.js]
 [browser_webconsole_string.js]
 [browser_webconsole_time_methods.js]
--- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
+++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
@@ -46,17 +46,17 @@ struct DevTools : public ::testing::Test
     if (!cx)
       return;
 
     JS_BeginRequest(cx);
 
     global.init(cx, createGlobal());
     if (!global)
       return;
-    JS_EnterCompartment(cx, global);
+    JS::EnterRealm(cx, global);
 
     compartment = js::GetContextCompartment(cx);
     zone = js::GetContextZone(cx);
 
     _initialized = true;
   }
 
   JSContext* getContext() {
@@ -83,17 +83,17 @@ struct DevTools : public ::testing::Test
     };
     return &globalClass;
   }
 
   JSObject* createGlobal()
   {
     /* Create the global object. */
     JS::RootedObject newGlobal(cx);
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                    JS::FireOnNewGlobalHook, options);
     if (!newGlobal)
       return nullptr;
 
     JSAutoRealm ar(cx, newGlobal);
 
     /* Populate the global object with the standard globals, like Object and
@@ -103,17 +103,17 @@ struct DevTools : public ::testing::Test
 
     return newGlobal;
   }
 
   virtual void TearDown() {
     _initialized = false;
 
     if (global) {
-      JS_LeaveCompartment(cx, nullptr);
+      JS::LeaveRealm(cx, nullptr);
       global = nullptr;
     }
     if (cx)
       JS_EndRequest(cx);
   }
 };
 
 
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Test that heap snapshots cross compartment boundaries when expected.
 
 #include "DevTools.h"
 
 DEF_TEST(DoesCrossCompartmentBoundaries, {
     // Create a new global to get a new compartment.
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
                                                       getGlobalClass(),
                                                       nullptr,
                                                       JS::FireOnNewGlobalHook,
                                                       options));
     ASSERT_TRUE(newGlobal);
     JSCompartment* newCompartment = nullptr;
     {
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Test that heap snapshots walk the compartment boundaries correctly.
 
 #include "DevTools.h"
 
 DEF_TEST(DoesntCrossCompartmentBoundaries, {
     // Create a new global to get a new compartment.
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
                                                       getGlobalClass(),
                                                       nullptr,
                                                       JS::FireOnNewGlobalHook,
                                                       options));
     ASSERT_TRUE(newGlobal);
     JSCompartment* newCompartment = nullptr;
     {
--- a/dom/base/ProcessGlobal.cpp
+++ b/dom/base/ProcessGlobal.cpp
@@ -124,17 +124,17 @@ ProcessGlobal::Init()
   }
   mInitialized = true;
 
   return InitChildGlobalInternal(NS_LITERAL_CSTRING("processChildGlobal"));
 }
 
 bool
 ProcessGlobal::WrapGlobalObject(JSContext* aCx,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 JS::MutableHandle<JSObject*> aReflector)
 {
   bool ok = ContentProcessMessageManagerBinding::Wrap(aCx, this, this, aOptions,
                                                       nsJSPrincipals::get(mPrincipal),
                                                       true, aReflector);
   if (ok) {
     // Since we can't rewrap we have to preserve the global's wrapper here.
     PreserveWrapper(ToSupports(this));
--- a/dom/base/ProcessGlobal.h
+++ b/dom/base/ProcessGlobal.h
@@ -59,17 +59,17 @@ public:
   void MarkForCC();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override
   {
     MOZ_CRASH("We should never get here!");
   }
   virtual bool WrapGlobalObject(JSContext* aCx,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 JS::MutableHandle<JSObject*> aReflector) override;
 
   using MessageManagerGlobal::AddMessageListener;
   using MessageManagerGlobal::RemoveMessageListener;
   using MessageManagerGlobal::AddWeakMessageListener;
   using MessageManagerGlobal::RemoveWeakMessageListener;
 
   // ContentProcessMessageManager
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -553,31 +553,31 @@ nsFrameMessageManager::SendMessage(JSCon
                                    nsTArray<JS::Value>& aResult,
                                    ErrorResult& aError)
 {
   NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!IsBroadcaster(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!GetParentManager(),
                "Should not have parent manager in content!");
 
-  if (!AllowMessage(aData.DataLength(), aMessageName)) {
-    aError.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
 #ifdef FUZZING
   if (aData.DataLength() > 0) {
     MessageManagerFuzzer::TryMutate(
       aCx,
       aMessageName,
       &aData,
       JS::UndefinedHandleValue);
   }
 #endif
 
+  if (!AllowMessage(aData.DataLength(), aMessageName)) {
+    aError.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
   if (!mCallback) {
     aError.Throw(NS_ERROR_NOT_INITIALIZED);
     return;
   }
 
   nsTArray<StructuredCloneData> retval;
 
   TimeStamp start = TimeStamp::Now();
@@ -638,64 +638,42 @@ nsFrameMessageManager::DispatchAsyncMess
 
   nsresult rv = mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return NS_OK;
 }
 
-nsresult
-nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
-                                            const JS::Value& aJSON,
-                                            const JS::Value& aObjects,
-                                            nsIPrincipal* aPrincipal,
-                                            const JS::Value& aTransfers,
-                                            JSContext* aCx,
-                                            uint8_t aArgc)
-{
-  StructuredCloneData data;
-  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, aTransfers, data)) {
-    return NS_ERROR_DOM_DATA_CLONE_ERR;
-  }
-
-#ifdef FUZZING
-  if (data.DataLength()) {
-    MessageManagerFuzzer::TryMutate(aCx, aMessageName, &data, aTransfers);
-  }
-#endif
-
-  if (!AllowMessage(data.DataLength(), aMessageName)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JS::Rooted<JSObject*> objects(aCx);
-  if (aArgc >= 3 && aObjects.isObject()) {
-    objects = &aObjects.toObject();
-  }
-
-  return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
-                                      aPrincipal);
-}
-
 void
 nsFrameMessageManager::DispatchAsyncMessage(JSContext* aCx,
                                             const nsAString& aMessageName,
                                             JS::Handle<JS::Value> aObj,
                                             JS::Handle<JSObject*> aObjects,
                                             nsIPrincipal* aPrincipal,
                                             JS::Handle<JS::Value> aTransfers,
                                             ErrorResult& aError)
 {
   StructuredCloneData data;
   if (!aObj.isUndefined() && !GetParamsForMessage(aCx, aObj, aTransfers, data)) {
     aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
+#ifdef FUZZING
+  if (data.DataLength()) {
+    MessageManagerFuzzer::TryMutate(aCx, aMessageName, &data, aTransfers);
+  }
+#endif
+
+  if (!AllowMessage(data.DataLength(), aMessageName)) {
+    aError.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
   aError = DispatchAsyncMessageInternal(aCx, aMessageName, data, aObjects,
                                         aPrincipal);
 }
 
 class MMListenerRemover
 {
 public:
   explicit MMListenerRemover(nsFrameMessageManager* aMM)
@@ -1463,17 +1441,17 @@ nsMessageManagerScriptExecutor::InitChil
 {
   AutoSafeJSContext cx;
   if (!SystemBindingInitIds(cx)) {
     return false;
   }
 
   nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
 
-  JS::CompartmentOptions options;
+  JS::RealmOptions options;
   options.creationOptions().setSystemZone();
 
   xpc::InitGlobalObjectOptions(options, mPrincipal);
   JS::Rooted<JSObject*> global(cx);
   if (!WrapGlobalObject(cx, options, &global)) {
     return false;
   }
 
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -251,24 +251,16 @@ public:
 
   void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
 
   mozilla::dom::ipc::MessageManagerCallback* GetCallback()
   {
     return mCallback;
   }
 
-  nsresult DispatchAsyncMessage(const nsAString& aMessageName,
-                                const JS::Value& aJSON,
-                                const JS::Value& aObjects,
-                                nsIPrincipal* aPrincipal,
-                                const JS::Value& aTransfers,
-                                JSContext* aCx,
-                                uint8_t aArgc);
-
   nsresult DispatchAsyncMessageInternal(JSContext* aCx,
                                         const nsAString& aMessage,
                                         StructuredCloneData& aData,
                                         JS::Handle<JSObject*> aCpows,
                                         nsIPrincipal* aPrincipal);
   bool IsGlobal() { return mGlobal; }
   bool IsBroadcaster() { return mIsBroadcaster; }
   bool IsChrome() { return mChrome; }
@@ -460,17 +452,17 @@ protected:
   void TryCacheLoadAndCompileScript(const nsAString& aURL,
                                     bool aRunInGlobalScope,
                                     bool aShouldCache,
                                     JS::MutableHandle<JSScript*> aScriptp);
   void TryCacheLoadAndCompileScript(const nsAString& aURL,
                                     bool aRunInGlobalScope);
   bool InitChildGlobalInternal(const nsACString& aID);
   virtual bool WrapGlobalObject(JSContext* aCx,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 JS::MutableHandle<JSObject*> aReflector) = 0;
   void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
   void Unlink();
   nsCOMPtr<nsIPrincipal> mPrincipal;
   AutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
 
   static nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>* sCachedScripts;
   static mozilla::StaticRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -1557,19 +1557,19 @@ InitializeLegacyNetscapeObject(JSContext
 
   /* Define PrivilegeManager object with the necessary "static" methods. */
   obj = JS_DefineObject(aCx, obj, "PrivilegeManager", nullptr);
   NS_ENSURE_TRUE(obj, false);
 
   return JS_DefineFunctions(aCx, obj, EnablePrivilegeSpec);
 }
 
-static JS::CompartmentCreationOptions&
+static JS::RealmCreationOptions&
 SelectZone(nsGlobalWindowInner* aNewInner,
-           JS::CompartmentCreationOptions& aOptions)
+           JS::RealmCreationOptions& aOptions)
 {
   if (aNewInner->GetOuterWindow()) {
     nsGlobalWindowOuter *top = aNewInner->GetTopInternal();
 
     // If we have a top-level window, use its zone.
     if (top && top->GetGlobalJSObject()) {
       return aOptions.setExistingZone(top->GetGlobalJSObject());
     }
@@ -1595,17 +1595,17 @@ CreateNativeGlobalForInner(JSContext* aC
   MOZ_ASSERT(aNewInner);
   MOZ_ASSERT(aPrincipal);
 
   // DOMWindow with nsEP is not supported, we have to make sure
   // no one creates one accidentally.
   nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
   MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
 
-  JS::CompartmentOptions options;
+  JS::RealmOptions options;
 
   SelectZone(aNewInner, options.creationOptions());
 
   options.creationOptions().setSecureContext(aIsSecureContext);
 
   xpc::InitGlobalObjectOptions(options, aPrincipal);
 
   // Determine if we need the Components object.
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -173,17 +173,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal, DOMEventTargetHelper)
 
 bool
 nsInProcessTabChildGlobal::WrapGlobalObject(JSContext* aCx,
-                                            JS::CompartmentOptions& aOptions,
+                                            JS::RealmOptions& aOptions,
                                             JS::MutableHandle<JSObject*> aReflector)
 {
   bool ok = ContentFrameMessageManagerBinding::Wrap(aCx, this, this, aOptions,
                                                     nsJSPrincipals::get(mPrincipal),
                                                     true, aReflector);
   if (ok) {
     // Since we can't rewrap we have to preserve the global's wrapper here.
     PreserveWrapper(ToSupports(this));
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -64,17 +64,17 @@ public:
   void MarkForCC();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override
   {
     MOZ_CRASH("We should never get here!");
   }
   virtual bool WrapGlobalObject(JSContext* aCx,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 JS::MutableHandle<JSObject*> aReflector) override;
 
   virtual already_AddRefed<nsPIDOMWindowOuter>
     GetContent(mozilla::ErrorResult& aError) override;
   virtual already_AddRefed<nsIDocShell>
     GetDocShell(mozilla::ErrorResult& aError) override
   {
     nsCOMPtr<nsIDocShell> docShell(mDocShell);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3130,17 +3130,17 @@ struct CreateGlobalOptions<nsGlobalWindo
 //
 // Typically this method's caller will want to ensure that
 // xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
 // called after, this method, to ensure that this global object and its
 // compartment are consistent with other global objects.
 template <class T, ProtoHandleGetter GetProto>
 bool
 CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
-             const JSClass* aClass, JS::CompartmentOptions& aOptions,
+             const JSClass* aClass, JS::RealmOptions& aOptions,
              JSPrincipals* aPrincipal, bool aInitStandardClasses,
              JS::MutableHandle<JSObject*> aGlobal)
 {
   aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
   if (xpc::SharedMemoryEnabled()) {
     aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
   }
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3852,17 +3852,17 @@ class CGWrapGlobalMethod(CGAbstractMetho
 
     properties should be a PropertyArrays instance.
     """
     def __init__(self, descriptor, properties):
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'),
                 Argument(descriptor.nativeType + '*', 'aObject'),
                 Argument('nsWrapperCache*', 'aCache'),
-                Argument('JS::CompartmentOptions&', 'aOptions'),
+                Argument('JS::RealmOptions&', 'aOptions'),
                 Argument('JSPrincipals*', 'aPrincipal'),
                 Argument('bool', 'aInitStandardClasses'),
                 Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
         self.descriptor = descriptor
         self.properties = properties
 
     def definition_body(self):
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -55,18 +55,18 @@ namespace dom {
  *
  * Note: We'd prefer this function to live in BindingUtils.h, but we need to
  * call it in this header, and BindingUtils.h includes us (i.e. we'd have a
  * circular dependency between headers if it lived there).
  */
 inline bool
 IsSecureContextOrObjectIsFromSecureContext(JSContext* aCx, JSObject* aObj)
 {
-  return JS::CompartmentCreationOptionsRef(js::GetContextCompartment(aCx)).secureContext() ||
-         JS::CompartmentCreationOptionsRef(js::GetObjectCompartment(aObj)).secureContext();
+  return JS::RealmCreationOptionsRef(js::GetContextCompartment(aCx)).secureContext() ||
+         JS::RealmCreationOptionsRef(js::GetObjectCompartment(aObj)).secureContext();
 }
 
 typedef bool
 (* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                        JS::MutableHandle<JS::PropertyDescriptor> desc);
 
 typedef bool
--- a/dom/bindings/SimpleGlobalObject.cpp
+++ b/dom/bindings/SimpleGlobalObject.cpp
@@ -103,17 +103,17 @@ SimpleGlobalObject::Create(GlobalType gl
   // the lifetime of the AutoJSAPI.
   JS::Rooted<JSObject*> global(RootingCx());
 
   { // Scope to ensure the AutoJSAPI destructor runs before we end up returning
     AutoJSAPI jsapi;
     jsapi.Init();
     JSContext* cx = jsapi.cx();
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     options.creationOptions()
            .setInvisibleToDebugger(true)
            // Put our SimpleGlobalObjects in the system zone, so we won't create
            // lots of zones for what are probably very short-lived
            // compartments.  This should help them be GCed quicker and take up
            // less memory before they're GCed.
            .setSystemZone();
 
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1900,43 +1900,47 @@ CanvasRenderingContext2D::TryBasicTarget
 
   aOutProvider = new PersistentBufferProviderBasic(aOutDT);
   return true;
 }
 
 NS_IMETHODIMP
 CanvasRenderingContext2D::SetDimensions(int32_t aWidth, int32_t aHeight)
 {
-  ClearTarget();
-
   // Zero sized surfaces can cause problems.
   mZero = false;
   if (aHeight == 0) {
     aHeight = 1;
     mZero = true;
   }
   if (aWidth == 0) {
     aWidth = 1;
     mZero = true;
   }
-  mWidth = aWidth;
-  mHeight = aHeight;
+
+  ClearTarget(aWidth, aHeight);
 
   return NS_OK;
 }
 
 void
-CanvasRenderingContext2D::ClearTarget()
+CanvasRenderingContext2D::ClearTarget(int32_t aWidth, int32_t aHeight)
 {
   Reset();
 
   mResetLayer = true;
 
   SetInitialState();
 
+  // Update dimensions only if new (strictly positive) values were passed.
+  if (aWidth > 0 && aHeight > 0) {
+    mWidth = aWidth;
+    mHeight = aHeight;
+  }
+
   if (!mCanvasElement || !mCanvasElement->IsInComposedDoc()) {
     return;
   }
 
   // For vertical writing-mode, unless text-orientation is sideways,
   // we'll modify the initial value of textBaseline to 'middle'.
   RefPtr<ComputedStyle> canvasStyle =
     nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr);
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -685,18 +685,21 @@ protected:
 
   /**
    * Cf. OnStableState.
    */
   void ScheduleStableStateCallback();
 
   /**
    * Disposes an old target and prepares to lazily create a new target.
+   *
+   * Parameters are the new dimensions to be used, or if either is negative,
+   * existing dimensions will be left unchanged.
    */
-  void ClearTarget();
+  void ClearTarget(int32_t aWidth = -1, int32_t aHeight = -1);
 
   /*
    * Returns the target to the buffer provider. i.e. this will queue a frame for
    * rendering.
    */
   void ReturnTarget(bool aForceReset = false);
 
   /**
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1141,20 +1141,20 @@ WebGLTexture::TexStorage(const char* fun
         const auto lastLevel = uint32_t(levels - 1);
         if (lastLevel > 31)
             return false;
 
         const auto lastLevelWidth = uint32_t(width) >> lastLevel;
         const auto lastLevelHeight = uint32_t(height) >> lastLevel;
 
         // If these are all zero, then some earlier level was the final 1x1(x1) level.
-        bool ok = lastLevelWidth && lastLevelHeight;
+        bool ok = lastLevelWidth || lastLevelHeight;
         if (target == LOCAL_GL_TEXTURE_3D) {
             const auto lastLevelDepth = uint32_t(depth) >> lastLevel;
-            ok &= bool(lastLevelDepth);
+            ok |= bool(lastLevelDepth);
         }
         return ok;
     }();
     if (!levelsOk) {
         mContext->ErrorInvalidOperation("%s: Too many levels requested for the given"
                                         " dimensions. (levels: %u, width: %u, height: %u,"
                                         " depth: %u)",
                                         funcName, levels, width, height, depth);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -317,16 +317,21 @@ parent:
     nested(inside_cpow) async SetPluginFocused(bool aFocused);
 
     /**
      * Set IME candidate window by windowless plugin if plugin has focus.
      */
     async SetCandidateWindowForPlugin(CandidateWindowPosition aPosition);
 
     /**
+     * Enable or Disable IME by windowless plugin if plugin has focus.
+     */
+    async EnableIMEForPlugin(bool aEnable);
+
+    /**
      * Notifies the parent process of native key event data received in a
      * plugin process directly.
      *
      * aKeyEventData    The native key event data.  The actual type copied into
      *                  NativeEventData depending on the caller.  Please check
      *                  PluginInstanceChild.
      */
     nested(inside_cpow) async OnWindowedPluginKeyEvent(NativeEventData aKeyEventData);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3528,17 +3528,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(TabChildGlobal, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(TabChildGlobal, DOMEventTargetHelper)
 
 bool
 TabChildGlobal::WrapGlobalObject(JSContext* aCx,
-                                 JS::CompartmentOptions& aOptions,
+                                 JS::RealmOptions& aOptions,
                                  JS::MutableHandle<JSObject*> aReflector)
 {
   bool ok = ContentFrameMessageManagerBinding::Wrap(aCx, this, this, aOptions,
                                                     nsJSPrincipals::get(mTabChild->GetPrincipal()),
                                                     true, aReflector);
   if (ok) {
     // Since we can't rewrap we have to preserve the global's wrapper here.
     PreserveWrapper(ToSupports(this));
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -94,17 +94,17 @@ public:
   void MarkForCC();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override
   {
     MOZ_CRASH("We should never get here!");
   }
   bool WrapGlobalObject(JSContext* aCx,
-                        JS::CompartmentOptions& aOptions,
+                        JS::RealmOptions& aOptions,
                         JS::MutableHandle<JSObject*> aReflector);
 
   virtual already_AddRefed<nsPIDOMWindowOuter> GetContent(ErrorResult& aError) override;
   virtual already_AddRefed<nsIDocShell> GetDocShell(ErrorResult& aError) override;
   virtual already_AddRefed<nsIEventTarget> GetTabEventTarget() override;
 
   NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
   NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
@@ -158,17 +158,17 @@ protected:
 
 public:
   TabChildBase();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TabChildBase)
 
   virtual bool WrapGlobalObject(JSContext* aCx,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 JS::MutableHandle<JSObject*> aReflector) override
   {
     return mTabChildGlobal->WrapGlobalObject(aCx, aOptions, aReflector);
   }
 
   virtual nsIWebNavigation* WebNavigation() const = 0;
   virtual PuppetWidget* WebWidget() = 0;
   nsIPrincipal* GetPrincipal() { return mPrincipal; }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2423,16 +2423,27 @@ TabParent::RecvSetCandidateWindowForPlug
   if (!widget) {
     return IPC_OK();
   }
 
   widget->SetCandidateWindowForPlugin(aPosition);
   return IPC_OK();
 }
 
+ mozilla::ipc::IPCResult
+TabParent::RecvEnableIMEForPlugin(const bool& aEnable)
+{
+  nsCOMPtr<nsIWidget> widget = GetWidget();
+  if (!widget) {
+    return IPC_OK();
+  }
+  widget->EnableIMEForPlugin(aEnable);
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult
 TabParent::RecvDefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return IPC_OK();
   }
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -229,16 +229,18 @@ public:
                      const int32_t& aPanelX,
                      const int32_t& aPanelY,
                      nsString* aCommitted) override;
 
   virtual mozilla::ipc::IPCResult RecvSetPluginFocused(const bool& aFocused) override;
 
   virtual mozilla::ipc::IPCResult RecvSetCandidateWindowForPlugin(
     const widget::CandidateWindowPosition& aPosition) override;
+  virtual mozilla::ipc::IPCResult
+  RecvEnableIMEForPlugin(const bool& aEnable) override;
 
   virtual mozilla::ipc::IPCResult
   RecvDefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult RecvGetInputContext(
     widget::IMEState::Enabled* aIMEEnabled,
     widget::IMEState::Open* aIMEOpen) override;
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -894,16 +894,31 @@ nsPluginInstanceOwner::RequestCommitOrCa
   if (aCommitted) {
     widget->NotifyIME(widget::REQUEST_TO_COMMIT_COMPOSITION);
   } else {
     widget->NotifyIME(widget::REQUEST_TO_CANCEL_COMPOSITION);
   }
   return true;
 }
 
+bool
+nsPluginInstanceOwner::EnableIME(bool aEnable)
+{
+  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
+  if (!widget) {
+    widget = GetRootWidgetForPluginFrame(mPluginFrame);
+    if (NS_WARN_IF(!widget)) {
+      return false;
+    }
+  }
+
+  widget->EnableIMEForPlugin(aEnable);
+  return true;
+}
+
 #endif // #ifdef XP_WIN
 
 void
 nsPluginInstanceOwner::HandledWindowedPluginKeyEvent(
                          const NativeEventData& aKeyEventData,
                          bool aIsConsumed)
 {
   if (NS_WARN_IF(!mInstance)) {
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -257,16 +257,17 @@ public:
 
   already_AddRefed<nsIURI> GetBaseURI() const;
 
   bool GetCompositionString(uint32_t aIndex, nsTArray<uint8_t>* aString,
                             int32_t* aLength);
   bool SetCandidateWindow(
            const mozilla::widget::CandidateWindowPosition& aPosition);
   bool RequestCommitOrCancel(bool aCommitted);
+  bool EnableIME(bool aEnable);
 
   // See nsIKeyEventInPluginCallback
   virtual void HandledWindowedPluginKeyEvent(
                  const mozilla::NativeEventData& aKeyEventData,
                  bool aIsConsumed) override;
 
   /**
    * OnWindowedPluginKeyEvent() is called when the plugin process receives
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -259,16 +259,21 @@ parent:
   sync GetCompositionString(uint32_t aType)
                             returns (uint8_t[] aDist, int32_t aLength);
   // Set candidate window position.
   //
   // @param aPosition  position information of candidate window
   async SetCandidateWindow(CandidateWindowPosition aPosition);
   async RequestCommitOrCancel(bool aCommitted);
 
+  // Control IME can enable or disable
+  //
+  // @param aEanble  whether IME is enabled or disabled
+  async EnableIME(bool aEnable);
+
   // Notifies the parent process of a plugin instance receiving key event
   // directly.
   //
   // @param aKeyEventData       The native key event which will be sent to
   //                            plugin from native event handler.
   async OnWindowedPluginKeyEvent(NativeEventData aKeyEventData);
 
 both:
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -70,30 +70,25 @@ typedef BOOL (WINAPI *User32TrackPopupMe
                                             int y,
                                             int nReserved,
                                             HWND hWnd,
                                             CONST RECT *prcRect);
 static WindowsDllInterceptor sUser32Intercept;
 static HWND sWinlessPopupSurrogateHWND = nullptr;
 static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr;
 
-typedef HIMC (WINAPI *Imm32ImmGetContext)(HWND hWND);
-typedef LONG (WINAPI *Imm32ImmGetCompositionString)(HIMC hIMC,
-                                                    DWORD dwIndex,
-                                                    LPVOID lpBuf,
-                                                    DWORD dwBufLen);
-typedef BOOL (WINAPI *Imm32ImmSetCandidateWindow)(HIMC hIMC,
-                                                  LPCANDIDATEFORM lpCandidate);
-typedef BOOL (WINAPI *Imm32ImmNotifyIME)(HIMC hIMC, DWORD dwAction,
-                                        DWORD dwIndex, DWORD dwValue);
 static WindowsDllInterceptor sImm32Intercept;
-static Imm32ImmGetContext sImm32ImmGetContextStub = nullptr;
-static Imm32ImmGetCompositionString sImm32ImmGetCompositionStringStub = nullptr;
-static Imm32ImmSetCandidateWindow sImm32ImmSetCandidateWindowStub = nullptr;
-static Imm32ImmNotifyIME sImm32ImmNotifyIME = nullptr;
+static decltype(ImmGetContext)* sImm32ImmGetContextStub = nullptr;
+static decltype(ImmGetCompositionStringW)* sImm32ImmGetCompositionStringStub =
+                                             nullptr;
+static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub =
+                                          nullptr;
+static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr;
+static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub =
+                                          nullptr;
 static PluginInstanceChild* sCurrentPluginInstance = nullptr;
 static const HIMC sHookIMC = (const HIMC)0xefefefef;
 
 using mozilla::gfx::SharedDIB;
 
 // Flash WM_USER message delay time for PostDelayedTask. Borrowed
 // from Chromium's web plugin delegate src. See 'flash msg throttling
 // helpers' section for details.
@@ -175,16 +170,17 @@ PluginInstanceChild::PluginInstanceChild
     , mSurfaceType(gfxSurfaceType::Max)
     , mPendingPluginCall(false)
     , mDoAlphaExtraction(false)
     , mHasPainted(false)
     , mSurfaceDifferenceRect(0,0,0,0)
     , mDestroyed(false)
 #ifdef XP_WIN
     , mLastKeyEventConsumed(false)
+    , mLastEnableIMEState(true)
 #endif // #ifdef XP_WIN
     , mStackDepth(0)
 {
     memset(&mWindow, 0, sizeof(mWindow));
     mWindow.type = NPWindowTypeWindow;
     mData.ndata = (void*) this;
     mData.pdata = nullptr;
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
@@ -2100,16 +2096,40 @@ PluginInstanceChild::ImmNotifyIME(HIMC a
         (aIndex != CPS_COMPLETE && aIndex != CPS_CANCEL)) {
         return FALSE;
     }
 
     sCurrentPluginInstance->SendRequestCommitOrCancel(aAction == CPS_COMPLETE);
     return TRUE;
 }
 
+// static
+BOOL
+PluginInstanceChild::ImmAssociateContextExProc(HWND hWND, HIMC hImc,
+                                               DWORD dwFlags)
+{
+    PluginInstanceChild* self = sCurrentPluginInstance;
+    if (!self) {
+        // If ImmAssociateContextEx calls unexpected window message,
+        // we can use child instance object from window property if available.
+        self = reinterpret_cast<PluginInstanceChild*>(
+                   GetProp(hWND, kFlashThrottleProperty));
+        NS_WARNING_ASSERTION(self, "Cannot find PluginInstanceChild");
+    }
+
+    // HIMC is always nullptr on Flash's windowless
+    if (!hImc && self) {
+        // Store the last IME state since Flash may call ImmAssociateContextEx
+        // before taking focus.
+        self->mLastEnableIMEState = !!(dwFlags & IACE_DEFAULT);
+        self->SendEnableIME(self->mLastEnableIMEState);
+    }
+    return sImm32ImmAssociateContextExStub(hWND, hImc, dwFlags);
+}
+
 void
 PluginInstanceChild::InitImm32Hook()
 {
     if (!(GetQuirks() & QUIRK_WINLESS_HOOK_IME)) {
         return;
     }
 
     if (sImm32ImmGetContextStub) {
@@ -2133,16 +2153,20 @@ PluginInstanceChild::InitImm32Hook()
     sImm32Intercept.AddHook(
         "ImmSetCandidateWindow",
         reinterpret_cast<intptr_t>(ImmSetCandidateWindowProc),
         (void**)&sImm32ImmSetCandidateWindowStub);
     sImm32Intercept.AddHook(
         "ImmNotifyIME",
         reinterpret_cast<intptr_t>(ImmNotifyIME),
         (void**)&sImm32ImmNotifyIME);
+    sImm32Intercept.AddHook(
+        "ImmAssociateContextEx",
+        reinterpret_cast<intptr_t>(ImmAssociateContextExProc),
+        (void**)&sImm32ImmAssociateContextExStub);
 }
 
 void
 PluginInstanceChild::DestroyWinlessPopupSurrogate()
 {
     if (mWinlessPopupSurrogateHWND)
         DestroyWindow(mWinlessPopupSurrogateHWND);
     mWinlessPopupSurrogateHWND = nullptr;
@@ -2171,31 +2195,53 @@ PluginInstanceChild::WinlessHandleEvent(
       // A little trick scrounged from chromium's code - set the focus
       // to our surrogate parent so keyboard nav events go to the menu.
       focusHwnd = SetFocus(mWinlessPopupSurrogateHWND);
     }
 
     AutoRestore<PluginInstanceChild *> pluginInstance(sCurrentPluginInstance);
     if (event.event == WM_IME_STARTCOMPOSITION ||
         event.event == WM_IME_COMPOSITION ||
+        event.event == WM_LBUTTONDOWN ||
         event.event == WM_KILLFOCUS) {
       sCurrentPluginInstance = this;
     }
 
     MessageLoop* loop = MessageLoop::current();
     AutoRestore<bool> modalLoop(loop->os_modal_loop());
 
     handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
 
     sWinlessPopupSurrogateHWND = nullptr;
 
     if (IsWindow(focusHwnd)) {
       SetFocus(focusHwnd);
     }
 
+    // This is hack of Flash's behaviour.
+    //
+    // When moving focus from chrome to plugin by mouse click, Gecko sends
+    // mouse message (such as WM_LBUTTONDOWN etc) at first, then sends
+    // WM_SETFOCUS. But Flash will call ImmAssociateContextEx on WM_LBUTTONDOWN
+    // even if it doesn't receive WM_SETFOCUS.
+    //
+    // In this situation, after sending mouse message, content process will be
+    // activated and set input context with PLUGIN.  So after activating
+    // content process, we have to set current IME state again.
+
+    if (event.event == WM_SETFOCUS) {
+        // When focus is changed from chrome process to plugin process,
+        // Flash may call ImmAssociateContextEx before receiving WM_SETFOCUS.
+        SendEnableIME(mLastEnableIMEState);
+    } else if (event.event == WM_KILLFOCUS) {
+        // Flash always calls ImmAssociateContextEx by taking focus.
+        // Although this flag doesn't have to be reset, I add it for safety.
+        mLastEnableIMEState = true;
+    }
+
     return handled;
 }
 
 /* flash msg throttling helpers */
 
 // Flash has the unfortunate habit of flooding dispatch loops with custom
 // windowing events they use for timing. We throttle these by dropping the
 // delivery priority below any other event, including pending ipc io
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -336,16 +336,18 @@ private:
 
     static HIMC WINAPI ImmGetContextProc(HWND aWND);
     static LONG WINAPI ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
                                                    LPVOID aBuf, DWORD aLen);
     static BOOL WINAPI ImmSetCandidateWindowProc(HIMC hIMC,
                                                  LPCANDIDATEFORM plCandidate);
     static BOOL WINAPI ImmNotifyIME(HIMC aIMC, DWORD aAction, DWORD aIndex,
                                     DWORD aValue);
+    static BOOL WINAPI ImmAssociateContextExProc(HWND hWnd, HIMC aIMC,
+                                                 DWORD dwFlags);
 
     class FlashThrottleMsg : public CancelableRunnable
     {
       public:
         FlashThrottleMsg(PluginInstanceChild* aInstance, HWND aWnd, UINT aMsg,
                          WPARAM aWParam, LPARAM aLParam, bool isWindowed)
           : CancelableRunnable("FlashThrottleMsg"),
           mInstance(aInstance),
@@ -641,16 +643,20 @@ private:
     bool mDestroyed;
 
 #ifdef XP_WIN
     // WM_*CHAR messages are never consumed by chrome process's widget.
     // So, if preceding keydown or keyup event is consumed by reserved
     // shortcut key in the chrome process, we shouldn't send the following
     // WM_*CHAR messages to the plugin.
     bool mLastKeyEventConsumed;
+
+    // Store the last IME state by ImmAssociateContextEx.  This will reset by
+    // WM_KILLFOCUS;
+    bool mLastEnableIMEState;
 #endif // #ifdef XP_WIN
 
     // While IME in the process has composition, this is set to true.
     // Otherwise, false.
     static bool sIsIMEComposing;
 
     // A counter is incremented by AutoStackHelper to indicate that there is an
     // active plugin call which should be preventing shutdown.
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -2292,16 +2292,30 @@ PluginInstanceParent::RecvRequestCommitO
     nsPluginInstanceOwner* owner = GetOwner();
     if (owner) {
         owner->RequestCommitOrCancel(aCommitted);
     }
 #endif
     return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+PluginInstanceParent::RecvEnableIME(const bool& aEnable)
+{
+#if defined(OS_WIN)
+    nsPluginInstanceOwner* owner = GetOwner();
+    if (owner) {
+        owner->EnableIME(aEnable);
+    }
+#else
+    MOZ_CRASH("Not reachable");
+#endif
+    return IPC_OK();
+}
+
 nsresult
 PluginInstanceParent::HandledWindowedPluginKeyEvent(
                         const NativeEventData& aKeyEventData,
                         bool aIsConsumed)
 {
     if (NS_WARN_IF(!SendHandledWindowedPluginKeyEvent(aKeyEventData,
                                                       aIsConsumed))) {
         return NS_ERROR_FAILURE;
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -315,16 +315,17 @@ public:
     RecvGetCompositionString(const uint32_t& aIndex,
                              nsTArray<uint8_t>* aBuffer,
                              int32_t* aLength) override;
     virtual mozilla::ipc::IPCResult
     RecvSetCandidateWindow(
         const mozilla::widget::CandidateWindowPosition& aPosition) override;
     virtual mozilla::ipc::IPCResult
     RecvRequestCommitOrCancel(const bool& aCommitted) override;
+    virtual mozilla::ipc::IPCResult RecvEnableIME(const bool& aEnable) override;
 
     // for reserved shortcut key handling with windowed plugin on Windows
     nsresult HandledWindowedPluginKeyEvent(
       const mozilla::NativeEventData& aKeyEventData,
       bool aIsConsumed);
     virtual mozilla::ipc::IPCResult
     RecvOnWindowedPluginKeyEvent(
       const mozilla::NativeEventData& aKeyEventData) override;
--- a/dom/workers/JSSettings.h
+++ b/dom/workers/JSSettings.h
@@ -53,21 +53,21 @@ struct JSSettings
 
   // There are several settings that we know we need so it makes sense to
   // preallocate here.
   typedef JSGCSetting JSGCSettingsArray[kGCSettingsArraySize];
 
   // Settings that change based on chrome/content context.
   struct JSContentChromeSettings
   {
-    JS::CompartmentOptions compartmentOptions;
+    JS::RealmOptions realmOptions;
     int32_t maxScriptRuntime;
 
     JSContentChromeSettings()
-    : compartmentOptions(), maxScriptRuntime(0)
+    : realmOptions(), maxScriptRuntime(0)
     { }
   };
 
   JSContentChromeSettings chrome;
   JSContentChromeSettings content;
   JSGCSettingsArray gcSettings;
   JS::ContextOptions contextOptions;
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2712,23 +2712,23 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
       // secure context state from attaching to them.
       mIsSecureContext = mLoadInfo.mWindow->IsSecureContext();
     } else {
       MOZ_ASSERT_UNREACHABLE("non-chrome worker that is not a service worker "
                              "that has no parent and no associated window");
     }
 
     if (mIsSecureContext) {
-      mJSSettings.chrome.compartmentOptions
+      mJSSettings.chrome.realmOptions
                  .creationOptions().setSecureContext(true);
-      mJSSettings.chrome.compartmentOptions
+      mJSSettings.chrome.realmOptions
                  .creationOptions().setClampAndJitterTime(false);
-      mJSSettings.content.compartmentOptions
+      mJSSettings.content.realmOptions
                  .creationOptions().setSecureContext(true);
-      mJSSettings.content.compartmentOptions
+      mJSSettings.content.realmOptions
                  .creationOptions().setClampAndJitterTime(false);
     }
 
     mIsInAutomation = xpc::IsInAutomation();
 
     // Our parent can get suspended after it initiates the async creation
     // of a new worker thread.  In this case suspend the new worker as well.
     if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -666,21 +666,21 @@ public:
   void
   CopyJSSettings(workerinternals::JSSettings& aSettings)
   {
     mozilla::MutexAutoLock lock(mMutex);
     aSettings = mJSSettings;
   }
 
   void
-  CopyJSCompartmentOptions(JS::CompartmentOptions& aOptions)
+  CopyJSRealmOptions(JS::RealmOptions& aOptions)
   {
     mozilla::MutexAutoLock lock(mMutex);
-    aOptions = IsChromeWorker() ? mJSSettings.chrome.compartmentOptions
-                                : mJSSettings.content.compartmentOptions;
+    aOptions = IsChromeWorker() ? mJSSettings.chrome.realmOptions
+                                : mJSSettings.content.realmOptions;
   }
 
   // The ability to be a chrome worker is orthogonal to the type of
   // worker [Dedicated|Shared|Service].
   bool
   IsChromeWorker() const
   {
     return mIsChromeWorker;
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -589,36 +589,36 @@ DedicatedWorkerGlobalScope::DedicatedWor
 
 bool
 DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
                                              JS::MutableHandle<JSObject*> aReflector)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker());
 
-  JS::CompartmentOptions options;
-  mWorkerPrivate->CopyJSCompartmentOptions(options);
+  JS::RealmOptions options;
+  mWorkerPrivate->CopyJSRealmOptions(options);
 
   const bool usesSystemPrincipal = mWorkerPrivate->UsesSystemPrincipal();
 
   // Note that xpc::ShouldDiscardSystemSource() and
   // xpc::ExtraWarningsForSystemJS() read prefs that are cached on the main
   // thread. This is benignly racey.
   const bool discardSource = usesSystemPrincipal &&
                              xpc::ShouldDiscardSystemSource();
   const bool extraWarnings = usesSystemPrincipal &&
                              xpc::ExtraWarningsForSystemJS();
 
-  JS::CompartmentBehaviors& behaviors = options.behaviors();
+  JS::RealmBehaviors& behaviors = options.behaviors();
   behaviors.setDiscardSource(discardSource)
            .extraWarningsOverride().set(extraWarnings);
 
   const bool sharedMemoryEnabled = xpc::SharedMemoryEnabled();
 
-  JS::CompartmentCreationOptions& creationOptions = options.creationOptions();
+  JS::RealmCreationOptions& creationOptions = options.creationOptions();
   creationOptions.setSharedMemoryAndAtomicsEnabled(sharedMemoryEnabled);
 
   return DedicatedWorkerGlobalScopeBinding::Wrap(aCx, this, this,
                                                  options,
                                                  GetWorkerPrincipal(),
                                                  true, aReflector);
 }
 
@@ -647,18 +647,18 @@ SharedWorkerGlobalScope::SharedWorkerGlo
 
 bool
 SharedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
                                           JS::MutableHandle<JSObject*> aReflector)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(mWorkerPrivate->IsSharedWorker());
 
-  JS::CompartmentOptions options;
-  mWorkerPrivate->CopyJSCompartmentOptions(options);
+  JS::RealmOptions options;
+  mWorkerPrivate->CopyJSRealmOptions(options);
 
   return SharedWorkerGlobalScopeBinding::Wrap(aCx, this, this, options,
                                               GetWorkerPrincipal(),
                                               true, aReflector);
 }
 
 void
 SharedWorkerGlobalScope::Close()
@@ -693,18 +693,18 @@ ServiceWorkerGlobalScope::~ServiceWorker
 
 bool
 ServiceWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
                                            JS::MutableHandle<JSObject*> aReflector)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
 
-  JS::CompartmentOptions options;
-  mWorkerPrivate->CopyJSCompartmentOptions(options);
+  JS::RealmOptions options;
+  mWorkerPrivate->CopyJSRealmOptions(options);
 
   return ServiceWorkerGlobalScopeBinding::Wrap(aCx, this, this, options,
                                                GetWorkerPrincipal(),
                                                true, aReflector);
 }
 
 already_AddRefed<Clients>
 ServiceWorkerGlobalScope::GetClients()
@@ -949,18 +949,18 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 bool
 WorkerDebuggerGlobalScope::WrapGlobalObject(JSContext* aCx,
                                             JS::MutableHandle<JSObject*> aReflector)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
-  JS::CompartmentOptions options;
-  mWorkerPrivate->CopyJSCompartmentOptions(options);
+  JS::RealmOptions options;
+  mWorkerPrivate->CopyJSRealmOptions(options);
 
   return WorkerDebuggerGlobalScopeBinding::Wrap(aCx, this, this, options,
                                                 GetWorkerPrincipal(), true,
                                                 aReflector);
 }
 
 void
 WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
--- a/dom/worklet/AudioWorkletGlobalScope.cpp
+++ b/dom/worklet/AudioWorkletGlobalScope.cpp
@@ -17,17 +17,17 @@ AudioWorkletGlobalScope::AudioWorkletGlo
   , mCurrentTime(0)
   , mSampleRate(0.0)
 {}
 
 bool
 AudioWorkletGlobalScope::WrapGlobalObject(JSContext* aCx,
                                           JS::MutableHandle<JSObject*> aReflector)
 {
-  JS::CompartmentOptions options;
+  JS::RealmOptions options;
   return AudioWorkletGlobalScopeBinding::Wrap(aCx, this, this,
                                               options,
                                               WorkletPrincipal::GetWorkletPrincipal(),
                                               true, aReflector);
 }
 
 void
 AudioWorkletGlobalScope::RegisterProcessor(const nsAString& aType,
--- a/dom/worklet/PaintWorkletGlobalScope.cpp
+++ b/dom/worklet/PaintWorkletGlobalScope.cpp
@@ -13,17 +13,17 @@ namespace mozilla {
 namespace dom {
 
 PaintWorkletGlobalScope::PaintWorkletGlobalScope() = default;
 
 bool
 PaintWorkletGlobalScope::WrapGlobalObject(JSContext* aCx,
                                           JS::MutableHandle<JSObject*> aReflector)
 {
-  JS::CompartmentOptions options;
+  JS::RealmOptions options;
   return PaintWorkletGlobalScopeBinding::Wrap(aCx, this, this,
                                               options,
                                               WorkletPrincipal::GetWorkletPrincipal(),
                                               true, aReflector);
 }
 
 void
 PaintWorkletGlobalScope::RegisterPaint(const nsAString& aType,
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -188,21 +188,21 @@ struct MemStream {
   char *mData;
   size_t mLength;
   size_t mCapacity;
   void Resize(size_t aSize) {
     mLength = aSize;
     if (mLength > mCapacity) {
       mCapacity = mCapacity * 2;
       // check if the doubled capacity is enough
-      // otherwise use mLength
+      // otherwise use double mLength
       if (mLength > mCapacity) {
-        mCapacity = mLength;
+        mCapacity = mLength * 2;
       }
-      mData = (char*)realloc(mData, mCapacity * 2);
+      mData = (char*)realloc(mData, mCapacity);
     }
   }
 
   void write(const char* aData, size_t aSize) {
     Resize(mLength + aSize);
     memcpy(mData + mLength - aSize, aData, aSize);
   }
 
--- a/gfx/config/gfxVars.h
+++ b/gfx/config/gfxVars.h
@@ -29,16 +29,17 @@ class gfxVarReceiver;
   _(TileSize,                   IntSize,          IntSize(-1, -1))      \
   _(UseXRender,                 bool,             false)                \
   _(OffscreenFormat,            gfxImageFormat,   mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
   _(RequiresAcceleratedGLContextForCompositorOGL, bool, false)          \
   _(CanUseHardwareVideoDecoding, bool,            false)                \
   _(PDMWMFDisableD3D11Dlls,     nsCString,        nsCString())          \
   _(PDMWMFDisableD3D9Dlls,      nsCString,        nsCString())          \
   _(DXInterop2Blocked,          bool,             false)                \
+  _(DXNV12Blocked,              bool,             false)                \
   _(UseWebRender,               bool,             false)                \
   _(UseWebRenderANGLE,          bool,             false)                \
   _(UseWebRenderDCompWin,       bool,             false)                \
   _(UseWebRenderProgramBinary,  bool,             false)                \
   _(WebRenderDebugFlags,        int32_t,          0)                    \
   _(ScreenDepth,                int32_t,          0)                    \
   _(GREDirectory,               nsString,         nsString())           \
   _(UseOMTP,                    bool,             false)                \
--- a/gfx/thebes/D3D11Checks.cpp
+++ b/gfx/thebes/D3D11Checks.cpp
@@ -5,16 +5,17 @@
 
 #include "D3D11Checks.h"
 #include "DXVA2Manager.h"
 #include "gfxConfig.h"
 #include "GfxDriverInfo.h"
 #include "gfxPrefs.h"
 #include "gfxWindowsPlatform.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "nsIGfxInfo.h"
 #include <dxgi.h>
 #include <dxgi1_2.h>
 #include <d3d10_1.h>
 #include <d3d11.h>
 
@@ -408,16 +409,20 @@ D3D11Checks::DoesRemotePresentWork(IDXGI
   RefPtr<IDXGIAdapter2> check;
   HRESULT hr = adapter->QueryInterface(__uuidof(IDXGIAdapter2), getter_AddRefs(check));
   return SUCCEEDED(hr) && check;
 }
 
 /* static */ bool
 D3D11Checks::DoesNV12Work(ID3D11Device* device)
 {
+  if(gfxVars::DXNV12Blocked()) {
+    return false;
+  }
+
   DXGI_ADAPTER_DESC desc;
   PodZero(&desc);
   if (!GetDxgiDesc(device, &desc)) {
     // Failed to retrieve device information, assume it doesn't work
     return false;
   }
 
   HRESULT hr;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -848,16 +848,17 @@ gfxPlatform::Init()
     }
 #endif
 
     InitNullMetadata();
     InitOpenGLConfig();
 
     if (XRE_IsParentProcess()) {
       gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked());
+      gfxVars::SetDXNV12Blocked(IsDXNV12Blocked());
       Preferences::Unlock(FONT_VARIATIONS_PREF);
       if (!gPlatform->HasVariationFontSupport()) {
         // Ensure variation fonts are disabled and the pref is locked.
         Preferences::SetBool(FONT_VARIATIONS_PREF, false,
                              PrefValueKind::Default);
         Preferences::SetBool(FONT_VARIATIONS_PREF, false);
         Preferences::Lock(FONT_VARIATIONS_PREF);
       }
@@ -876,16 +877,29 @@ gfxPlatform::IsDXInterop2Blocked()
   int32_t status;
   if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_INTEROP2,
                                               blockId, &status))) {
     return true;
   }
   return status != nsIGfxInfo::FEATURE_STATUS_OK;
 }
 
+/* static*/ bool
+gfxPlatform::IsDXNV12Blocked()
+{
+  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+  nsCString blockId;
+  int32_t status;
+  if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_NV12,
+                                              blockId, &status))) {
+    return true;
+  }
+  return status != nsIGfxInfo::FEATURE_STATUS_OK;
+}
+
 /* static */ int32_t
 gfxPlatform::MaxTextureSize()
 {
   // Make sure we don't completely break rendering because of a typo in the
   // pref or whatnot.
   const int32_t kMinSizePref = 2048;
   return std::max(kMinSizePref, gfxPrefs::MaxTextureSizeDoNotUseDirectly());
 }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -870,16 +870,17 @@ private:
      */
     void PopulateScreenInfo();
 
     void InitCompositorAccelerationPrefs();
     void InitGPUProcessPrefs();
     void InitOMTPConfig();
 
     static bool IsDXInterop2Blocked();
+    static bool IsDXNV12Blocked();
 
     RefPtr<gfxASurface> mScreenReferenceSurface;
     nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
     nsCOMPtr<nsIObserver> mMemoryPressureObserver;
 
     // The preferred draw target backend to use for canvas
     mozilla::gfx::BackendType mPreferredCanvasBackend;
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -423,17 +423,17 @@ XPCShellEnvironment::Init()
 
     RefPtr<BackstagePass> backstagePass;
     rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
     if (NS_FAILED(rv)) {
         NS_ERROR("Failed to create backstage pass!");
         return false;
     }
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     options.creationOptions().setSystemZone();
     if (xpc::SharedMemoryEnabled())
         options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
 
     JS::Rooted<JSObject*> globalObj(cx);
     rv = xpc::InitClassesWithNewWrappedGlobal(cx,
                                               static_cast<nsIGlobalObject *>(backstagePass),
                                               principal, 0,
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -6,17 +6,16 @@
 
 #ifndef js_MemoryMetrics_h
 #define js_MemoryMetrics_h
 
 // These declarations are highly likely to change in the future. Depend on them
 // at your own risk.
 
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/PodOperations.h"
 #include "mozilla/TypeTraits.h"
 
 #include <string.h>
 
 #include "jspubtd.h"
 
 #include "js/AllocPolicy.h"
 #include "js/HashTable.h"
@@ -69,45 +68,37 @@ struct ServoSizes
         GCHeapUnused,
         GCHeapAdmin,
         GCHeapDecommitted,
         MallocHeap,
         NonHeap,
         Ignore
     };
 
-    ServoSizes()
-      : gcHeapUsed(0)
-      , gcHeapUnused(0)
-      , gcHeapAdmin(0)
-      , gcHeapDecommitted(0)
-      , mallocHeap(0)
-      , nonHeap(0)
-    {
-    }
+    ServoSizes() = default;
 
     void add(Kind kind, size_t n) {
         switch (kind) {
             case GCHeapUsed:        gcHeapUsed        += n; break;
             case GCHeapUnused:      gcHeapUnused      += n; break;
             case GCHeapAdmin:       gcHeapAdmin       += n; break;
             case GCHeapDecommitted: gcHeapDecommitted += n; break;
             case MallocHeap:        mallocHeap        += n; break;
             case NonHeap:           nonHeap           += n; break;
             case Ignore:            /* do nothing */        break;
             default:                MOZ_CRASH("bad ServoSizes kind");
         }
     }
 
-    size_t gcHeapUsed;
-    size_t gcHeapUnused;
-    size_t gcHeapAdmin;
-    size_t gcHeapDecommitted;
-    size_t mallocHeap;
-    size_t nonHeap;
+    size_t gcHeapUsed = 0;
+    size_t gcHeapUnused = 0;
+    size_t gcHeapAdmin = 0;
+    size_t gcHeapDecommitted = 0;
+    size_t mallocHeap = 0;
+    size_t nonHeap = 0;
 };
 
 } // namespace JS
 
 namespace js {
 
 /**
  * In memory reporting, we have concept of "sundries", line items which are too
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -846,64 +846,61 @@ class RootingContext
     }
 
     friend JSCompartment* js::GetContextCompartment(const JSContext* cx);
     friend JS::Zone* js::GetContextZone(const JSContext* cx);
 };
 
 class JS_PUBLIC_API(AutoGCRooter)
 {
+  protected:
+    enum class Tag : uint8_t {
+        Array,          /* js::AutoArrayRooter */
+        ValueArray,     /* js::AutoValueArray */
+        Parser,         /* js::frontend::Parser */
+#if defined(JS_BUILD_BINAST)
+        BinParser,      /* js::frontend::BinSource */
+#endif // defined(JS_BUILD_BINAST)
+        WrapperVector,  /* js::AutoWrapperVector */
+        Wrapper,        /* js::AutoWrapperRooter */
+        Custom          /* js::CustomAutoRooter */
+  };
+
   public:
-    AutoGCRooter(JSContext* cx, ptrdiff_t tag)
+    AutoGCRooter(JSContext* cx, Tag tag)
       : AutoGCRooter(JS::RootingContext::get(cx), tag)
     {}
-    AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag)
+    AutoGCRooter(JS::RootingContext* cx, Tag tag)
       : down(cx->autoGCRooters_),
-        tag_(tag),
-        stackTop(&cx->autoGCRooters_)
+        stackTop(&cx->autoGCRooters_),
+        tag_(tag)
     {
         MOZ_ASSERT(this != *stackTop);
         *stackTop = this;
     }
 
     ~AutoGCRooter() {
         MOZ_ASSERT(this == *stackTop);
         *stackTop = down;
     }
 
     /* Implemented in gc/RootMarking.cpp. */
     inline void trace(JSTracer* trc);
     static void traceAll(JSContext* cx, JSTracer* trc);
     static void traceAllWrappers(JSContext* cx, JSTracer* trc);
 
-  protected:
-    AutoGCRooter * const down;
+  private:
+    AutoGCRooter* const down;
+    AutoGCRooter** const stackTop;
 
     /*
-     * Discriminates actual subclass of this being used.  If non-negative, the
-     * subclass roots an array of values of the length stored in this field.
-     * If negative, meaning is indicated by the corresponding value in the enum
-     * below.  Any other negative value indicates some deeper problem such as
-     * memory corruption.
+     * Discriminates actual subclass of this being used. The meaning is
+     * indicated by the corresponding value in the Tag enum.
      */
-    ptrdiff_t tag_;
-
-    enum {
-        VALARRAY =     -2, /* js::AutoValueArray */
-        PARSER =       -3, /* js::frontend::Parser */
-#if defined(JS_BUILD_BINAST)
-        BINPARSER =    -4, /* js::frontend::BinSource */
-#endif // defined(JS_BUILD_BINAST)
-        WRAPVECTOR =  -20, /* js::AutoWrapperVector */
-        WRAPPER =     -21, /* js::AutoWrapperRooter */
-        CUSTOM =      -26  /* js::CustomAutoRooter */
-    };
-
-  private:
-    AutoGCRooter ** const stackTop;
+    Tag tag_;
 
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter& ida) = delete;
     void operator=(AutoGCRooter& ida) = delete;
 };
 
 namespace detail {
 
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -544,17 +544,17 @@ js_delete(const T* p)
 }
 
 template<class T>
 static MOZ_ALWAYS_INLINE void
 js_delete_poison(const T* p)
 {
     if (p) {
         p->~T();
-        memset(const_cast<T*>(p), 0x3B, sizeof(T));
+        memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
         js_free(const_cast<T*>(p));
     }
 }
 
 template <class T>
 static MOZ_ALWAYS_INLINE T*
 js_pod_malloc()
 {
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -143,17 +143,17 @@ const EXTRA_CLANG_FLAGS: &'static [&'sta
 /// Types which we want to generate bindings for (and every other type they
 /// transitively use).
 const WHITELIST_TYPES: &'static [&'static str] = &[
     "JS::AutoCheckCannotGC",
     "JS::AutoIdVector",
     "JS::AutoObjectVector",
     "JS::CallArgs",
     "js::Class",
-    "JS::CompartmentOptions",
+    "JS::RealmOptions",
     "JS::ContextOptions",
     "js::DOMCallbacks",
     "js::DOMProxyShadowsResult",
     "js::ESClass",
     "JS::ForOfIterator",
     "JS::Handle",
     "JS::HandleFunction",
     "JS::HandleId",
@@ -311,17 +311,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS_DefinePropertyById",
     "JS_DefineUCProperty",
     "JS::detail::InitWithFailureDiagnostic",
     "JS_DestroyContext",
     "JS::DisableIncrementalGC",
     "js::Dump.*",
     "JS_EncodeStringToUTF8",
     "JS_EndRequest",
-    "JS_EnterCompartment",
+    "JS::EnterRealm",
     "JS_EnumerateStandardClasses",
     "JS_ErrorFromException",
     "JS_FireOnNewGlobalObject",
     "JS_free",
     "JS_GC",
     "JS_GetArrayBufferData",
     "JS_GetArrayBufferViewType",
     "JS_GetFloat32ArrayData",
@@ -348,17 +348,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS::GetWellKnownSymbol",
     "JS_GlobalObjectTraceHook",
     "JS::HideScriptedCaller",
     "JS_InitStandardClasses",
     "JS_IsArrayObject",
     "JS_IsExceptionPending",
     "JS_IsGlobalObject",
     "JS::IsCallable",
-    "JS_LeaveCompartment",
+    "JS::LeaveRealm",
     "JS_LinkConstructorAndPrototype",
     "JS_MayResolveStandardClass",
     "JS_NewArrayBuffer",
     "JS_NewArrayObject",
     "JS_NewContext",
     "JS_NewFloat32Array",
     "JS_NewFloat64Array",
     "JS_NewFunction",
--- a/js/rust/src/rust.rs
+++ b/js/rust/src/rust.rs
@@ -546,17 +546,17 @@ impl Default for jsid {
         }
     }
 }
 
 impl Default for JS::Value {
     fn default() -> JS::Value { jsval::UndefinedValue() }
 }
 
-impl Default for JS::CompartmentOptions {
+impl Default for JS::RealmOptions {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
 
 const ChunkShift: usize = 20;
 const ChunkSize: usize = 1 << ChunkShift;
 
 #[cfg(target_pointer_width = "32")]
 const ChunkLocationOffset: usize = ChunkSize - 2 * 4 - 8;
@@ -606,17 +606,17 @@ impl GCMethods for JS::Value {
     }
 }
 
 // ___________________________________________________________________________
 // Implementations for various things in jsapi.rs
 
 impl Drop for JSAutoRealm {
     fn drop(&mut self) {
-        unsafe { JS_LeaveCompartment(self.cx_, self.oldCompartment_); }
+        unsafe { JS::LeaveRealm(self.cx_, self.oldCompartment_); }
     }
 }
 
 impl JSJitMethodCallArgs {
     #[inline]
     pub fn get(&self, i: u32) -> JS::HandleValue {
         unsafe {
             if i < self._base.argc_ {
--- a/js/rust/tests/callback.rs
+++ b/js/rust/tests/callback.rs
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[macro_use]
 extern crate js;
 extern crate libc;
 
 use js::ac::AutoCompartment;
 use js::jsapi::root::JS::CallArgs;
-use js::jsapi::root::JS::CompartmentOptions;
+use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::JSContext;
 use js::jsapi::root::JS_DefineFunction;
 use js::jsapi::root::JS_EncodeStringToUTF8;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS_ReportErrorASCII;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsapi::root::JS::Value;
 use js::jsval::UndefinedValue;
@@ -23,17 +23,17 @@ use std::ffi::CStr;
 use std::ptr;
 use std::str;
 
 #[test]
 fn callback() {
     let runtime = Runtime::new(false).unwrap();
     let context = runtime.cx();
     let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
-    let c_option = CompartmentOptions::default();
+    let c_option = RealmOptions::default();
 
     unsafe {
         let global = JS_NewGlobalObject(context, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(), h_option, &c_option);
         rooted!(in(context) let global_root = global);
         let global = global_root.handle();
         let _ac = AutoCompartment::with_obj(context, global.get());
         let function = JS_DefineFunction(context, global, b"puts\0".as_ptr() as *const libc::c_char,
                                          Some(puts), 1, 0);
--- a/js/rust/tests/enumerate.rs
+++ b/js/rust/tests/enumerate.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[macro_use]
 extern crate js;
 
 use js::glue::RUST_JSID_IS_STRING;
 use js::glue::RUST_JSID_TO_STRING;
-use js::jsapi::root::JS::CompartmentOptions;
+use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::js::GetPropertyKeys;
 use js::jsapi::root::JSITER_OWNONLY;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS_StringEqualsAscii;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::IdVector;
 use js::rust::Runtime;
@@ -23,17 +23,17 @@ use std::ptr;
 fn enumerate() {
     let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                OnNewGlobalHookOption::FireOnNewGlobalHook,
-                               &CompartmentOptions::default())
+                               &RealmOptions::default())
         );
 
         rooted!(in(cx) let mut rval = UndefinedValue());
         assert!(rt.evaluate_script(global.handle(), "({ 'a': 7 })",
                                    "test", 1, rval.handle_mut()).is_ok());
         assert!(rval.is_object());
 
         rooted!(in(cx) let object = rval.to_object());
--- a/js/rust/tests/evaluate.rs
+++ b/js/rust/tests/evaluate.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[macro_use]
 extern crate js;
 
-use js::jsapi::root::JS::CompartmentOptions;
+use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
 #[test]
@@ -18,15 +18,15 @@ fn evaluate() {
     let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
 
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                OnNewGlobalHookOption::FireOnNewGlobalHook,
-                               &CompartmentOptions::default())
+                               &RealmOptions::default())
         );
         rooted!(in(cx) let mut rval = UndefinedValue());
         assert!(rt.evaluate_script(global.handle(), "1 + 1",
                                    "test", 1, rval.handle_mut()).is_ok());
     }
 }
--- a/js/rust/tests/panic.rs
+++ b/js/rust/tests/panic.rs
@@ -13,17 +13,17 @@ use std::ptr;
 use std::str;
 
 #[test]
 #[should_panic]
 fn panic() {
     let runtime = Runtime::new(false).unwrap();
     let context = runtime.cx();
     let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
-    let c_option = JS::CompartmentOptions::default();
+    let c_option = JS::RealmOptions::default();
 
     unsafe {
         let global = JS_NewGlobalObject(context, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
         rooted!(in(context) let global_root = global);
         let global = global_root.handle();
         let _ac = js::ac::AutoCompartment::with_obj(context, global.get());
         let function = JS_DefineFunction(context, global,
--- a/js/rust/tests/rooting.rs
+++ b/js/rust/tests/rooting.rs
@@ -17,17 +17,17 @@ use std::ptr;
 #[test]
 fn rooting() {
     unsafe {
         let runtime = Runtime::new(false).unwrap();
         JS_SetGCZeal(runtime.cx(), 2, 1);
 
         let cx = runtime.cx();
         let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
-        let c_option = JS::CompartmentOptions::default();
+        let c_option = JS::RealmOptions::default();
 
         rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                        &SIMPLE_GLOBAL_CLASS,
                                                        ptr::null_mut(),
                                                        h_option,
                                                        &c_option));
         let _ac = js::ac::AutoCompartment::with_obj(cx, global.get());
         rooted!(in(cx) let prototype_proto = JS_GetObjectPrototype(cx, global.handle()));
--- a/js/rust/tests/runtime.rs
+++ b/js/rust/tests/runtime.rs
@@ -12,17 +12,17 @@ use std::ptr;
 
 #[test]
 fn runtime() {
     unsafe {
         let runtime = Runtime::new(false).unwrap();
 
         let cx = runtime.cx();
         let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
-        let c_option = JS::CompartmentOptions::default();
+        let c_option = JS::RealmOptions::default();
 
         rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                        &SIMPLE_GLOBAL_CLASS,
                                                        ptr::null_mut(),
                                                        h_option,
                                                        &c_option));
         let _ac = js::ac::AutoCompartment::with_obj(cx, global.get());
         rooted!(in(cx) let _object = JS_NewObject(cx, &CLASS as *const _));
--- a/js/rust/tests/stack_limit.rs
+++ b/js/rust/tests/stack_limit.rs
@@ -1,31 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[macro_use]
 extern crate js;
 
-use js::jsapi::root::JS::CompartmentOptions;
+use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
 #[test]
 fn stack_limit() {
     let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
-        let c_option = CompartmentOptions::default();
+        let c_option = RealmOptions::default();
         let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
         rooted!(in(cx) let global_root = global);
         let global = global_root.handle();
         rooted!(in(cx) let mut rval = UndefinedValue());
         assert!(rt.evaluate_script(global, "function f() { f.apply() } f()",
                                    "test", 1, rval.handle_mut()).is_err());
     }
--- a/js/rust/tests/typedarray.rs
+++ b/js/rust/tests/typedarray.rs
@@ -16,17 +16,17 @@ use std::ptr;
 fn typedarray() {
     let rt = Runtime_::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                JS::OnNewGlobalHookOption::FireOnNewGlobalHook,
-                               &JS::CompartmentOptions::default())
+                               &JS::RealmOptions::default())
         );
 
         let _ac = js::ac::AutoCompartment::with_obj(cx, global.get());
 
         rooted!(in(cx) let mut rval = UndefinedValue());
         assert!(rt.evaluate_script(global.handle(), "new Uint8Array([0, 2, 4])",
                                    "test", 1, rval.handle_mut()).is_ok());
         assert!(rval.is_object());
@@ -74,17 +74,17 @@ fn typedarray() {
 fn typedarray_update_panic() {
     let rt = Runtime_::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                JS::OnNewGlobalHookOption::FireOnNewGlobalHook,
-                               &JS::CompartmentOptions::default())
+                               &JS::RealmOptions::default())
         );
 
         let _ac = js::ac::AutoCompartment::with_obj(cx, global.get());
         rooted!(in(cx) let mut rval = ptr::null_mut());
         let _ = Uint32Array::create(cx, CreateWith::Slice(&[1, 2, 3, 4, 5]), rval.handle_mut());
         typedarray!(in(cx) let mut array: Uint32Array = rval.get());
         array.as_mut().unwrap().update(&[0, 2, 4, 6, 8, 10]);
     }
--- a/js/rust/tests/value.rs
+++ b/js/rust/tests/value.rs
@@ -1,33 +1,33 @@
 /* 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/. */
 
 #[macro_use]
 extern crate js;
 
-use js::jsapi::root::JS::CompartmentOptions;
+use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
 #[test]
 fn is_symbol() {
     let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                OnNewGlobalHookOption::FireOnNewGlobalHook,
-                               &CompartmentOptions::default())
+                               &RealmOptions::default())
         );
         rooted!(in(cx) let mut rval = UndefinedValue());
         assert!(rt.evaluate_script(global.handle(), "Symbol('test')",
                                    "test", 1, rval.handle_mut()).is_ok());
         assert!(rval.is_symbol());
     }
 }
 
@@ -35,16 +35,16 @@ fn is_symbol() {
 fn is_not_symbol() {
     let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                OnNewGlobalHookOption::FireOnNewGlobalHook,
-                               &CompartmentOptions::default())
+                               &RealmOptions::default())
         );
         rooted!(in(cx) let mut rval = UndefinedValue());
         assert!(rt.evaluate_script(global.handle(), "'not a symbol'",
                                    "test", 1, rval.handle_mut()).is_ok());
         assert!(!rval.is_symbol());
     }
 }
--- a/js/rust/tests/vec_conversion.rs
+++ b/js/rust/tests/vec_conversion.rs
@@ -5,17 +5,17 @@
 #[macro_use]
 extern crate js;
 
 use js::ac::AutoCompartment;
 use js::conversions::ConversionBehavior;
 use js::conversions::ConversionResult;
 use js::conversions::FromJSValConvertible;
 use js::conversions::ToJSValConvertible;
-use js::jsapi::root::JS::CompartmentOptions;
+use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::JS_InitStandardClasses;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
@@ -29,17 +29,17 @@ fn assert_is_array(cx: *mut js::jsapi::r
 }
 
 #[test]
 fn vec_conversion() {
     let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
-    let c_option = CompartmentOptions::default();
+    let c_option = RealmOptions::default();
 
     unsafe {
         let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
         rooted!(in(cx) let global_root = global);
         let global = global_root.handle();
 
         let _ac = AutoCompartment::with_obj(cx, global.get());
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -33,19 +33,16 @@ class UTF8CharsZ;
 using AutoValueVector = AutoVector<Value>;
 using AutoIdVector = AutoVector<jsid>;
 using AutoObjectVector = AutoVector<JSObject*>;
 
 using ValueVector = JS::GCVector<JS::Value>;
 using IdVector = JS::GCVector<jsid>;
 using ScriptVector = JS::GCVector<JSScript*>;
 
-template<typename K, typename V> class AutoHashMapRooter;
-template<typename T> class AutoHashSetRooter;
-
 class MOZ_STACK_CLASS SourceBufferHolder;
 
 class HandleValueArray;
 
 class ObjectOpResult;
 class PropertyResult;
 
 enum class SymbolCode: uint32_t;
@@ -89,19 +86,16 @@ using JS::OOM;
 using JS::AutoValueVector;
 using JS::AutoIdVector;
 using JS::AutoObjectVector;
 
 using JS::ValueVector;
 using JS::IdVector;
 using JS::ScriptVector;
 
-using JS::AutoHashMapRooter;
-using JS::AutoHashSetRooter;
-
 using JS::GCVector;
 using JS::GCHashMap;
 using JS::GCHashSet;
 
 using JS::CallArgs;
 using JS::CallNonGenericMethod;
 using JS::CompileOptions;
 using JS::IsAcceptableThis;
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -11,16 +11,17 @@
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/ParseNode.h"
 #include "frontend/SharedContext.h"
 #include "gc/FreeOp.h"
 #include "gc/Policy.h"
 #include "gc/Tracer.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
+#include "vm/SelfHosting.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 
 static_assert(MODULE_STATUS_UNINSTANTIATED < MODULE_STATUS_INSTANTIATING &&
@@ -1126,22 +1127,21 @@ ModuleObject::createNamespace(JSContext*
 
     self->initReservedSlot(NamespaceSlot, ObjectValue(*ns));
     return ns;
 }
 
 static bool
 InvokeSelfHostedMethod(JSContext* cx, HandleModuleObject self, HandlePropertyName name)
 {
-    RootedValue fval(cx);
-    if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), name, name, 0, &fval))
-        return false;
+    RootedValue thisv(cx, ObjectValue(*self));
+    FixedInvokeArgs<0> args(cx);
 
     RootedValue ignored(cx);
-    return Call(cx, fval, self, &ignored);
+    return CallSelfHostedFunction(cx, name, thisv, args, &ignored);
 }
 
 /* static */ bool
 ModuleObject::Instantiate(JSContext* cx, HandleModuleObject self)
 {
     return InvokeSelfHostedMethod(cx, self, cx->names().ModuleInstantiate);
 }
 
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1173,21 +1173,21 @@ js::RegExpTesterRaw(JSContext* cx, Handl
 
     return false;
 }
 
 using CapturesVector = GCVector<Value, 4>;
 
 struct JSSubString
 {
-    JSLinearString* base;
-    size_t          offset;
-    size_t          length;
+    JSLinearString* base = nullptr;
+    size_t offset = 0;
+    size_t length = 0;
 
-    JSSubString() { mozilla::PodZero(this); }
+    JSSubString() = default;
 
     void initEmpty(JSLinearString* base) {
         this->base = base;
         offset = length = 0;
     }
     void init(JSLinearString* base, size_t offset, size_t length) {
         this->base = base;
         this->offset = offset;
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -13,16 +13,17 @@
 
 #include "builtin/SIMD.h"
 #include "gc/Marking.h"
 #include "js/Vector.h"
 #include "util/StringBuffer.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSCompartment.h"
 #include "vm/JSFunction.h"
+#include "vm/SelfHosting.h"
 #include "vm/StringType.h"
 #include "vm/TypedArrayObject.h"
 
 #include "gc/Nursery-inl.h"
 #include "gc/StoreBuffer-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
@@ -111,34 +112,29 @@ RoundUpToAlignment(CheckedInt32 address,
 static bool
 ConvertAndCopyTo(JSContext* cx,
                  HandleTypeDescr typeObj,
                  HandleTypedObject typedObj,
                  int32_t offset,
                  HandleAtom name,
                  HandleValue val)
 {
-    RootedFunction func(cx, SelfHostedFunction(cx, cx->names().ConvertAndCopyTo));
-    if (!func)
-        return false;
-
     FixedInvokeArgs<5> args(cx);
 
     args[0].setObject(*typeObj);
     args[1].setObject(*typedObj);
     args[2].setInt32(offset);
     if (name)
         args[3].setString(name);
     else
         args[3].setNull();
     args[4].set(val);
 
-    RootedValue fval(cx, ObjectValue(*func));
     RootedValue dummy(cx); // ignored by ConvertAndCopyTo
-    return js::Call(cx, fval, dummy, args, &dummy);
+    return CallSelfHostedFunction(cx, cx->names().ConvertAndCopyTo, dummy, args, &dummy);
 }
 
 static bool
 ConvertAndCopyTo(JSContext* cx, HandleTypedObject typedObj, HandleValue val)
 {
     Rooted<TypeDescr*> type(cx, &typedObj->typeDescr());
     return ConvertAndCopyTo(cx, type, typedObj, 0, nullptr, val);
 }
@@ -149,28 +145,23 @@ ConvertAndCopyTo(JSContext* cx, HandleTy
  */
 static bool
 Reify(JSContext* cx,
       HandleTypeDescr type,
       HandleTypedObject typedObj,
       size_t offset,
       MutableHandleValue to)
 {
-    RootedFunction func(cx, SelfHostedFunction(cx, cx->names().Reify));
-    if (!func)
-        return false;
-
     FixedInvokeArgs<3> args(cx);
 
     args[0].setObject(*type);
     args[1].setObject(*typedObj);
     args[2].setInt32(offset);
 
-    RootedValue fval(cx, ObjectValue(*func));
-    return js::Call(cx, fval, UndefinedHandleValue, args, to);
+    return CallSelfHostedFunction(cx, cx->names().Reify, UndefinedHandleValue, args, to);
 }
 
 // Extracts the `prototype` property from `obj`, throwing if it is
 // missing or not an object.
 static JSObject*
 GetPrototype(JSContext* cx, HandleObject obj)
 {
     RootedValue prototypeVal(cx);
@@ -2338,17 +2329,17 @@ TypedObject::create(JSContext* cx, js::g
 
     TypedObject* tobj = static_cast<TypedObject*>(obj);
     tobj->initGroup(group);
     tobj->initShape(shape);
 
     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
     cx->compartment()->setObjectPendingMetadata(cx, tobj);
 
-    js::gc::TraceCreateObject(tobj);
+    js::gc::gcTracer.traceCreateObject(tobj);
 
     return tobj;
 }
 
 /******************************************************************************
  * Intrinsics
  */
 
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -11,16 +11,18 @@
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 
+#include <new>
+
 // This data structure supports stacky LIFO allocation (mark/release and
 // LifoAllocScope). It does not maintain one contiguous segment; instead, it
 // maintains a bunch of linked memory segments. In order to prevent malloc/free
 // thrashing, unused segments are deallocated when garbage collection occurs.
 
 #include "jsutil.h"
 
 #include "js/UniquePtr.h"
@@ -588,16 +590,30 @@ class LifoAlloc
         // Only simulate OOMs when we are not using the LifoAlloc as an
         // infallible allocator.
         if (fallibleScope_)
             JS_OOM_POSSIBLY_FAIL();
 #endif
         return allocImpl(n);
     }
 
+    template<typename T, typename... Args>
+    MOZ_ALWAYS_INLINE T*
+    allocInSize(size_t n, Args&&... args)
+    {
+        MOZ_ASSERT(n >= sizeof(T), "must request enough space to store a T");
+        static_assert(alignof(T) <= detail::LIFO_ALLOC_ALIGN,
+                      "LifoAlloc must provide enough alignment to store T");
+        void* ptr = alloc(n);
+        if (!ptr)
+            return nullptr;
+
+        return new (ptr) T(mozilla::Forward<Args>(args)...);
+    }
+
     MOZ_ALWAYS_INLINE
     void* allocInfallible(size_t n) {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (void* result = allocImpl(n))
             return result;
         oomUnsafe.crash("LifoAlloc::allocInfallible");
         return nullptr;
     }
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -31,17 +31,17 @@
 
 namespace js {
 namespace frontend {
 
 class BinASTParserBase: private JS::AutoGCRooter
 {
   public:
     BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames)
-        : AutoGCRooter(cx, BINPARSER)
+        : AutoGCRooter(cx, AutoGCRooter::Tag::BinParser)
         , cx_(cx)
         , alloc_(alloc)
         , traceListHead_(nullptr)
         , usedNames_(usedNames)
         , nodeAlloc_(cx, alloc)
         , keepAtoms_(cx)
         , parseContext_(nullptr)
         , factory_(cx, alloc, nullptr, SourceKind::Binary)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -332,17 +332,17 @@ class TryFinallyControl : public Bytecod
     bool emittingSubroutine() const {
         return emittingSubroutine_;
     }
 };
 
 static inline void
 MarkAllBindingsClosedOver(LexicalScope::Data& data)
 {
-    BindingName* names = data.names;
+    TrailingNamesArray& names = data.trailingNames;
     for (uint32_t i = 0; i < data.length; i++)
         names[i] = BindingName(names[i].name(), true);
 }
 
 // A scope that introduces bindings.
 class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterScope>
 {
     // The cache of bound names that may be looked up in the
@@ -9255,17 +9255,18 @@ BytecodeEmitter::isRestParameter(ParseNo
 
     JSAtom* name = pn->name();
     Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
     if (paramLoc && lookupName(name) == *paramLoc) {
         FunctionScope::Data* bindings = funbox->functionScopeBindings();
         if (bindings->nonPositionalFormalStart > 0) {
             // |paramName| can be nullptr when the rest destructuring syntax is
             // used: `function f(...[]) {}`.
-            JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name();
+            JSAtom* paramName =
+                bindings->trailingNames[bindings->nonPositionalFormalStart - 1].name();
             return paramName && name == paramName;
         }
     }
 
     return false;
 }
 
 bool
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -329,17 +329,17 @@ void
 LexicalScopeNode::dump(GenericPrinter& out, int indent)
 {
     const char* name = parseNodeNames[size_t(getKind())];
     out.printf("(%s [", name);
     int nameIndent = indent + strlen(name) + 3;
     if (!isEmptyScope()) {
         LexicalScope::Data* bindings = scopeBindings();
         for (uint32_t i = 0; i < bindings->length; i++) {
-            JSAtom* name = bindings->names[i].name();
+            JSAtom* name = bindings->trailingNames[i].name();
             JS::AutoCheckCannotGC nogc;
             if (name->hasLatin1Chars())
                 DumpName(out, name->latin1Chars(nogc), name->length());
             else
                 DumpName(out, name->twoByteChars(nogc), name->length());
             if (i < bindings->length - 1)
                 IndentNewLine(out, nameIndent);
         }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -18,16 +18,18 @@
  */
 
 #include "frontend/Parser.h"
 
 #include "mozilla/Range.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/TypeTraits.h"
 
+#include <new>
+
 #include "jsapi.h"
 #include "jstypes.h"
 
 #include "builtin/ModuleObject.h"
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/TokenStream.h"
@@ -794,17 +796,17 @@ ParserBase::errorNoOffset(unsigned error
     va_end(args);
 }
 
 ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
                        const ReadOnlyCompileOptions& options,
                        bool foldConstants,
                        UsedNameTracker& usedNames,
                        ScriptSourceObject* sourceObject)
-  : AutoGCRooter(cx, PARSER),
+  : AutoGCRooter(cx, AutoGCRooter::Tag::Parser),
     context(cx),
     alloc(alloc),
     anyChars(cx, options, thisForCtor()),
     traceListHead(nullptr),
     pc(nullptr),
     usedNames(usedNames),
     ss(nullptr),
     sourceObject(cx, sourceObject),
@@ -1755,26 +1757,36 @@ Parser<FullParseHandler, CharT>::checkSt
     }
     return true;
 }
 
 template <typename Scope>
 typename Scope::Data*
 NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc, uint32_t numBindings)
 {
+    using Data = typename Scope::Data;
     size_t allocSize = Scope::sizeOfData(numBindings);
-    typename Scope::Data* bindings = static_cast<typename Scope::Data*>(alloc.alloc(allocSize));
-    if (!bindings) {
+    auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
+    if (!bindings)
         ReportOutOfMemory(cx);
-        return nullptr;
-    }
-    PodZero(bindings);
     return bindings;
 }
 
+/**
+ * Copy-construct |BindingName|s from |bindings| into |cursor|, then return
+ * the location one past the newly-constructed |BindingName|s.
+ */
+static MOZ_MUST_USE BindingName*
+FreshlyInitializeBindings(BindingName* cursor, const Vector<BindingName>& bindings)
+{
+    for (const BindingName& binding : bindings)
+        new (cursor++) BindingName(binding);
+    return cursor;
+}
+
 Maybe<GlobalScope::Data*>
 NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
 
     Vector<BindingName> funs(context);
     Vector<BindingName> vars(context);
     Vector<BindingName> lets(context);
     Vector<BindingName> consts(context);
@@ -1809,32 +1821,30 @@ NewGlobalScopeData(JSContext* context, P
     uint32_t numBindings = funs.length() + vars.length() + lets.length() + consts.length();
 
     if (numBindings > 0) {
         bindings = NewEmptyBindingData<GlobalScope>(context, alloc, numBindings);
         if (!bindings)
             return Nothing();
 
         // The ordering here is important. See comments in GlobalScope.
-        BindingName* start = bindings->names;
+        BindingName* start = bindings->trailingNames.start();
         BindingName* cursor = start;
 
-        PodCopy(cursor, funs.begin(), funs.length());
-        cursor += funs.length();
+        cursor = FreshlyInitializeBindings(cursor, funs);
 
         bindings->varStart = cursor - start;
-        PodCopy(cursor, vars.begin(), vars.length());
-        cursor += vars.length();
+        cursor = FreshlyInitializeBindings(cursor, vars);
 
         bindings->letStart = cursor - start;
-        PodCopy(cursor, lets.begin(), lets.length());
-        cursor += lets.length();
+        cursor = FreshlyInitializeBindings(cursor, lets);
 
         bindings->constStart = cursor - start;
-        PodCopy(cursor, consts.begin(), consts.length());
+        cursor = FreshlyInitializeBindings(cursor, consts);
+
         bindings->length = numBindings;
     }
 
     return Some(bindings);
 }
 
 Maybe<GlobalScope::Data*>
 ParserBase::newGlobalScopeData(ParseContext::Scope& scope)
@@ -1881,32 +1891,30 @@ NewModuleScopeData(JSContext* context, P
     uint32_t numBindings = imports.length() + vars.length() + lets.length() + consts.length();
 
     if (numBindings > 0) {
         bindings = NewEmptyBindingData<ModuleScope>(context, alloc, numBindings);
         if (!bindings)
             return Nothing();
 
         // The ordering here is important. See comments in ModuleScope.
-        BindingName* start = bindings->names;
+        BindingName* start = bindings->trailingNames.start();
         BindingName* cursor = start;
 
-        PodCopy(cursor, imports.begin(), imports.length());
-        cursor += imports.length();
+        cursor = FreshlyInitializeBindings(cursor, imports);
 
         bindings->varStart = cursor - start;
-        PodCopy(cursor, vars.begin(), vars.length());
-        cursor += vars.length();
+        cursor = FreshlyInitializeBindings(cursor, vars);
 
         bindings->letStart = cursor - start;
-        PodCopy(cursor, lets.begin(), lets.length());
-        cursor += lets.length();
+        cursor = FreshlyInitializeBindings(cursor, lets);
 
         bindings->constStart = cursor - start;
-        PodCopy(cursor, consts.begin(), consts.length());
+        cursor = FreshlyInitializeBindings(cursor, consts);
+
         bindings->length = numBindings;
     }
 
     return Some(bindings);
 }
 
 Maybe<ModuleScope::Data*>
 ParserBase::newModuleScopeData(ParseContext::Scope& scope)
@@ -1937,26 +1945,26 @@ NewEvalScopeData(JSContext* context, Par
     EvalScope::Data* bindings = nullptr;
     uint32_t numBindings = funs.length() + vars.length();
 
     if (numBindings > 0) {
         bindings = NewEmptyBindingData<EvalScope>(context, alloc, numBindings);
         if (!bindings)
             return Nothing();
 
-        BindingName* start = bindings->names;
+        BindingName* start = bindings->trailingNames.start();
         BindingName* cursor = start;
 
         // Keep track of what vars are functions. This is only used in BCE to omit
         // superfluous DEFVARs.
-        PodCopy(cursor, funs.begin(), funs.length());
-        cursor += funs.length();
+        cursor = FreshlyInitializeBindings(cursor, funs);
 
         bindings->varStart = cursor - start;
-        PodCopy(cursor, vars.begin(), vars.length());
+        cursor = FreshlyInitializeBindings(cursor, vars);
+
         bindings->length = numBindings;
     }
 
     return Some(bindings);
 }
 
 Maybe<EvalScope::Data*>
 ParserBase::newEvalScopeData(ParseContext::Scope& scope)
@@ -2035,28 +2043,27 @@ NewFunctionScopeData(JSContext* context,
     uint32_t numBindings = positionalFormals.length() + formals.length() + vars.length();
 
     if (numBindings > 0) {
         bindings = NewEmptyBindingData<FunctionScope>(context, alloc, numBindings);
         if (!bindings)
             return Nothing();
 
         // The ordering here is important. See comments in FunctionScope.
-        BindingName* start = bindings->names;
+        BindingName* start = bindings->trailingNames.start();
         BindingName* cursor = start;
 
-        PodCopy(cursor, positionalFormals.begin(), positionalFormals.length());
-        cursor += positionalFormals.length();
+        cursor = FreshlyInitializeBindings(cursor, positionalFormals);
 
         bindings->nonPositionalFormalStart = cursor - start;
-        PodCopy(cursor, formals.begin(), formals.length());
-        cursor += formals.length();
+        cursor = FreshlyInitializeBindings(cursor, formals);
 
         bindings->varStart = cursor - start;
-        PodCopy(cursor, vars.begin(), vars.length());
+        cursor = FreshlyInitializeBindings(cursor, vars);
+
         bindings->length = numBindings;
     }
 
     return Some(bindings);
 }
 
 Maybe<FunctionScope::Data*>
 ParserBase::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs)
@@ -2083,20 +2090,21 @@ NewVarScopeData(JSContext* context, Pars
     uint32_t numBindings = vars.length();
 
     if (numBindings > 0) {
         bindings = NewEmptyBindingData<VarScope>(context, alloc, numBindings);
         if (!bindings)
             return Nothing();
 
         // The ordering here is important. See comments in FunctionScope.
-        BindingName* start = bindings->names;
+        BindingName* start = bindings->trailingNames.start();
         BindingName* cursor = start;
 
-        PodCopy(cursor, vars.begin(), vars.length());
+        cursor = FreshlyInitializeBindings(cursor, vars);
+
         bindings->length = numBindings;
     }
 
     return Some(bindings);
 }
 
 Maybe<VarScope::Data*>
 ParserBase::newVarScopeData(ParseContext::Scope& scope)
@@ -2136,24 +2144,24 @@ NewLexicalScopeData(JSContext* context, 
     uint32_t numBindings = lets.length() + consts.length();
 
     if (numBindings > 0) {
         bindings = NewEmptyBindingData<LexicalScope>(context, alloc, numBindings);
         if (!bindings)
             return Nothing();
 
         // The ordering here is important. See comments in LexicalScope.
-        BindingName* cursor = bindings->names;
+        BindingName* cursor = bindings->trailingNames.start();
         BindingName* start = cursor;
 
-        PodCopy(cursor, lets.begin(), lets.length());
-        cursor += lets.length();
+        cursor = FreshlyInitializeBindings(cursor, lets);
 
         bindings->constStart = cursor - start;
-        PodCopy(cursor, consts.begin(), consts.length());
+        cursor = FreshlyInitializeBindings(cursor, consts);
+
         bindings->length = numBindings;
     }
 
     return Some(bindings);
 }
 
 Maybe<LexicalScope::Data*>
 ParserBase::newLexicalScopeData(ParseContext::Scope& scope)
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -482,33 +482,26 @@ void
 TokenStreamAnyChars::undoInternalUpdateLineInfoForEOL()
 {
     MOZ_ASSERT(prevLinebase != size_t(-1)); // we should never get more than one EOL
     linebase = prevLinebase;
     prevLinebase = size_t(-1);
     lineno--;
 }
 
-template<typename CharT, class AnyCharsAccess>
-MOZ_MUST_USE MOZ_ALWAYS_INLINE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::updateLineInfoForEOL()
-{
-    return anyCharsAccess().internalUpdateLineInfoForEOL(sourceUnits.offset());
-}
-
 MOZ_ALWAYS_INLINE void
 TokenStreamAnyChars::updateFlagsForEOL()
 {
     flags.isDirtyLine = false;
 }
 
 // This gets the next char, normalizing all EOL sequences to '\n' as it goes.
-template<typename CharT, class AnyCharsAccess>
+template<class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::getChar(int32_t* cp)
+TokenStreamChars<char16_t, AnyCharsAccess>::getChar(int32_t* cp)
 {
     TokenStreamAnyChars& anyChars = anyCharsAccess();
 
     if (MOZ_UNLIKELY(!sourceUnits.hasRawChars())) {
         anyChars.flags.isEOF = true;
         *cp = EOF;
         return true;
     }
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -541,16 +541,17 @@ class MOZ_STACK_CLASS TokenStreamPositio
 class TokenStreamAnyChars
   : public TokenStreamShared
 {
   public:
     TokenStreamAnyChars(JSContext* cx, const ReadOnlyCompileOptions& options,
                         StrictModeGetter* smg);
 
     template<typename CharT, class AnyCharsAccess> friend class GeneralTokenStreamChars;
+    template<typename CharT, class AnyCharsAccess> friend class TokenStreamChars;
     template<typename CharT, class AnyCharsAccess> friend class TokenStreamSpecific;
 
     template<typename CharT> friend class TokenStreamPosition;
 
     // Accessors.
     unsigned cursor() const { return cursor_; }
     unsigned nextCursor() const { return (cursor_ + 1) & ntokensMask; }
     unsigned aheadCursor(unsigned steps) const { return (cursor_ + steps) & ntokensMask; }
@@ -1021,16 +1022,40 @@ class TokenStreamCharsBase
     MOZ_MUST_USE bool copyTokenbufTo(JSContext* cx,
                                      UniquePtr<char16_t[], JS::FreePolicy>* destination);
 
     using SourceUnits = frontend::SourceUnits<CharT>;
 
     MOZ_MUST_USE bool appendCodePointToTokenbuf(uint32_t codePoint);
 
   protected:
+    MOZ_MUST_USE bool
+    fillWithTemplateStringContents(CharBuffer& charbuf, const CharT* cur, const CharT* end) {
+        while (cur < end) {
+            // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
+            // interpreted literally inside template literal contents; only
+            // literal CRLF sequences are normalized to '\n'.  See
+            // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
+            CharT ch = *cur;
+            if (ch == '\r') {
+                ch = '\n';
+                if ((cur + 1 < end) && (*(cur + 1) == '\n'))
+                    cur++;
+            }
+
+            if (!charbuf.append(ch))
+                return false;
+
+            cur++;
+        }
+
+        return true;
+    }
+
+  protected:
     /** Code units in the source code being tokenized. */
     SourceUnits sourceUnits;
 
     /** Current token string buffer. */
     CharBuffer tokenbuf;
 };
 
 template<>
@@ -1159,16 +1184,20 @@ class GeneralTokenStreamChars
 
     void ungetChar(int32_t c);
 
     /**
      * Consume characters til EOL/EOF following the start of a single-line
      * comment, without consuming the EOL/EOF.
      */
     void consumeRestOfSingleLineComment();
+
+    MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
+        return anyCharsAccess().internalUpdateLineInfoForEOL(sourceUnits.offset());
+    }
 };
 
 template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
 
 template<class AnyCharsAccess>
 class TokenStreamChars<char16_t, AnyCharsAccess>
   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
 {
@@ -1183,16 +1212,17 @@ class TokenStreamChars<char16_t, AnyChar
 
     void matchMultiUnitCodePointSlow(char16_t lead, uint32_t* codePoint);
 
   protected:
     using GeneralCharsBase::anyCharsAccess;
     using GeneralCharsBase::getCharIgnoreEOL;
     using GeneralCharsBase::sourceUnits;
     using CharsSharedBase::ungetCharIgnoreEOL;
+    using GeneralCharsBase::updateLineInfoForEOL;
 
     using GeneralCharsBase::GeneralCharsBase;
 
     // |c| must be the code unit just gotten.  If it and the subsequent code
     // unit form a valid surrogate pair, get the second code unit, set
     // |*codePoint| to the code point encoded by the surrogate pair, and return
     // true.  Otherwise do not get a second code unit, set |*codePoint = 0|,
     // and return true.
@@ -1211,16 +1241,22 @@ class TokenStreamChars<char16_t, AnyChar
     MOZ_ALWAYS_INLINE bool matchMultiUnitCodePoint(char16_t c, uint32_t* codePoint) {
         if (MOZ_LIKELY(!unicode::IsLeadSurrogate(c)))
             *codePoint = 0;
         else
             matchMultiUnitCodePointSlow(c, codePoint);
         return true;
     }
 
+    // Try to get the next character, normalizing '\r', '\r\n', and '\n' into
+    // '\n'.  Also updates internal line-counter state.  Return true on success
+    // and store the character in |*c|.  Return false and leave |*c| undefined
+    // on failure.
+    MOZ_MUST_USE bool getChar(int32_t* cp);
+
     void ungetCodePointIgnoreEOL(uint32_t codePoint);
 };
 
 // TokenStream is the lexical scanner for JavaScript source text.
 //
 // It takes a buffer of CharT characters (currently only char16_t encoding
 // UTF-16, but we're adding either UTF-8 or Latin-1 single-byte text soon) and
 // linearly scans it into |Token|s.
@@ -1293,28 +1329,31 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     using typename CharsSharedBase::SourceUnits;
 
   private:
     using CharsSharedBase::appendCodePointToTokenbuf;
     using CharsSharedBase::atomizeChars;
     using GeneralCharsBase::badToken;
     using GeneralCharsBase::consumeRestOfSingleLineComment;
     using CharsSharedBase::copyTokenbufTo;
+    using CharsSharedBase::fillWithTemplateStringContents;
+    using CharsBase::getChar;
     using GeneralCharsBase::getCharIgnoreEOL;
     using CharsBase::matchMultiUnitCodePoint;
     using GeneralCharsBase::newAtomToken;
     using GeneralCharsBase::newNameToken;
     using GeneralCharsBase::newNumberToken;
     using GeneralCharsBase::newRegExpToken;
     using GeneralCharsBase::newSimpleToken;
     using CharsSharedBase::sourceUnits;
     using CharsSharedBase::tokenbuf;
     using GeneralCharsBase::ungetChar;
     using CharsSharedBase::ungetCharIgnoreEOL;
     using CharsBase::ungetCodePointIgnoreEOL;
+    using GeneralCharsBase::updateLineInfoForEOL;
 
     template<typename CharU> friend class TokenStreamPosition;
 
   public:
     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
                         const CharT* base, size_t length);
 
     // If there is an invalid escape in a template, report it and return false,
@@ -1407,27 +1446,19 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
             // Of the form    |`...${|   or   |}...${|
             end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 2);
         } else {
             // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
             end = sourceUnits.codeUnitPtrAt(anyChars.currentToken().pos.end - 1);
         }
 
         CharBuffer charbuf(anyChars.cx);
-        while (cur < end) {
-            CharT ch = *cur;
-            if (ch == '\r') {
-                ch = '\n';
-                if ((cur + 1 < end) && (*(cur + 1) == '\n'))
-                    cur++;
-            }
-            if (!charbuf.append(ch))
-                return nullptr;
-            cur++;
-        }
+        if (!fillWithTemplateStringContents(charbuf, cur, end))
+            return nullptr;
+
         return atomizeChars(anyChars.cx, charbuf.begin(), charbuf.length());
     }
 
   private:
     // This is private because it should only be called by the tokenizer while
     // tokenizing not by, for example, BytecodeEmitter.
     bool reportStrictModeError(unsigned errorNumber, ...);
 
@@ -1656,22 +1687,16 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     MOZ_MUST_USE bool identifierName(TokenStart start, const CharT* identStart,
                                      IdentifierEscapes escaping, Modifier modifier,
                                      TokenKind* out);
 
     MOZ_MUST_USE bool getTokenInternal(TokenKind* const ttp, const Modifier modifier);
 
     MOZ_MUST_USE bool getStringOrTemplateToken(char untilChar, Modifier modifier, TokenKind* out);
 
-    // Try to get the next character, normalizing '\r', '\r\n', and '\n' into
-    // '\n'.  Also updates internal line-counter state.  Return true on success
-    // and store the character in |*c|.  Return false and leave |*c| undefined
-    // on failure.
-    MOZ_MUST_USE bool getChar(int32_t* cp);
-
     uint32_t peekUnicodeEscape(uint32_t* codePoint);
     uint32_t peekExtendedUnicodeEscape(uint32_t* codePoint);
     uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
     bool matchUnicodeEscapeIdent(uint32_t* codePoint);
     bool peekChars(int n, CharT* cp);
 
     MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);
     MOZ_MUST_USE bool getDirective(bool isMultiline, bool shouldWarnDeprecated,
@@ -1717,18 +1742,16 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     }
 
     void skipCharsIgnoreEOL(uint8_t n) {
         while (n-- > 0) {
             MOZ_ASSERT(sourceUnits.hasRawChars());
             getCharIgnoreEOL();
         }
     }
-
-    MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL();
 };
 
 // It's preferable to define this in TokenStream.cpp, but its template-ness
 // means we'd then have to *instantiate* this constructor for all possible
 // (CharT, AnyCharsAccess) pairs -- and that gets super-messy as AnyCharsAccess
 // *itself* is templated.  This symbol really isn't that huge compared to some
 // defined inline in TokenStreamSpecific, so just rely on the linker commoning
 // stuff up.
--- a/js/src/fuzz-tests/tests.cpp
+++ b/js/src/fuzz-tests/tests.cpp
@@ -39,17 +39,17 @@ getGlobalClass()
     return &c;
 }
 
 static JSObject*
 jsfuzz_createGlobal(JSContext* cx, JSPrincipals* principals)
 {
     /* Create the global object. */
     JS::RootedObject newGlobal(cx);
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
 #ifdef ENABLE_STREAMS
     options.creationOptions().setStreamsEnabled(true);
 #endif
     newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook,
                                    options);
     if (!newGlobal)
         return nullptr;
 
@@ -77,25 +77,25 @@ jsfuzz_init(JSContext** cx, JS::Persiste
     js::UseInternalJobQueues(*cx);
     if (!JS::InitSelfHostedCode(*cx))
         return false;
     JS_BeginRequest(*cx);
     global->init(*cx);
     *global = jsfuzz_createGlobal(*cx, nullptr);
     if (!*global)
         return false;
-    JS_EnterCompartment(*cx, *global);
+    JS::EnterRealm(*cx, *global);
     return true;
 }
 
 static void
 jsfuzz_uninit(JSContext* cx, JSCompartment* oldCompartment)
 {
     if (oldCompartment) {
-        JS_LeaveCompartment(cx, oldCompartment);
+        JS::LeaveRealm(cx, oldCompartment);
         oldCompartment = nullptr;
     }
     if (cx) {
         JS_EndRequest(cx);
         JS_DestroyContext(cx);
         cx = nullptr;
     }
 }
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -256,17 +256,17 @@ GCRuntime::tryNewTenuredThing(JSContext*
                 t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
             }
             if (!t)
                 ReportOutOfMemory(cx);
         }
     }
 
     checkIncrementalZoneState(cx, t);
-    TraceTenuredAlloc(t, kind);
+    gcTracer.traceTenuredAlloc(t, kind);
     return t;
 }
 
 template <AllowGC allowGC>
 bool
 GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind)
 {
     if (allowGC) {
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -589,17 +589,17 @@ Arena::finalize(FreeOp* fop, AllocKind t
                                         thing - thingSize, this);
                 newListTail = newListTail->nextSpanUnchecked(this);
             }
             firstThingOrSuccessorOfLastMarkedThing = thing + thingSize;
             nmarked++;
         } else {
             t->finalize(fop);
             JS_POISON(t, JS_SWEPT_TENURED_PATTERN, thingSize, MemCheckKind::MakeUndefined);
-            TraceTenuredFinalize(t);
+            gcTracer.traceTenuredFinalize(t);
         }
     }
 
     if (nmarked == 0) {
         // Do nothing. The caller will update the arena appropriately.
         MOZ_ASSERT(newListTail == &newListHead);
         JS_EXTRA_POISON(data, JS_SWEPT_TENURED_PATTERN, sizeof(data), MemCheckKind::MakeUndefined);
         return nmarked;
@@ -1289,17 +1289,17 @@ GCRuntime::init(uint32_t maxbytes, uint3
     }
 
 #ifdef JS_GC_ZEAL
     const char* zealSpec = getenv("JS_GC_ZEAL");
     if (zealSpec && zealSpec[0] && !parseAndSetZeal(zealSpec))
         return false;
 #endif
 
-    if (!InitTrace(*this))
+    if (!gcTracer.initTrace(*this))
         return false;
 
     if (!marker.init(mode))
         return false;
 
     if (!initSweepActions())
         return false;
 
@@ -1341,17 +1341,17 @@ GCRuntime::finish()
     }
 
     zones().clear();
 
     FreeChunkPool(fullChunks_.ref());
     FreeChunkPool(availableChunks_.ref());
     FreeChunkPool(emptyChunks_.ref());
 
-    FinishTrace();
+    gcTracer.finishTrace();
 
     nursery().printTotalProfileTimes();
     stats().printTotalProfileTimes();
 }
 
 bool
 GCRuntime::setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock)
 {
@@ -5841,17 +5841,19 @@ GCRuntime::beginSweepPhase(JS::gcreason:
 
     releaseHeldRelocatedArenas();
 
     computeNonIncrementalMarkingForValidation(session);
 
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP);
 
     sweepOnBackgroundThread =
-        reason != JS::gcreason::DESTROY_RUNTIME && !TraceEnabled() && CanUseExtraThreads();
+        reason != JS::gcreason::DESTROY_RUNTIME &&
+        !gcTracer.traceEnabled() &&
+        CanUseExtraThreads();
 
     releaseObservedTypes = shouldReleaseObservedTypes();
 
     AssertNoWrappersInGrayList(rt);
     DropStringWrappers(rt);
 
     groupZonesForSweeping(reason);
 
@@ -7466,28 +7468,28 @@ GCRuntime::gcCycle(bool nonincrementalBy
     auto result = budgetIncrementalGC(nonincrementalByAPI, reason, budget, session);
 
     // If an ongoing incremental GC was reset, we may need to restart.
     if (result == IncrementalResult::Reset) {
         MOZ_ASSERT(!isIncrementalGCInProgress());
         return result;
     }
 
-    TraceMajorGCStart();
+    gcTracer.traceMajorGCStart();
 
     incrementalCollectSlice(budget, reason, session);
 
     chunkAllocationSinceLastGC = false;
 
 #ifdef JS_GC_ZEAL
     /* Keeping these around after a GC is dangerous. */
     clearSelectedForMarking();
 #endif
 
-    TraceMajorGCEnd();
+    gcTracer.traceMajorGCEnd();
 
     return IncrementalResult::Ok;
 }
 
 #ifdef JS_GC_ZEAL
 static bool
 IsDeterministicGCReason(JS::gcreason::Reason reason)
 {
@@ -7904,17 +7906,17 @@ js::gc::FinishGC(JSContext* cx)
 AutoPrepareForTracing::AutoPrepareForTracing(JSContext* cx)
 {
     js::gc::FinishGC(cx);
     session_.emplace(cx->runtime());
 }
 
 JSCompartment*
 js::NewCompartment(JSContext* cx, JSPrincipals* principals,
-                   const JS::CompartmentOptions& options)
+                   const JS::RealmOptions& options)
 {
     JSRuntime* rt = cx->runtime();
     JS_AbortIfWrongThread(cx);
 
     ScopedJSDeletePtr<Zone> zoneHolder;
 
     Zone* zone = nullptr;
     JS::ZoneSpecifier zoneSpec = options.creationOptions().zoneSpecifier();
--- a/js/src/gc/GC.h
+++ b/js/src/gc/GC.h
@@ -119,17 +119,17 @@ typedef void (*IterateScriptCallback)(JS
  * the given compartment or for all compartments if it is null.
  */
 extern void
 IterateScripts(JSContext* cx, JSCompartment* compartment,
                void* data, IterateScriptCallback scriptCallback);
 
 JSCompartment*
 NewCompartment(JSContext* cx, JSPrincipals* principals,
-               const JS::CompartmentOptions& options);
+               const JS::RealmOptions& options);
 
 namespace gc {
 
 void FinishGC(JSContext* cx);
 
 /*
  * Merge all contents of source into target. This can only be used if source is
  * the only compartment in its zone.
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -8,17 +8,16 @@
  * GC-internal definitions.
  */
 
 #ifndef gc_GCInternals_h
 #define gc_GCInternals_h
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Maybe.h"
-#include "mozilla/PodOperations.h"
 
 #include "gc/RelocationOverlay.h"
 #include "gc/Zone.h"
 #include "vm/HelperThreads.h"
 #include "vm/Runtime.h"
 
 namespace js {
 namespace gc {
@@ -153,19 +152,19 @@ struct TenureCount
 // Keep rough track of how many times we tenure objects in particular groups
 // during minor collections, using a fixed size hash for efficiency at the cost
 // of potential collisions.
 struct TenureCountCache
 {
     static const size_t EntryShift = 4;
     static const size_t EntryCount = 1 << EntryShift;
 
-    TenureCount entries[EntryCount];
+    TenureCount entries[EntryCount] = {}; // zeroes
 
-    TenureCountCache() { mozilla::PodZero(this); }
+    TenureCountCache() = default;
 
     HashNumber hash(ObjectGroup* group) {
 #if JS_BITS_PER_WORD == 32
         static const size_t ZeroBits = 3;
 #else
         static const size_t ZeroBits = 4;
 #endif
 
--- a/js/src/gc/GCTrace.cpp
+++ b/js/src/gc/GCTrace.cpp
@@ -1,250 +1,260 @@
 /* -*- 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/. */
 
-#ifdef JS_GC_TRACE
-
 #include "gc/GCTrace.h"
 
 #include <stdio.h>
 #include <string.h>
 
+#include "gc/AllocKind.h"
 #include "gc/GCTraceFormat.h"
+#include "js/HashTable.h"
+#include "vm/JSFunction.h"
+#include "vm/JSObject.h"
 
-#include "js/HashTable.h"
+#include "gc/ObjectKind-inl.h"
 
-using namespace js;
-using namespace js::gc;
+namespace js {
+namespace gc {
 
-JS_STATIC_ASSERT(AllocKinds == unsigned(AllocKind::LIMIT));
+GCTrace gcTracer;
+
+#ifdef JS_GC_TRACE
+
+JS_STATIC_ASSERT(NumAllocKinds == unsigned(AllocKind::LIMIT));
 JS_STATIC_ASSERT(LastObjectAllocKind == unsigned(AllocKind::OBJECT_LAST));
 
-static FILE* gcTraceFile = nullptr;
-
-static HashSet<const Class*, DefaultHasher<const Class*>, SystemAllocPolicy> tracedClasses;
-static HashSet<const ObjectGroup*, DefaultHasher<const ObjectGroup*>, SystemAllocPolicy> tracedGroups;
-
 static inline void
-WriteWord(uint64_t data)
+WriteWord(FILE *file, uint64_t data)
 {
-    if (gcTraceFile)
-        fwrite(&data, sizeof(data), 1, gcTraceFile);
+    if (file)
+        fwrite(&data, sizeof(data), 1, file);
 }
 
 static inline void
-TraceEvent(GCTraceEvent event, uint64_t payload = 0, uint8_t extra = 0)
+TraceEvent(FILE *file, GCTraceEvent event, uint64_t payload = 0,
+    uint8_t extra = 0)
 {
     MOZ_ASSERT(event < GCTraceEventCount);
     MOZ_ASSERT((payload >> TracePayloadBits) == 0);
-    WriteWord((uint64_t(event) << TraceEventShift) |
+    WriteWord(file, (uint64_t(event) << TraceEventShift) |
                (uint64_t(extra) << TraceExtraShift) | payload);
 }
 
 static inline void
-TraceAddress(const void* p)
+TraceAddress(FILE *file, const void* p)
 {
-    TraceEvent(TraceDataAddress, uint64_t(p));
+    TraceEvent(file, TraceDataAddress, uint64_t(p));
 }
 
 static inline void
-TraceInt(uint32_t data)
+TraceInt(FILE *file, uint32_t data)
 {
-    TraceEvent(TraceDataInt, data);
+    TraceEvent(file, TraceDataInt, data);
 }
 
 static void
-TraceString(const char* string)
+TraceString(FILE *file, const char* string)
 {
     JS_STATIC_ASSERT(sizeof(char) == 1);
 
     size_t length = strlen(string);
     const unsigned charsPerWord = sizeof(uint64_t);
     unsigned wordCount = (length + charsPerWord - 1) / charsPerWord;
 
-    TraceEvent(TraceDataString, length);
+    TraceEvent(file, TraceDataString, length);
     for (unsigned i = 0; i < wordCount; ++i) {
         union
         {
             uint64_t word;
             char chars[charsPerWord];
         } data;
         strncpy(data.chars, string + (i * charsPerWord), charsPerWord);
-        WriteWord(data.word);
+        WriteWord(file, data.word);
     }
 }
 
 bool
-js::gc::InitTrace(GCRuntime& gc)
+GCTrace::initTrace(GCRuntime& gc)
 {
     /* This currently does not support multiple runtimes. */
     MOZ_ALWAYS_TRUE(!gcTraceFile);
 
     char* filename = getenv("JS_GC_TRACE");
     if (!filename)
         return true;
 
-    if (!tracedClasses.init() || !tracedTypes.init()) {
-        FinishTrace();
+    if (!tracedClasses.init() || !tracedGroups.init()) {
+        finishTrace();
         return false;
     }
 
     gcTraceFile = fopen(filename, "w");
     if (!gcTraceFile) {
-        FinishTrace();
+        finishTrace();
         return false;
     }
 
-    TraceEvent(TraceEventInit, 0, TraceFormatVersion);
+    TraceEvent(gcTraceFile, TraceEventInit, 0, TraceFormatVersion);
 
     /* Trace information about thing sizes. */
     for (auto kind : AllAllocKinds())
-        TraceEvent(TraceEventThingSize, Arena::thingSize(kind));
+        TraceEvent(gcTraceFile, TraceEventThingSize, Arena::thingSize(kind));
 
     return true;
 }
 
 void
-js::gc::FinishTrace()
+GCTrace::finishTrace()
 {
     if (gcTraceFile) {
         fclose(gcTraceFile);
         gcTraceFile = nullptr;
     }
     tracedClasses.finish();
-    tracedTypes.finish();
+    tracedGroups.finish();
 }
 
 bool
-js::gc::TraceEnabled()
+GCTrace::traceEnabled()
 {
     return gcTraceFile != nullptr;
 }
 
 void
-js::gc::TraceNurseryAlloc(Cell* thing, size_t size)
+GCTrace::traceNurseryAlloc(Cell* thing, size_t size)
 {
     if (thing) {
         /* We don't have AllocKind here, but we can work it out from size. */
         unsigned slots = (size - sizeof(JSObject)) / sizeof(JS::Value);
         AllocKind kind = GetBackgroundAllocKind(GetGCObjectKind(slots));
-        TraceEvent(TraceEventNurseryAlloc, uint64_t(thing), kind);
+        TraceEvent(gcTraceFile, TraceEventNurseryAlloc, uint64_t(thing),
+            uint8_t(kind));
+    }
+}
+
+void
+GCTrace::traceNurseryAlloc(Cell* thing, AllocKind kind)
+{
+    if (thing) {
+        TraceEvent(gcTraceFile, TraceEventNurseryAlloc, uint64_t(thing),
+            uint8_t(kind));
+    }
+}
+
+void
+GCTrace::traceTenuredAlloc(Cell* thing, AllocKind kind)
+{
+    if (thing) {
+        TraceEvent(gcTraceFile, TraceEventTenuredAlloc, uint64_t(thing),
+            uint8_t(kind));
     }
 }
 
 void
-js::gc::TraceNurseryAlloc(Cell* thing, AllocKind kind)
-{
-    if (thing)
-        TraceEvent(TraceEventNurseryAlloc, uint64_t(thing), kind);
-}
-
-void
-js::gc::TraceTenuredAlloc(Cell* thing, AllocKind kind)
-{
-    if (thing)
-        TraceEvent(TraceEventTenuredAlloc, uint64_t(thing), kind);
-}
-
-static void
-MaybeTraceClass(const Class* clasp)
+js::gc::GCTrace::maybeTraceClass(const Class* clasp)
 {
     if (tracedClasses.has(clasp))
         return;
 
-    TraceEvent(TraceEventClassInfo, uint64_t(clasp));
-    TraceString(clasp->name);
-    TraceInt(clasp->flags);
-    TraceInt(clasp->finalize != nullptr);
+    TraceEvent(gcTraceFile, TraceEventClassInfo, uint64_t(clasp));
+    TraceString(gcTraceFile, clasp->name);
+    TraceInt(gcTraceFile, clasp->flags);
+    TraceInt(gcTraceFile, clasp->hasFinalize());
 
     MOZ_ALWAYS_TRUE(tracedClasses.put(clasp));
 }
 
-static void
-MaybeTraceGroup(ObjectGroup* group)
+void
+js::gc::GCTrace::maybeTraceGroup(ObjectGroup* group)
 {
     if (tracedGroups.has(group))
         return;
 
-    MaybeTraceClass(group->clasp());
-    TraceEvent(TraceEventGroupInfo, uint64_t(group));
-    TraceAddress(group->clasp());
-    TraceInt(group->flags());
+    maybeTraceClass(group->clasp());
+    TraceEvent(gcTraceFile, TraceEventGroupInfo, uint64_t(group));
+    TraceAddress(gcTraceFile, group->clasp());
+    TraceInt(gcTraceFile, group->flagsDontCheckGeneration());
 
     MOZ_ALWAYS_TRUE(tracedGroups.put(group));
 }
 
 void
-js::gc::TraceTypeNewScript(ObjectGroup* group)
+GCTrace::traceTypeNewScript(ObjectGroup* group)
 {
     const size_t bufLength = 128;
     static char buffer[bufLength];
-    MOZ_ASSERT(group->hasNewScript());
-    JSAtom* funName = group->newScript()->fun->displayAtom();
+
+    JSAtom* funName = group->newScriptDontCheckGeneration()->function()->displayAtom();
     if (!funName)
         return;
 
     size_t length = funName->length();
     MOZ_ALWAYS_TRUE(length < bufLength);
     CopyChars(reinterpret_cast<Latin1Char*>(buffer), *funName);
     buffer[length] = 0;
 
-    TraceEvent(TraceEventTypeNewScript, uint64_t(group));
-    TraceString(buffer);
+    TraceEvent(gcTraceFile, TraceEventTypeNewScript, uint64_t(group));
+    TraceString(gcTraceFile, buffer);
 }
 
 void
-js::gc::TraceCreateObject(JSObject* object)
+GCTrace::traceCreateObject(JSObject* object)
 {
     if (!gcTraceFile)
         return;
 
     ObjectGroup* group = object->group();
-    MaybeTraceGroup(group);
-    TraceEvent(TraceEventCreateObject, uint64_t(object));
-    TraceAddress(group);
+    maybeTraceGroup(group);
+    TraceEvent(gcTraceFile, TraceEventCreateObject, uint64_t(object));
+    TraceAddress(gcTraceFile, group);
 }
 
 void
-js::gc::TraceMinorGCStart()
+GCTrace::traceMinorGCStart()
 {
-    TraceEvent(TraceEventMinorGCStart);
+    TraceEvent(gcTraceFile, TraceEventMinorGCStart);
 }
 
 void
-js::gc::TracePromoteToTenured(Cell* src, Cell* dst)
+GCTrace::tracePromoteToTenured(Cell* src, Cell* dst)
 {
-    TraceEvent(TraceEventPromoteToTenured, uint64_t(src));
-    TraceAddress(dst);
+    TraceEvent(gcTraceFile, TraceEventPromoteToTenured, uint64_t(src));
+    TraceAddress(gcTraceFile, dst);
+}
+
+void
+GCTrace::traceMinorGCEnd()
+{
+    TraceEvent(gcTraceFile, TraceEventMinorGCEnd);
 }
 
 void
-js::gc::TraceMinorGCEnd()
+GCTrace::traceMajorGCStart()
 {
-    TraceEvent(TraceEventMinorGCEnd);
-}
-
-void
-js::gc::TraceMajorGCStart()
-{
-    TraceEvent(TraceEventMajorGCStart);
+    TraceEvent(gcTraceFile, TraceEventMajorGCStart);
 }
 
 void
-js::gc::TraceTenuredFinalize(Cell* thing)
+GCTrace::traceTenuredFinalize(Cell* thing)
 {
     if (!gcTraceFile)
         return;
-    if (thing->tenuredGetAllocKind() == AllocKind::OBJECT_GROUP)
+    if (thing->asTenured().getAllocKind() == AllocKind::OBJECT_GROUP)
         tracedGroups.remove(static_cast<const ObjectGroup*>(thing));
-    TraceEvent(TraceEventTenuredFinalize, uint64_t(thing));
+    TraceEvent(gcTraceFile, TraceEventTenuredFinalize, uint64_t(thing));
 }
 
 void
-js::gc::TraceMajorGCEnd()
+GCTrace::traceMajorGCEnd()
 {
-    TraceEvent(TraceEventMajorGCEnd);
+    TraceEvent(gcTraceFile, TraceEventMajorGCEnd);
 }
 
 #endif
+
+} // js
+} // gc
--- a/js/src/gc/GCTrace.h
+++ b/js/src/gc/GCTrace.h
@@ -10,48 +10,68 @@
 #include "gc/Heap.h"
 
 namespace js {
 
 class ObjectGroup;
 
 namespace gc {
 
+/*
+ * Tracing code is declared within this class, so the class can be a friend of
+ * something and access private details used for tracing.
+ */
+class GCTrace {
+  public:
+    GCTrace() { };
+
 #ifdef JS_GC_TRACE
 
-extern MOZ_MUST_USE bool InitTrace(GCRuntime& gc);
-extern void FinishTrace();
-extern bool TraceEnabled();
-extern void TraceNurseryAlloc(Cell* thing, size_t size);
-extern void TraceNurseryAlloc(Cell* thing, AllocKind kind);
-extern void TraceTenuredAlloc(Cell* thing, AllocKind kind);
-extern void TraceCreateObject(JSObject* object);
-extern void TraceMinorGCStart();
-extern void TracePromoteToTenured(Cell* src, Cell* dst);
-extern void TraceMinorGCEnd();
-extern void TraceMajorGCStart();
-extern void TraceTenuredFinalize(Cell* thing);
-extern void TraceMajorGCEnd();
-extern void TraceTypeNewScript(js::ObjectGroup* group);
+    MOZ_MUST_USE bool initTrace(GCRuntime& gc);
+    void finishTrace();
+    bool traceEnabled();
+    void traceNurseryAlloc(Cell* thing, size_t size);
+    void traceNurseryAlloc(Cell* thing, AllocKind kind);
+    void traceTenuredAlloc(Cell* thing, AllocKind kind);
+    void traceCreateObject(JSObject* object);
+    void traceMinorGCStart();
+    void tracePromoteToTenured(Cell* src, Cell* dst);
+    void traceMinorGCEnd();
+    void traceMajorGCStart();
+    void traceTenuredFinalize(Cell* thing);
+    void traceMajorGCEnd();
+    void traceTypeNewScript(js::ObjectGroup* group);
+
+  private:
+    FILE* gcTraceFile = nullptr;
+
+    HashSet<const Class*, DefaultHasher<const Class*>, SystemAllocPolicy> tracedClasses;
+    HashSet<const ObjectGroup*, DefaultHasher<const ObjectGroup*>, SystemAllocPolicy> tracedGroups;
+
+    void maybeTraceClass(const Class* clasp);
+    void maybeTraceGroup(ObjectGroup* group);
 
 #else
 
-inline MOZ_MUST_USE bool InitTrace(GCRuntime& gc) { return true; }
-inline void FinishTrace() {}
-inline bool TraceEnabled() { return false; }
-inline void TraceNurseryAlloc(Cell* thing, size_t size) {}
-inline void TraceNurseryAlloc(Cell* thing, AllocKind kind) {}
-inline void TraceTenuredAlloc(Cell* thing, AllocKind kind) {}
-inline void TraceCreateObject(JSObject* object) {}
-inline void TraceMinorGCStart() {}
-inline void TracePromoteToTenured(Cell* src, Cell* dst) {}
-inline void TraceMinorGCEnd() {}
-inline void TraceMajorGCStart() {}
-inline void TraceTenuredFinalize(Cell* thing) {}
-inline void TraceMajorGCEnd() {}
-inline void TraceTypeNewScript(js::ObjectGroup* group) {}
+    MOZ_MUST_USE bool initTrace(GCRuntime& gc) { return true; }
+    void finishTrace() {}
+    bool traceEnabled() { return false; }
+    void traceNurseryAlloc(Cell* thing, size_t size) {}
+    void traceNurseryAlloc(Cell* thing, AllocKind kind) {}
+    void traceTenuredAlloc(Cell* thing, AllocKind kind) {}
+    void traceCreateObject(JSObject* object) {}
+    void traceMinorGCStart() {}
+    void tracePromoteToTenured(Cell* src, Cell* dst) {}
+    void traceMinorGCEnd() {}
+    void traceMajorGCStart() {}
+    void traceTenuredFinalize(Cell* thing) {}
+    void traceMajorGCEnd() {}
+    void traceTypeNewScript(js::ObjectGroup* group) {}
 
 #endif
+}; /* GCTrace */
+
+extern GCTrace gcTracer;
 
 } /* namespace gc */
 } /* namespace js */
 
 #endif
--- a/js/src/gc/GCTraceFormat.h
+++ b/js/src/gc/GCTraceFormat.h
@@ -18,17 +18,17 @@
 
 enum GCTraceEvent {
     // Events
     TraceEventInit,
     TraceEventThingSize,
     TraceEventNurseryAlloc,
     TraceEventTenuredAlloc,
     TraceEventClassInfo,
-    TraceEventTypeInfo,
+    TraceEventGroupInfo,
     TraceEventTypeNewScript,
     TraceEventCreateObject,
     TraceEventMinorGCStart,
     TraceEventPromoteToTenured,
     TraceEventMinorGCEnd,
     TraceEventMajorGCStart,
     TraceEventTenuredFinalize,
     TraceEventMajorGCEnd,
@@ -45,12 +45,12 @@ const unsigned TraceFormatVersion = 1;
 const unsigned TracePayloadBits = 48;
 
 const unsigned TraceExtraShift = 48;
 const unsigned TraceExtraBits = 8;
 
 const unsigned TraceEventShift = 56;
 const unsigned TraceEventBits = 8;
 
-const unsigned AllocKinds = 22;
-const unsigned LastObjectAllocKind = 11;
+const unsigned NumAllocKinds = 29;
+const unsigned LastObjectAllocKind = 13;
 
 #endif
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1290,55 +1290,55 @@ BindingName::trace(JSTracer* trc)
 void
 BindingIter::trace(JSTracer* trc)
 {
     TraceNullableBindingNames(trc, names_, length_);
 }
 void
 LexicalScope::Data::trace(JSTracer* trc)
 {
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 FunctionScope::Data::trace(JSTracer* trc)
 {
     TraceNullableEdge(trc, &canonicalFunction, "scope canonical function");
-    TraceNullableBindingNames(trc, names, length);
+    TraceNullableBindingNames(trc, trailingNames.start(), length);
 }
 void
 VarScope::Data::trace(JSTracer* trc)
 {
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 GlobalScope::Data::trace(JSTracer* trc)
 {
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 EvalScope::Data::trace(JSTracer* trc)
 {
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 ModuleScope::Data::trace(JSTracer* trc)
 {
     TraceNullableEdge(trc, &module, "scope module");
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 WasmInstanceScope::Data::trace(JSTracer* trc)
 {
     TraceNullableEdge(trc, &instance, "wasm instance");
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 WasmFunctionScope::Data::trace(JSTracer* trc)
 {
-    TraceBindingNames(trc, names, length);
+    TraceBindingNames(trc, trailingNames.start(), length);
 }
 void
 Scope::traceChildren(JSTracer* trc)
 {
     TraceNullableEdge(trc, &enclosing_, "scope enclosing");
     TraceNullableEdge(trc, &environmentShape_, "scope env shape");
     switch (kind_) {
       case ScopeKind::Function:
@@ -1378,96 +1378,96 @@ Scope::traceChildren(JSTracer* trc)
 }
 inline void
 js::GCMarker::eagerlyMarkChildren(Scope* scope)
 {
     if (scope->enclosing_)
         traverseEdge(scope, static_cast<Scope*>(scope->enclosing_));
     if (scope->environmentShape_)
         traverseEdge(scope, static_cast<Shape*>(scope->environmentShape_));
-    BindingName* names = nullptr;
+    TrailingNamesArray* names = nullptr;
     uint32_t length = 0;
     switch (scope->kind_) {
       case ScopeKind::Function: {
         FunctionScope::Data* data = reinterpret_cast<FunctionScope::Data*>(scope->data_);
         traverseEdge(scope, static_cast<JSObject*>(data->canonicalFunction));
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::FunctionBodyVar:
       case ScopeKind::ParameterExpressionVar: {
         VarScope::Data* data = reinterpret_cast<VarScope::Data*>(scope->data_);
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Lexical:
       case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda: {
         LexicalScope::Data* data = reinterpret_cast<LexicalScope::Data*>(scope->data_);
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic: {
         GlobalScope::Data* data = reinterpret_cast<GlobalScope::Data*>(scope->data_);
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Eval:
       case ScopeKind::StrictEval: {
         EvalScope::Data* data = reinterpret_cast<EvalScope::Data*>(scope->data_);
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Module: {
         ModuleScope::Data* data = reinterpret_cast<ModuleScope::Data*>(scope->data_);
         traverseEdge(scope, static_cast<JSObject*>(data->module));
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::With:
         break;
 
       case ScopeKind::WasmInstance: {
         WasmInstanceScope::Data* data = reinterpret_cast<WasmInstanceScope::Data*>(scope->data_);
         traverseEdge(scope, static_cast<JSObject*>(data->instance));
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::WasmFunction: {
         WasmFunctionScope::Data* data = reinterpret_cast<WasmFunctionScope::Data*>(scope->data_);
-        names = data->names;
+        names = &data->trailingNames;
         length = data->length;
         break;
       }
     }
     if (scope->kind_ == ScopeKind::Function) {
         for (uint32_t i = 0; i < length; i++) {
-            if (JSAtom* name = names[i].name())
+            if (JSAtom* name = names->operator[](i).name())
                 traverseEdge(scope, static_cast<JSString*>(name));
         }
     } else {
         for (uint32_t i = 0; i < length; i++)
-            traverseEdge(scope, static_cast<JSString*>(names[i].name()));
+            traverseEdge(scope, static_cast<JSString*>(names->operator[](i).name()));
     }
 }
 
 void
 js::ObjectGroup::traceChildren(JSTracer* trc)
 {
     AutoSweepObjectGroup sweep(this);
 
@@ -2290,17 +2290,17 @@ MarkStack::reset()
     }
     setStack(newStack, 0, baseCapacity_);
 }
 
 inline bool
 MarkStack::ensureSpace(size_t count)
 {
     if ((tos_ + count) <= end_)
-        return true;
+        return !js::oom::ShouldFailWithOOM();
 
     return enlarge(count);
 }
 
 bool
 MarkStack::enlarge(size_t count)
 {
     size_t newCapacity = Min(maxCapacity_.ref(), capacity() * 2);
@@ -3098,17 +3098,17 @@ js::TenuringTracer::moveToTenuredSlow(JS
         MOZ_ASSERT_IF(src->getClass()->hasFinalize(),
                       CanNurseryAllocateFinalizedClass(src->getClass()));
     }
 
     RelocationOverlay* overlay = RelocationOverlay::fromCell(src);
     overlay->forwardTo(dst);
     insertIntoObjectFixupList(overlay);
 
-    TracePromoteToTenured(src, dst);
+    gcTracer.tracePromoteToTenured(src, dst);
     return dst;
 }
 
 inline JSObject*
 js::TenuringTracer::movePlainObjectToTenured(PlainObject* src)
 {
     // Fast path version of moveToTenuredSlow() for specialized for PlainObject.
 
@@ -3130,17 +3130,17 @@ js::TenuringTracer::movePlainObjectToTen
     tenuredSize += moveElementsToTenured(dst, src, dstKind);
 
     MOZ_ASSERT(!dst->getClass()->extObjectMovedOp());
 
     RelocationOverlay* overlay = RelocationOverlay::fromCell(src);
     overlay->forwardTo(dst);
     insertIntoObjectFixupList(overlay);
 
-    TracePromoteToTenured(src, dst);
+    gcTracer.tracePromoteToTenured(src, dst);
     return dst;
 }
 
 size_t
 js::TenuringTracer::moveSlotsToTenured(NativeObject* dst, NativeObject* src)
 {
     /* Fixed slots have already been copied over. */
     if (!src->hasDynamicSlots())
@@ -3243,17 +3243,17 @@ js::TenuringTracer::moveToTenured(JSStri
     }
     JSString* dst = reinterpret_cast<JSString*>(t);
     tenuredSize += moveStringToTenured(dst, src, dstKind);
 
     RelocationOverlay* overlay = RelocationOverlay::fromCell(src);
     overlay->forwardTo(dst);
     insertIntoStringFixupList(overlay);
 
-    TracePromoteToTenured(src, dst);
+    gcTracer.tracePromoteToTenured(src, dst);
     return dst;
 }
 
 void
 js::Nursery::collectToFixedPoint(TenuringTracer& mover, TenureCountCache& tenureCounts)
 {
     for (RelocationOverlay* p = mover.objHead; p; p = p->next()) {
         JSObject* obj = static_cast<JSObject*>(p->forwardingAddress());
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -324,34 +324,34 @@ js::Nursery::allocateObject(JSContext* c
     }
 
     /* Store slots pointer directly in new object. If no dynamic slots were
      * requested, caller must initialize slots_ field itself as needed. We
      * don't know if the caller was a native object or not. */
     if (nDynamicSlots)
         static_cast<NativeObject*>(obj)->initSlots(slots);
 
-    TraceNurseryAlloc(obj, size);
+    gcTracer.traceNurseryAlloc(obj, size);
     return obj;
 }
 
 Cell*
 js::Nursery::allocateString(Zone* zone, size_t size, AllocKind kind)
 {
     /* Ensure there's enough space to replace the contents with a RelocationOverlay. */
     MOZ_ASSERT(size >= sizeof(RelocationOverlay));
 
     size_t allocSize = JS_ROUNDUP(sizeof(StringLayout) - 1 + size, CellAlignBytes);
     auto header = static_cast<StringLayout*>(allocate(allocSize));
     if (!header)
         return nullptr;
     header->zone = zone;
 
     auto cell = reinterpret_cast<Cell*>(&header->cell);
-    TraceNurseryAlloc(cell, kind);
+    gcTracer.traceNurseryAlloc(cell, kind);
     return cell;
 }
 
 void*
 js::Nursery::allocate(size_t size)
 {
     MOZ_ASSERT(isEnabled());
     MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
@@ -717,17 +717,17 @@ js::Nursery::collect(JS::gcreason::Reaso
     if (rt->gc.hasZealMode(ZealMode::CheckNursery)) {
         for (auto canary = lastCanary_; canary; canary = canary->next)
             MOZ_ASSERT(canary->magicValue == CanaryMagicValue);
     }
     lastCanary_ = nullptr;
 #endif
 
     rt->gc.stats().beginNurseryCollection(reason);
-    TraceMinorGCStart();
+    gcTracer.traceMinorGCStart();
 
     maybeClearProfileDurations();
     startProfile(ProfileKey::Total);
 
     // The analysis marks TenureCount as not problematic for GC hazards because
     // it is only used here, and ObjectGroup pointers are never
     // nursery-allocated.
     MOZ_ASSERT(!IsNurseryAllocable(AllocKind::OBJECT_GROUP));
@@ -813,17 +813,17 @@ js::Nursery::collect(JS::gcreason::Reaso
     rt->addTelemetry(JS_TELEMETRY_GC_MINOR_US, totalTime.ToMicroseconds());
     rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON, reason);
     if (totalTime.ToMilliseconds() > 1.0)
         rt->addTelemetry(JS_TELEMETRY_GC_MINOR_REASON_LONG, reason);
     rt->addTelemetry(JS_TELEMETRY_GC_NURSERY_BYTES, sizeOfHeapCommitted());
     rt->addTelemetry(JS_TELEMETRY_GC_PRETENURE_COUNT, pretenureCount);
 
     rt->gc.stats().endNurseryCollection(reason);
-    TraceMinorGCEnd();
+    gcTracer.traceMinorGCEnd();
     timeInChunkAlloc_ = mozilla::TimeDuration();
 
     if (enableProfiling_ && totalTime >= profileThreshold_) {
         rt->gc.stats().maybePrintProfileHeaders();
 
         fprintf(stderr, "MinorGC: %20s %5.1f%% %4u        ",
                 JS::gcreason::ExplainReason(reason),
                 promotionRate * 100,
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -129,89 +129,94 @@ JSRuntime::finishPersistentRoots()
 #define FINISH_ROOT_LIST(name, type, _)                                 \
     FinishPersistentRootedChain<type*>(heapRoots.ref()[JS::RootKind::name]);
 JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST)
 #undef FINISH_ROOT_LIST
     FinishPersistentRootedChain<jsid>(heapRoots.ref()[JS::RootKind::Id]);
     FinishPersistentRootedChain<Value>(heapRoots.ref()[JS::RootKind::Value]);
 
     // Note that we do not finalize the Traceable list as we do not know how to
-    // safely clear memebers. We instead assert that none escape the RootLists.
+    // safely clear members. We instead assert that none escape the RootLists.
     // See the comment on RootLists::~RootLists for details.
 }
 
 inline void
 AutoGCRooter::trace(JSTracer* trc)
 {
     switch (tag_) {
-      case PARSER:
+      case Tag::Parser:
         frontend::TraceParser(trc, this);
         return;
 
 #if defined(JS_BUILD_BINAST)
-      case BINPARSER:
+      case Tag::BinParser:
         frontend::TraceBinParser(trc, this);
         return;
 #endif // defined(JS_BUILD_BINAST)
 
-      case VALARRAY: {
+      case Tag::ValueArray: {
         /*
          * We don't know the template size parameter, but we can safely treat it
          * as an AutoValueArray<1> because the length is stored separately.
          */
         AutoValueArray<1>* array = static_cast<AutoValueArray<1>*>(this);
         TraceRootRange(trc, array->length(), array->begin(), "js::AutoValueArray");
         return;
       }
 
-      case WRAPPER: {
+      case Tag::Wrapper: {
         /*
          * We need to use TraceManuallyBarrieredEdge here because we trace
          * wrapper roots in every slice. This is because of some rule-breaking
          * in RemapAllWrappersForObject; see comment there.
          */
         TraceManuallyBarrieredEdge(trc, &static_cast<AutoWrapperRooter*>(this)->value.get(),
-                                   "JS::AutoWrapperRooter.value");
+                                   "js::AutoWrapperRooter.value");
         return;
       }
 
-      case WRAPVECTOR: {
+      case Tag::WrapperVector: {
         auto vector = static_cast<AutoWrapperVector*>(this);
         /*
          * We need to use TraceManuallyBarrieredEdge here because we trace
          * wrapper roots in every slice. This is because of some rule-breaking
          * in RemapAllWrappersForObject; see comment there.
          */
         for (WrapperValue* p = vector->begin(); p < vector->end(); p++)
             TraceManuallyBarrieredEdge(trc, &p->get(), "js::AutoWrapperVector.vector");
         return;
       }
 
-      case CUSTOM:
+      case Tag::Custom:
         static_cast<JS::CustomAutoRooter*>(this)->trace(trc);
         return;
+
+      case Tag::Array: {
+        auto array = static_cast<AutoArrayRooter*>(this);
+        if (Value* vp = array->begin())
+            TraceRootRange(trc, array->length(), vp, "js::AutoArrayRooter");
+        return;
+      }
     }
 
-    MOZ_ASSERT(tag_ >= 0);
-    if (Value* vp = static_cast<AutoArrayRooter*>(this)->array)
-        TraceRootRange(trc, tag_, vp, "JS::AutoArrayRooter.array");
+    MOZ_CRASH("Bad AutoGCRooter::Tag");
 }
 
 /* static */ void
 AutoGCRooter::traceAll(JSContext* cx, JSTracer* trc)
 {
     for (AutoGCRooter* gcr = cx->autoGCRooters_; gcr; gcr = gcr->down)
         gcr->trace(trc);
 }
 
 /* static */ void
 AutoGCRooter::traceAllWrappers(JSContext* cx, JSTracer* trc)
 {
     for (AutoGCRooter* gcr = cx->autoGCRooters_; gcr; gcr = gcr->down) {
-        if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
+        if (gcr->tag_ == Tag::WrapperVector || gcr->tag_ == Tag::Wrapper)
             gcr->trace(trc);
     }
 }
 
 void
 StackShape::trace(JSTracer* trc)
 {
     if (base)
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -6,17 +6,16 @@
 
 #ifndef gc_Statistics_h
 #define gc_Statistics_h
 
 #include "mozilla/Array.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/IntegerRange.h"
-#include "mozilla/PodOperations.h"
 #include "mozilla/TimeStamp.h"
 
 #include "jspubtd.h"
 #include "NamespaceImports.h"
 
 #include "gc/GCEnum.h"
 #include "js/AllocPolicy.h"
 #include "js/SliceBudget.h"
@@ -45,43 +44,41 @@ enum Stat {
     STAT_ARENA_RELOCATED,
 
     STAT_LIMIT
 };
 
 struct ZoneGCStats
 {
     /* Number of zones collected in this GC. */
-    int collectedZoneCount;
+    int collectedZoneCount = 0;
 
     /* Number of zones that could have been collected in this GC. */
-    int collectableZoneCount;
+    int collectableZoneCount = 0;
 
     /* Total number of zones in the Runtime at the start of this GC. */
-    int zoneCount;
+    int zoneCount = 0;
 
     /* Number of zones swept in this GC. */
-    int sweptZoneCount;
+    int sweptZoneCount = 0;
 
     /* Total number of compartments in all zones collected. */
-    int collectedCompartmentCount;
+    int collectedCompartmentCount = 0;
 
     /* Total number of compartments in the Runtime at the start of this GC. */
-    int compartmentCount;
+    int compartmentCount = 0;
 
     /* Total number of compartments swept by this GC. */
-    int sweptCompartmentCount;
+    int sweptCompartmentCount = 0;
 
     bool isFullCollection() const {
         return collectedZoneCount == collectableZoneCount;
     }
 
-    ZoneGCStats() {
-        mozilla::PodZero(this);
-    }
+    ZoneGCStats() = default;
 };
 
 #define FOR_EACH_GC_PROFILE_TIME(_)                                           \
     _(BeginCallback, "bgnCB",  PhaseKind::GC_BEGIN)                           \
     _(MinorForMajor, "evct4m", PhaseKind::EVICT_NURSERY_FOR_MAJOR_GC)         \
     _(WaitBgThread,  "waitBG", PhaseKind::WAIT_BACKGROUND_THREAD)             \
     _(Prepare,       "prep",   PhaseKind::PREPARE)                            \
     _(Mark,          "mark",   PhaseKind::MARK)                               \
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -80,17 +80,17 @@ main(int argc, const char** argv)
     JS_SetNativeStackQuota(cx, 5000000);
 
     checkBool(JS::InitSelfHostedCode(cx));
     JS::SetWarningReporter(cx, reportWarning);
 
     JSAutoRequest areq(cx);
 
     /* Create the global object. */
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class,
                         nullptr, JS::FireOnNewGlobalHook, options)));
     JSAutoRealm ar(cx, global);
 
     /* Populate the global object with the standard globals,
        like Object and Array. */
     checkBool(JS_InitStandardClasses(cx, global));
 
--- a/js/src/jit-test/tests/gc/bug-1231386.js
+++ b/js/src/jit-test/tests/gc/bug-1231386.js
@@ -1,8 +1,10 @@
+// |jit-test| slow
+
 if (!('oomTest' in this))
     quit();
 
 function f1() {}
 function f2() {}
 r = [function() {}, function() {}, [], function() {}, f1, function() {}, f2];
 l = [0];
 function f3() {
--- a/js/src/jit-test/tests/ion/bug1215600.js
+++ b/js/src/jit-test/tests/ion/bug1215600.js
@@ -1,8 +1,10 @@
+|jit-test| slow
+
 lfcode = Array()
 lfcode.push("5")
 lfcode.push("")
 lfcode.push("3")
 lfcode.push("oomTest(()=>{gc()})")
 for (let i = 0; i < 10; i++) {
     file = lfcode.shift()
     loadFile(file)
--- a/js/src/jit-test/tests/wasm/ion-error-i64.js
+++ b/js/src/jit-test/tests/wasm/ion-error-i64.js
@@ -25,35 +25,35 @@ var instance = wasmEvalText(`(module
      call $add
      i64.extend_s/i32
     )
 )`).exports;
 
 var callToMain;
 
 function main() {
-    var arr = [instance.add, (x,y)=>x+y];
-    var arrayCallLine = nextLineNumber(6);
+    var arrayCallLine = nextLineNumber(13);
     for (var i = 0; i < ITER; i++) {
+        var arr = [instance.add, (x,y)=>x+y];
+        if (i === EXCEPTION_ITER) {
+            arr[0] = instance.add64;
+        } else if (i === EXCEPTION_ITER + 1) {
+            arr[0] = instance.add;
+        }
+
         var caught = null;
 
         startProfiling();
         try {
             arr[i%2](i, i);
         } catch(e) {
             caught = e;
         }
         let profilingStack = endProfiling();
 
-        if (i === EXCEPTION_ITER - 1) {
-            arr[0] = instance.add64;
-        } else if (i === EXCEPTION_ITER) {
-            arr[0] = instance.add;
-        }
-
         assertEq(!!caught, i === EXCEPTION_ITER);
         if (caught) {
             assertEqPreciseStacks(profilingStack, [
                 // Error stack: control flow is redirected to a builtin thunk
                 // then calling into C++ from the wasm entry before jumping to
                 // the wasm jit entry exception handler.
                 ['', '>', '<,>', 'i64>,>', '<,>', '>', ''],
                 [''] // the jit path wasn't taken (interpreter/baseline only).
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/ion-lazy-stubs-jit.js
@@ -0,0 +1,55 @@
+(function coerceinplace() {
+    var { table } = wasmEvalText(`(module
+        (func $add (result i32) (param i32) (param i32)
+         get_local 0
+        )
+        (table (export "table") 10 anyfunc)
+        (elem (i32.const 0) $add)
+    )`).exports;
+
+    for (var i = 0; i < 100; i++) {
+      table.get(0)((true).get++, i*2+1);
+    }
+})();
+
+(function reporti64() {
+    var instance = wasmEvalText(`(module
+        (func $add (export "add") (result i32) (param i32) (param i32)
+            get_local 0
+            get_local 1
+            i32.add
+        )
+
+        (func $addi64 (result i64) (param i32) (param i32)
+            get_local 0
+            get_local 1
+            call $add
+            i64.extend_s/i32
+        )
+
+        (table (export "table") 10 anyfunc)
+        (elem (i32.const 0) $add $addi64)
+    )`).exports;
+
+    const EXCEPTION_ITER = 50;
+
+    for (var i = 0; i < 100; i++) {
+        var caught = null;
+
+        var arr = [instance.add, (x,y)=>x+y];
+        if (i === EXCEPTION_ITER) {
+            arr[0] = instance.table.get(1);
+        } else if (i === EXCEPTION_ITER + 1) {
+            arr[0] = instance.add;
+        }
+
+        try {
+            arr[i%2](i, i);
+        } catch(e) {
+            caught = e;
+            print(e);
+        }
+
+        assertEq(!!caught, i === EXCEPTION_ITER);
+    }
+})();
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -409,17 +409,16 @@ BacktrackingAllocator::init()
 
     liveIn = mir->allocate<BitSet>(graph.numBlockIds());
     if (!liveIn)
         return false;
 
     size_t numVregs = graph.numVirtualRegisters();
     if (!vregs.init(mir->alloc(), numVregs))
         return false;
-    memset(&vregs[0], 0, sizeof(VirtualRegister) * numVregs);
     for (uint32_t i = 0; i < numVregs; i++)
         new(&vregs[i]) VirtualRegister();
 
     // Build virtual register objects.
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         if (mir->shouldCancel("Create data structures (main loop)"))
             return false;
 
@@ -1145,19 +1144,19 @@ BacktrackingAllocator::mergeAndQueueRegi
     // If there is an OSR block, merge parameters in that block with the
     // corresponding parameters in the initial block.
     if (MBasicBlock* osr = graph.mir().osrBlock()) {
         size_t original = 1;
         for (LInstructionIterator iter = osr->lir()->begin(); iter != osr->lir()->end(); iter++) {
             if (iter->isParameter()) {
                 for (size_t i = 0; i < iter->numDefs(); i++) {
                     DebugOnly<bool> found = false;
-                    VirtualRegister &paramVreg = vreg(iter->getDef(i));
+                    VirtualRegister& paramVreg = vreg(iter->getDef(i));
                     for (; original < paramVreg.vreg(); original++) {
-                        VirtualRegister &originalVreg = vregs[original];
+                        VirtualRegister& originalVreg = vregs[original];
                         if (*originalVreg.def()->output() == *iter->getDef(i)->output()) {
                             MOZ_ASSERT(originalVreg.ins()->isParameter());
                             if (!tryMergeBundles(originalVreg.firstBundle(), paramVreg.firstBundle()))
                                 return false;
                             found = true;
                             break;
                         }
                     }
@@ -1181,17 +1180,17 @@ BacktrackingAllocator::mergeAndQueueRegi
         }
     }
 
     // Try to merge phis with their inputs.
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         LBlock* block = graph.getBlock(i);
         for (size_t j = 0; j < block->numPhis(); j++) {
             LPhi* phi = block->getPhi(j);
-            VirtualRegister &outputVreg = vreg(phi->getDef(0));
+            VirtualRegister& outputVreg = vreg(phi->getDef(0));
             for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) {
                 VirtualRegister& inputVreg = vreg(phi->getOperand(k)->toUse());
                 if (!tryMergeBundles(inputVreg.firstBundle(), outputVreg.firstBundle()))
                     return false;
             }
         }
     }
 
@@ -1381,17 +1380,17 @@ BacktrackingAllocator::computeRequiremen
                                           Requirement *requirement, Requirement *hint)
 {
     // Set any requirement or hint on bundle according to its definition and
     // uses. Return false if there are conflicting requirements which will
     // require the bundle to be split.
 
     for (LiveRange::BundleLinkIterator iter = bundle->rangesBegin(); iter; iter++) {
         LiveRange* range = LiveRange::get(*iter);
-        VirtualRegister &reg = vregs[range->vreg()];
+        VirtualRegister& reg = vregs[range->vreg()];
 
         if (range->hasDefinition()) {
             // Deal with any definition constraints/hints.
             LDefinition::Policy policy = reg.def()->policy();
             if (policy == LDefinition::FIXED) {
                 // Fixed policies get a FIXED requirement.
                 JitSpew(JitSpew_RegAlloc, "  Requirement %s, fixed by definition",
                         reg.def()->output()->toString().get());
@@ -1443,17 +1442,17 @@ BacktrackingAllocator::tryAllocateRegist
 
     if (!r.allocatable)
         return true;
 
     LiveBundleVector aliasedConflicting;
 
     for (LiveRange::BundleLinkIterator iter = bundle->rangesBegin(); iter; iter++) {
         LiveRange* range = LiveRange::get(*iter);
-        VirtualRegister &reg = vregs[range->vreg()];
+        VirtualRegister& reg = vregs[range->vreg()];
 
         if (!reg.isCompatible(r.reg))
             return true;
 
         for (size_t a = 0; a < r.reg.numAliased(); a++) {
             PhysicalRegister& rAlias = registers[r.reg.aliased(a).code()];
             LiveRange* existing;
             if (!rAlias.allocations.contains(range, &existing))
--- a/js/src/jit/BacktrackingAllocator.h
+++ b/js/src/jit/BacktrackingAllocator.h
@@ -501,44 +501,41 @@ class LiveBundle : public TempObject
     UniqueChars toString() const;
 #endif
 };
 
 // Information about the allocation for a virtual register.
 class VirtualRegister
 {
     // Instruction which defines this register.
-    LNode* ins_;
+    LNode* ins_ = nullptr;
 
     // Definition in the instruction for this register.
-    LDefinition* def_;
+    LDefinition* def_ = nullptr;
 
     // All live ranges for this register. These may overlap each other, and are
     // ordered by their start position.
     InlineForwardList<LiveRange::RegisterLink> ranges_;
 
     // Whether def_ is a temp or an output.
-    bool isTemp_;
+    bool isTemp_ = false;
 
     // Whether this vreg is an input for some phi. This use is not reflected in
     // any range on the vreg.
-    bool usedByPhi_;
+    bool usedByPhi_ = false;
 
     // If this register's definition is MUST_REUSE_INPUT, whether a copy must
     // be introduced before the definition that relaxes the policy.
-    bool mustCopyInput_;
+    bool mustCopyInput_ = false;
 
     void operator=(const VirtualRegister&) = delete;
     VirtualRegister(const VirtualRegister&) = delete;
 
   public:
-    explicit VirtualRegister()
-    {
-        // Note: This class is zeroed before it is constructed.
-    }
+    VirtualRegister() = default;
 
     void init(LNode* ins, LDefinition* def, bool isTemp) {
         MOZ_ASSERT(!ins_);
         ins_ = ins;
         def_ = def;
         isTemp_ = isTemp;
     }
 
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -102,17 +102,17 @@ class CompileCompartment
     const void* addressOfRandomNumberGenerator();
 
     const JitCompartment* jitCompartment();
 
     const GlobalObject* maybeGlobal();
 
     bool hasAllocationMetadataBuilder();
 
-    // Mirror CompartmentOptions.
+    // Mirror RealmOptions.
     void setSingletonsAsValues();
 };
 
 class JitCompileOptions
 {
   public:
     JitCompileOptions();
     explicit JitCompileOptions(JSContext* cx);
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -4,17 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_IonCode_h
 #define jit_IonCode_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/PodOperations.h"
 
 #include "jstypes.h"
 
 #include "gc/Heap.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/ICStubSpace.h"
 #include "jit/IonOptimizationLevels.h"
 #include "jit/IonTypes.h"
@@ -672,27 +671,24 @@ struct IonBlockCounts
 };
 
 // Execution information for a compiled script which may persist after the
 // IonScript is destroyed, for use during profiling.
 struct IonScriptCounts
 {
   private:
     // Any previous invalidated compilation(s) for the script.
-    IonScriptCounts* previous_;
+    IonScriptCounts* previous_ = nullptr;
 
     // Information about basic blocks in this script.
-    size_t numBlocks_;
-    IonBlockCounts* blocks_;
+    size_t numBlocks_ = 0;
+    IonBlockCounts* blocks_ = nullptr;
 
   public:
-
-    IonScriptCounts() {
-        mozilla::PodZero(this);
-    }
+    IonScriptCounts() = default;
 
     ~IonScriptCounts() {
         for (size_t i = 0; i < numBlocks_; i++)
             blocks_[i].destroy();
         js_free(blocks_);
         // The list can be long in some corner cases (bug 1140084), so
         // unroll the recursion.
         IonScriptCounts* victims = previous_;
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -808,17 +808,17 @@ MacroAssembler::storeUnboxedProperty(Bas
                                      const ConstantOrRegister& value, Label* failure);
 
 // Inlined version of gc::CheckAllocatorState that checks the bare essentials
 // and bails for anything that cannot be handled with our jit allocators.
 void
 MacroAssembler::checkAllocatorState(Label* fail)
 {
     // Don't execute the inline path if we are tracing allocations.
-    if (js::gc::TraceEnabled())
+    if (js::gc::gcTracer.traceEnabled())
         jump(fail);
 
 #ifdef JS_GC_ZEAL
     // Don't execute the inline path if gc zeal or tracing are active.
     branch32(Assembler::NotEqual,
              AbsoluteAddress(GetJitContext()->runtime->addressOfGCZealModeBits()), Imm32(0),
              fail);
 #endif
@@ -1359,16 +1359,25 @@ MacroAssembler::initGCSlots(Register obj
         } else {
             fillSlotsWithUndefined(Address(obj, 0), temp, 0, ndynamic);
         }
 
         pop(obj);
     }
 }
 
+#ifdef JS_GC_TRACE
+static void
+TraceCreateObject(JSObject *obj)
+{
+    AutoUnsafeCallWithABI unsafe;
+    js::gc::gcTracer.traceCreateObject(obj);
+}
+#endif
+
 void
 MacroAssembler::initGCThing(Register obj, Register temp, const TemplateObject& templateObj,
                             bool initContents)
 {
     // Fast initialization of an empty object returned by allocateObject().
 
     storePtr(ImmGCPtr(templateObj.group()), Address(obj, JSObject::offsetOfGroup()));
 
@@ -1451,28 +1460,28 @@ MacroAssembler::initGCThing(Register obj
         storePtr(ImmPtr(nullptr), Address(obj, UnboxedPlainObject::offsetOfExpando()));
         if (initContents)
             initUnboxedObjectContents(obj, templateObj.unboxedObjectLayout());
     } else {
         MOZ_CRASH("Unknown object");
     }
 
 #ifdef JS_GC_TRACE
-    RegisterSet regs = RegisterSet::Volatile();
-    PushRegsInMask(regs);
+    AllocatableRegisterSet regs(RegisterSet::Volatile());
+    LiveRegisterSet save(regs.asLiveSet());
+    PushRegsInMask(save);
+
     regs.takeUnchecked(obj);
-    Register temp = regs.takeAnyGeneral();
-
-    setupUnalignedABICall(temp);
+    Register temp2 = regs.takeAnyGeneral();
+
+    setupUnalignedABICall(temp2);
     passABIArg(obj);
-    movePtr(ImmGCPtr(templateObj->type()), temp);
-    passABIArg(temp);
-    callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::gc::TraceCreateObject));
-
-    PopRegsInMask(RegisterSet::Volatile());
+    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceCreateObject));
+
+    PopRegsInMask(save);
 #endif
 }
 
 void
 MacroAssembler::initUnboxedObjectContents(Register object, const UnboxedLayout& layout)
 {
     // Initialize reference fields of the object, per UnboxedPlainObject::create.
     if (const int32_t* list = layout.traceList()) {
@@ -3164,17 +3173,17 @@ MacroAssembler::callWithABINoProfiler(vo
 
 #ifdef DEBUG
     if (check == CheckUnsafeCallWithABI::Check) {
         Label ok;
         push(ReturnReg);
         loadJSContext(ReturnReg);
         Address flagAddr(ReturnReg, JSContext::offsetOfInUnsafeCallWithABI());
         branch32(Assembler::Equal, flagAddr, Imm32(0), &ok);
-        assumeUnreachable("callWithABI: callee did not use AutoInUnsafeCallWithABI");
+        assumeUnreachable("callWithABI: callee did not use AutoUnsafeCallWithABI");
         bind(&ok);
         pop(ReturnReg);
     }
 #endif
 }
 
 void
 MacroAssembler::callWithABI(wasm::BytecodeOffset bytecode, wasm::SymbolicAddress imm,
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -12,16 +12,17 @@
 #include "jit/BaselineIC.h"
 #include "jit/JitCompartment.h"
 #include "jit/JitFrames.h"
 #include "jit/mips32/Simulator-mips32.h"
 #include "jit/mips64/Simulator-mips64.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
 #include "vm/TraceLogging.h"
 
 #include "jit/BaselineFrame-inl.h"
 #include "jit/JitFrames-inl.h"
 #include "vm/Debugger-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/StringObject-inl.h"
@@ -921,32 +922,24 @@ FinalSuspend(JSContext* cx, HandleObject
 }
 
 bool
 InterpretResume(JSContext* cx, HandleObject obj, HandleValue val, HandlePropertyName kind,
                 MutableHandleValue rval)
 {
     MOZ_ASSERT(obj->is<GeneratorObject>());
 
-    RootedValue selfHostedFun(cx);
-    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().InterpretGeneratorResume,
-                                         &selfHostedFun))
-    {
-        return false;
-    }
-
-    MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
-
     FixedInvokeArgs<3> args(cx);
 
     args[0].setObject(*obj);
     args[1].set(val);
     args[2].setString(kind);
 
-    return Call(cx, selfHostedFun, UndefinedHandleValue, args, rval);
+    return CallSelfHostedFunction(cx, cx->names().InterpretGeneratorResume, UndefinedHandleValue,
+                                  args, rval);
 }
 
 bool
 DebugAfterYield(JSContext* cx, BaselineFrame* frame)
 {
     // The BaselineFrame has just been constructed by JSOP_RESUME in the
     // caller. We need to set its debuggee flag as necessary.
     if (frame->script()->isDebuggee())
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -154,21 +154,21 @@ class Assembler : public AssemblerShared
     {
         MOZ_CRASH();
     }
 };
 
 class Operand
 {
   public:
-    Operand (const Address&) { MOZ_CRASH();}
-    Operand (const Register) { MOZ_CRASH();}
-    Operand (const FloatRegister) { MOZ_CRASH();}
-    Operand (Register, Imm32 ) { MOZ_CRASH(); }
-    Operand (Register, int32_t ) { MOZ_CRASH(); }
+    explicit Operand(const Address&) { MOZ_CRASH();}
+    explicit Operand(const Register) { MOZ_CRASH();}
+    explicit Operand(const FloatRegister) { MOZ_CRASH();}
+    explicit Operand(Register, Imm32) { MOZ_CRASH(); }
+    explicit Operand(Register, int32_t) { MOZ_CRASH(); }
 };
 
 class ScratchTagScope
 {
   public:
     ScratchTagScope(MacroAssembler&, const ValueOperand) {}
     operator Register() { MOZ_CRASH(); }
     void release() { MOZ_CRASH(); }
@@ -236,20 +236,20 @@ class MacroAssemblerNone : public Assemb
     CodeOffset toggledJump(Label*) { MOZ_CRASH(); }
     CodeOffset toggledCall(JitCode*, bool) { MOZ_CRASH(); }
     static size_t ToggledCallSize(uint8_t*) { MOZ_CRASH(); }
 
     void finish() { MOZ_CRASH(); }
 
     template <typename T, typename S> void moveValue(T, S) { MOZ_CRASH(); }
     template <typename T, typename S, typename U> void moveValue(T, S, U) { MOZ_CRASH(); }
-    template <typename T, typename S> void storeValue(T, S) { MOZ_CRASH(); }
+    template <typename T, typename S> void storeValue(const T&, const S&) { MOZ_CRASH(); }
     template <typename T, typename S, typename U> void storeValue(T, S, U) { MOZ_CRASH(); }
     template <typename T, typename S> void loadValue(T, S) { MOZ_CRASH(); }
-    template <typename T> void pushValue(T) { MOZ_CRASH(); }
+    template <typename T> void pushValue(const T&) { MOZ_CRASH(); }
     template <typename T, typename S> void pushValue(T, S) { MOZ_CRASH(); }
     void popValue(ValueOperand) { MOZ_CRASH(); }
     void tagValue(JSValueType, Register, ValueOperand) { MOZ_CRASH(); }
     void retn(Imm32 n) { MOZ_CRASH(); }
     template <typename T> void push(T) { MOZ_CRASH(); }
     template <typename T> void Push(T) { MOZ_CRASH(); }
     template <typename T> void pop(T) { MOZ_CRASH(); }
     template <typename T> void Pop(T) { MOZ_CRASH(); }
@@ -371,25 +371,25 @@ class MacroAssemblerNone : public Assemb
 
     void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); }
     bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
     void loadWasmGlobalPtr(uint32_t, Register) { MOZ_CRASH(); }
     void loadWasmPinnedRegsFromTls() { MOZ_CRASH(); }
 
     void setPrinter(Sprinter*) { MOZ_CRASH(); }
     Operand ToPayload(Operand base) { MOZ_CRASH(); }
+    Address ToPayload(Address) { MOZ_CRASH(); }
 
     static const Register getStackPointer() { MOZ_CRASH(); }
 
     // Instrumentation for entering and leaving the profiler.
     void profilerEnterFrame(Register , Register ) { MOZ_CRASH(); }
     void profilerExitFrame() { MOZ_CRASH(); }
 
 #ifdef JS_NUNBOX32
-    Address ToPayload(Address) { MOZ_CRASH(); }
     Address ToType(Address) { MOZ_CRASH(); }
 #endif
 };
 
 typedef MacroAssemblerNone MacroAssemblerSpecific;
 
 class ABIArgGenerator
 {
--- a/js/src/jit/none/MoveEmitter-none.h
+++ b/js/src/jit/none/MoveEmitter-none.h
@@ -11,17 +11,17 @@
 #include "jit/MoveResolver.h"
 
 namespace js {
 namespace jit {
 
 class MoveEmitterNone
 {
   public:
-    MoveEmitterNone(MacroAssemblerNone&) { MOZ_CRASH(); }
+    explicit MoveEmitterNone(MacroAssemblerNone&) { MOZ_CRASH(); }
     void emit(const MoveResolver&) { MOZ_CRASH(); }
     void finish() { MOZ_CRASH(); }
     void setScratchRegister(Register) { MOZ_CRASH(); }
 };
 
 typedef MoveEmitterNone MoveEmitter;
 
 } // namespace jit
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -3,17 +3,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_shared_Assembler_shared_h
 #define jit_shared_Assembler_shared_h
 
 #include "mozilla/CheckedInt.h"
-#include "mozilla/PodOperations.h"
 
 #include <limits.h>
 
 #include "jit/AtomicOp.h"
 #include "jit/JitAllocPolicy.h"
 #include "jit/Label.h"
 #include "jit/Registers.h"
 #include "jit/RegisterSets.h"
@@ -592,38 +591,36 @@ private:
 
 typedef Vector<CodeLabel, 0, SystemAllocPolicy> CodeLabelVector;
 
 // Location of a jump or label in a generated JitCode block, relative to the
 // start of the block.
 
 class CodeOffsetJump
 {
-    size_t offset_;
+    size_t offset_ = 0;
 
 #ifdef JS_SMALL_BRANCH
-    size_t jumpTableIndex_;
+    size_t jumpTableIndex_ = 0;
 #endif
 
   public:
 
 #ifdef JS_SMALL_BRANCH
     CodeOffsetJump(size_t offset, size_t jumpTableIndex)
         : offset_(offset), jumpTableIndex_(jumpTableIndex)
     {}
     size_t jumpTableIndex() const {
         return jumpTableIndex_;
     }
 #else
     explicit CodeOffsetJump(size_t offset) : offset_(offset) {}
 #endif
 
-    CodeOffsetJump() {
-        mozilla::PodZero(this);
-    }
+    CodeOffsetJump() = default;
 
     size_t offset() const {
         return offset_;
     }
     void fixup(MacroAssembler* masm);
 };
 
 // Absolute location of a jump or a label in some generated JitCode block.
--- a/js/src/jsapi-tests/testArrayBufferView.cpp
+++ b/js/src/jsapi-tests/testArrayBufferView.cpp
@@ -132,17 +132,17 @@ bool TestViewType(JSContext* cx)
         bool shared2;
         uint32_t len;
         CHECK(obj == GetObjectAs(obj, &len, &shared2, &data2));
         CHECK(data1 == data2);
         CHECK(shared1 == shared2);
         CHECK(len == ExpectedLength);
     }
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::RootedObject otherGlobal(cx, JS_NewGlobalObject(cx, basicGlobalClass(), nullptr,
                                                         JS::DontFireOnNewGlobalHook, options));
     CHECK(otherGlobal);
 
     JS::Rooted<JSObject*> buffer(cx);
     {
         AutoRealm ar(cx, otherGlobal);
         buffer = JS_NewArrayBuffer(cx, 8);
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -49,17 +49,17 @@ static const JSWrapObjectCallbacks WrapO
 BEGIN_TEST(testBug604087)
 {
     js::SetWindowProxyClass(cx, &OuterWrapperClass);
 
     js::WrapperOptions options;
     options.setClass(&OuterWrapperClass);
     options.setSingleton(true);
     JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, &js::Wrapper::singleton, options));
-    JS::CompartmentOptions globalOptions;
+    JS::RealmOptions globalOptions;
     JS::RootedObject compartment2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                                          JS::FireOnNewGlobalHook, globalOptions));
     CHECK(compartment2 != nullptr);
     JS::RootedObject compartment3(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                                          JS::FireOnNewGlobalHook, globalOptions));
     CHECK(compartment3 != nullptr);
     JS::RootedObject compartment4(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                                          JS::FireOnNewGlobalHook, globalOptions));
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -32,17 +32,17 @@ CustomMethod(JSContext* cx, unsigned arg
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod(cx, IsCustomClass, CustomMethodImpl, args);
 }
 
 BEGIN_TEST(test_CallNonGenericMethodOnProxy)
 {
   // Create the first global object and compartment
-  JS::CompartmentOptions options;
+  JS::RealmOptions options;
   JS::RootedObject globalA(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						  JS::FireOnNewGlobalHook, options));
   CHECK(globalA);
 
   JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass));
   CHECK(customA);
   JS_SetReservedSlot(customA, CUSTOM_SLOT, Int32Value(17));
 
@@ -52,17 +52,17 @@ BEGIN_TEST(test_CallNonGenericMethodOnPr
 
   JS::RootedValue rval(cx);
   CHECK(JS_CallFunction(cx, customA, customMethodA, JS::HandleValueArray::empty(),
                         &rval));
   CHECK_SAME(rval, Int32Value(17));
 
   // Now create the second global object and compartment...
   {
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						    JS::FireOnNewGlobalHook, options));
     CHECK(globalB);
 
     // ...and enter it.
     JSAutoRealm enter(cx, globalB);
     JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass));
     CHECK(customB);
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -44,17 +44,17 @@ CallTrusted(JSContext* cx, unsigned argc
     }
     return ok;
 }
 
 BEGIN_TEST(testChromeBuffer)
 {
     JS_SetTrustedPrincipals(cx, &system_principals);
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     trusted_glob.init(cx, JS_NewGlobalObject(cx, &global_class, &system_principals,
                                              JS::FireOnNewGlobalHook, options));
     CHECK(trusted_glob);
 
     JS::RootedFunction fun(cx);
 
     /*
      * Check that, even after untrusted content has exhausted the stack, code
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -9,17 +9,17 @@
 #include "vm/JSContext.h"
 
 using namespace js;
 
 BEGIN_TEST(testDebugger_newScriptHook)
 {
     // Test that top-level indirect eval fires the newScript hook.
     CHECK(JS_DefineDebuggerObject(cx, global));
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                               JS::FireOnNewGlobalHook, options));
     CHECK(g);
     {
         JSAutoRealm ae(cx, g);
         CHECK(JS_InitStandardClasses(cx, g));
     }
 
--- a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
+++ b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
@@ -23,17 +23,17 @@ BEGIN_TEST(testRedefineGlobalEval)
     };
 
     static const JSClass cls = {
         "global", JSCLASS_GLOBAL_FLAGS,
         &clsOps
     };
 
     /* Create the global object. */
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::Rooted<JSObject*> g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options));
     if (!g)
         return false;
 
     JSAutoRealm ar(cx, g);
     JS::Rooted<JS::Value> v(cx);
     CHECK(JS_GetProperty(cx, g, "Object", &v));
 
--- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp
+++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp
@@ -127,17 +127,17 @@ BEGIN_TEST(testGCFinalizeCallback)
     CHECK(JS_IsGlobalObject(global2));
     CHECK(JS_IsGlobalObject(global3));
 
     return true;
 }
 
 JSObject* createTestGlobal()
 {
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     return JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook, options);
 }
 
 virtual bool init() override
 {
     if (!JSAPITest::init())
         return false;
 
--- a/js/src/jsapi-tests/testGCMarking.cpp
+++ b/js/src/jsapi-tests/testGCMarking.cpp
@@ -18,17 +18,17 @@ ConstructCCW(JSContext* cx, const JSClas
              JS::MutableHandleObject global2, JS::MutableHandleObject wrappee)
 {
     if (!global1) {
         fprintf(stderr, "null initial global");
         return false;
     }
 
     // Define a second global in a different zone.
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     global2.set(JS_NewGlobalObject(cx, globalClasp, nullptr,
                                    JS::FireOnNewGlobalHook, options));
     if (!global2) {
         fprintf(stderr, "failed to create second global");
         return false;
     }
 
     // This should always be false, regardless.
--- a/js/src/jsapi-tests/testMutedErrors.cpp
+++ b/js/src/jsapi-tests/testMutedErrors.cpp
@@ -37,17 +37,17 @@ bool
 eval(const char* asciiChars, bool mutedErrors, JS::MutableHandleValue rval)
 {
     size_t len = strlen(asciiChars);
     mozilla::UniquePtr<char16_t[]> chars(new char16_t[len+1]);
     for (size_t i = 0; i < len; ++i)
         chars[i] = asciiChars[i];
     chars[len] = 0;
 
-    JS::CompartmentOptions globalOptions;
+    JS::RealmOptions globalOptions;
     JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						   JS::FireOnNewGlobalHook, globalOptions));
     CHECK(global);
     JSAutoRealm ar(cx, global);
     CHECK(JS_InitStandardClasses(cx, global));
 
 
     JS::CompileOptions options(cx);
--- a/js/src/jsapi-tests/testPreserveJitCode.cpp
+++ b/js/src/jsapi-tests/testPreserveJitCode.cpp
@@ -80,13 +80,13 @@ testPreserveJitCode(bool preserveJitCode
     CHECK_EQUAL(countIonScripts(global), 0u);
 
     return true;
 }
 
 JSObject*
 createTestGlobal(bool preserveJitCode)
 {
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     options.creationOptions().setPreserveJitCode(preserveJitCode);
     return JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook, options);
 }
 END_TEST(test_PreserveJitCode)
--- a/js/src/jsapi-tests/testSourcePolicy.cpp
+++ b/js/src/jsapi-tests/testSourcePolicy.cpp
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 #include "vm/JSScript.h"
 
 BEGIN_TEST(testBug795104)
 {
     JS::CompileOptions opts(cx);
-    JS::CompartmentBehaviorsRef(cx->compartment()).setDiscardSource(true);
+    JS::RealmBehaviorsRef(cx->compartment()).setDiscardSource(true);
 
     const size_t strLen = 60002;
     char* s = static_cast<char*>(JS_malloc(cx, strLen));
     CHECK(s);
 
     s[0] = '"';
     memset(s + 1, 'x', strLen - 2);
     s[strLen - 1] = '"';
--- a/js/src/jsapi-tests/testStructuredClone.cpp
+++ b/js/src/jsapi-tests/testStructuredClone.cpp
@@ -260,17 +260,17 @@ BEGIN_TEST(testStructuredClone_SavedFram
         { "DONE", DONE }
     };
 
     const char* FILENAME = "filename.js";
 
     for (auto* pp = principalsToTest; pp->principals != DONE; pp++) {
         fprintf(stderr, "Testing with principals '%s'\n", pp->name);
 
-	JS::CompartmentOptions options;
+        JS::RealmOptions options;
         JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), pp->principals,
                                                   JS::FireOnNewGlobalHook, options));
         CHECK(g);
         JSAutoRealm ar(cx, g);
 
         CHECK(js::DefineTestingFunctions(cx, g, false, false));
 
         JS::RootedValue srcVal(cx);
--- a/js/src/jsapi-tests/testUbiNode.cpp
+++ b/js/src/jsapi-tests/testUbiNode.cpp
@@ -70,17 +70,17 @@ const char16_t Concrete<FakeNode>::concr
 
 // ubi::Node::zone works
 BEGIN_TEST(test_ubiNodeZone)
 {
     RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
     CHECK(global1);
     CHECK(JS::ubi::Node(global1).zone() == cx->zone());
 
-    JS::CompartmentOptions globalOptions;
+    JS::RealmOptions globalOptions;
     RootedObject global2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                                 JS::FireOnNewGlobalHook, globalOptions));
     CHECK(global2);
     CHECK(global1->zone() != global2->zone());
     CHECK(JS::ubi::Node(global2).zone() == global2->zone());
     CHECK(JS::ubi::Node(global2).zone() != global1->zone());
 
     JS::CompileOptions options(cx);
@@ -114,17 +114,17 @@ END_TEST(test_ubiNodeZone)
 
 // ubi::Node::compartment works
 BEGIN_TEST(test_ubiNodeCompartment)
 {
     RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
     CHECK(global1);
     CHECK(JS::ubi::Node(global1).compartment() == cx->compartment());
 
-    JS::CompartmentOptions globalOptions;
+    JS::RealmOptions globalOptions;
     RootedObject global2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                                 JS::FireOnNewGlobalHook, globalOptions));
     CHECK(global2);
     CHECK(global1->compartment() != global2->compartment());
     CHECK(JS::ubi::Node(global2).compartment() == global2->compartment());
     CHECK(JS::ubi::Node(global2).compartment() != global1->compartment());
 
     JS::CompileOptions options(cx);
--- a/js/src/jsapi-tests/testWeakMap.cpp
+++ b/js/src/jsapi-tests/testWeakMap.cpp
@@ -229,17 +229,17 @@ JSObject* newDelegate()
         JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1),
         &delegateClassOps,
         JS_NULL_CLASS_SPEC,
         &delegateClassExtension,
         JS_NULL_OBJECT_OPS
     };
 
     /* Create the global object. */
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     JS::RootedObject global(cx, JS_NewGlobalObject(cx, Jsvalify(&delegateClass), nullptr,
                                                    JS::FireOnNewGlobalHook, options));
     if (!global)
         return nullptr;
 
     JS_SetReservedSlot(global, 0, JS::Int32Value(42));
     return global;
 }
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -21,28 +21,28 @@ bool JSAPITest::init()
     js::UseInternalJobQueues(cx);
     if (!JS::InitSelfHostedCode(cx))
         return false;
     JS_BeginRequest(cx);
     global.init(cx);
     createGlobal();
     if (!global)
         return false;
-    JS_EnterCompartment(cx, global);
+    JS::EnterRealm(cx, global);
     return true;
 }
 
 void JSAPITest::uninit()
 {
     if (oldCompartment) {
-        JS_LeaveCompartment(cx, oldCompartment);
+        JS::LeaveRealm(cx, oldCompartment);
         oldCompartment = nullptr;
     }
     if (global) {
-        JS_LeaveCompartment(cx, nullptr);
+        JS::LeaveRealm(cx, nullptr);
         global = nullptr;
     }
     if (cx) {
         JS_EndRequest(cx);
         destroyContext();
         cx = nullptr;
     }
     msgs.clear();
@@ -78,17 +78,17 @@ bool JSAPITest::definePrint()
 {
     return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0);
 }
 
 JSObject* JSAPITest::createGlobal(JSPrincipals* principals)
 {
     /* Create the global object. */
     JS::RootedObject newGlobal(cx);
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
 #ifdef ENABLE_STREAMS
     options.creationOptions().setStreamsEnabled(true);
 #endif
     newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook,
                                    options);
     if (!newGlobal)
         return nullptr;
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -670,32 +670,32 @@ JS_SetWrapObjectCallbacks(JSContext* cx,
 
 JS_PUBLIC_API(void)
 JS_SetExternalStringSizeofCallback(JSContext* cx, JSExternalStringSizeofCallback callback)
 {
     cx->runtime()->externalStringSizeofCallback = callback;
 }
 
 JS_PUBLIC_API(JSCompartment*)
-JS_EnterCompartment(JSContext* cx, JSObject* target)
+JS::EnterRealm(JSContext* cx, JSObject* target)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
     JSCompartment* oldCompartment = cx->compartment();
     cx->enterCompartmentOf(target);
     return oldCompartment;
 }
 
 JS_PUBLIC_API(void)
-JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    cx->leaveCompartment(oldCompartment);
+JS::LeaveRealm(JSContext* cx, JSCompartment* oldRealm)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    cx->leaveCompartment(oldRealm);
 }
 
 JSAutoRealm::JSAutoRealm(JSContext* cx, JSObject* target
                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : cx_(cx),
     oldCompartment_(cx->compartment())
 {
     AssertHeapIsIdleOrIterating();
@@ -1305,24 +1305,16 @@ JS_ExtensibleLexicalEnvironment(JSObject
         lexical = JS_GlobalLexicalEnvironment(obj);
     else
         lexical = obj->compartment()->getNonSyntacticLexicalEnvironment(obj);
     MOZ_ASSERT(lexical);
     return lexical;
 }
 
 JS_PUBLIC_API(JSObject*)
-JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c)
-{
-    AssertHeapIsIdleOrIterating();
-    assertSameCompartment(cx, c);
-    return c->maybeGlobal();
-}
-
-JS_PUBLIC_API(JSObject*)
 JS::CurrentGlobalOrNull(JSContext* cx)
 {
     AssertHeapIsIdleOrIterating();
     CHECK_REQUEST(cx);
     if (!cx->compartment())
         return nullptr;
     return cx->global();
 }
@@ -1840,104 +1832,104 @@ JS_GetConstructor(JSContext* cx, HandleO
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
                                   proto->getClass()->name);
         return nullptr;
     }
     return &cval.toObject();
 }
 
 bool
-JS::CompartmentBehaviors::extraWarnings(JSContext* cx) const
+JS::RealmBehaviors::extraWarnings(JSContext* cx) const
 {
     return extraWarningsOverride_.get(cx->options().extraWarnings());
 }
 
-JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptions::setSystemZone()
+JS::RealmCreationOptions&
+JS::RealmCreationOptions::setSystemZone()
 {
     zoneSpec_ = JS::SystemZone;
     zone_ = nullptr;
     return *this;
 }
 
-JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptions::setExistingZone(JSObject* obj)
+JS::RealmCreationOptions&
+JS::RealmCreationOptions::setExistingZone(JSObject* obj)
 {
     zoneSpec_ = JS::ExistingZone;
     zone_ = obj->zone();
     return *this;
 }
 
-JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptions::setNewZone()
+JS::RealmCreationOptions&
+JS::RealmCreationOptions::setNewZone()
 {
     zoneSpec_ = JS::NewZone;
     zone_ = nullptr;
     return *this;
 }
 
-const JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptionsRef(JSCompartment* compartment)
+const JS::RealmCreationOptions&
+JS::RealmCreationOptionsRef(JSCompartment* compartment)
 {
     return compartment->creationOptions();
 }
 
-const JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptionsRef(JSObject* obj)
+const JS::RealmCreationOptions&
+JS::RealmCreationOptionsRef(JSObject* obj)
 {
     return obj->compartment()->creationOptions();
 }
 
-const JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptionsRef(JSContext* cx)
+const JS::RealmCreationOptions&
+JS::RealmCreationOptionsRef(JSContext* cx)
 {
     return cx->compartment()->creationOptions();
 }
 
 bool
-JS::CompartmentCreationOptions::getSharedMemoryAndAtomicsEnabled() const
+JS::RealmCreationOptions::getSharedMemoryAndAtomicsEnabled() const
 {
 #if defined(ENABLE_SHARED_ARRAY_BUFFER)
     return sharedMemoryAndAtomics_;
 #else
     return false;
 #endif
 }
 
-JS::CompartmentCreationOptions&
-JS::CompartmentCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag)
+JS::RealmCreationOptions&
+JS::RealmCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag)
 {
 #if defined(ENABLE_SHARED_ARRAY_BUFFER)
     sharedMemoryAndAtomics_ = flag;
 #endif
     return *this;
 }
 
-JS::CompartmentBehaviors&
-JS::CompartmentBehaviorsRef(JSCompartment* compartment)
+JS::RealmBehaviors&
+JS::RealmBehaviorsRef(JSCompartment* compartment)
 {
     return compartment->behaviors();
 }
 
-JS::CompartmentBehaviors&
-JS::CompartmentBehaviorsRef(JSObject* obj)
+JS::RealmBehaviors&
+JS::RealmBehaviorsRef(JSObject* obj)
 {
     return obj->compartment()->behaviors();
 }
 
-JS::CompartmentBehaviors&
-JS::CompartmentBehaviorsRef(JSContext* cx)
+JS::RealmBehaviors&
+JS::RealmBehaviorsRef(JSContext* cx)
 {
     return cx->compartment()->behaviors();
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals,
                    JS::OnNewGlobalHookOption hookOption,
-                   const JS::CompartmentOptions& options)
+                   const JS::RealmOptions& options)
 {
     MOZ_RELEASE_ASSERT(cx->runtime()->hasInitializedSelfHosting(),
                        "Must call JS::InitSelfHostedCode() before creating a global");
 
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
     return GlobalObject::new_(cx, Valueify(clasp), principals, hookOption, options);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -74,17 +74,17 @@ template <size_t N>
 class MOZ_RAII AutoValueArray : public AutoGCRooter
 {
     const size_t length_;
     Value elements_[N];
 
   public:
     explicit AutoValueArray(JSContext* cx
                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, VALARRAY), length_(N)
+      : AutoGCRooter(cx, AutoGCRooter::Tag::ValueArray), length_(N)
     {
         /* Always initialize in case we GC before assignment. */
         mozilla::PodArrayZero(elements_);
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     unsigned length() const { return length_; }
     const Value* begin() const { return elements_; }
@@ -102,250 +102,25 @@ class MOZ_RAII AutoValueArray : public A
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 using ValueVector = JS::GCVector<JS::Value>;
 using IdVector = JS::GCVector<jsid>;
 using ScriptVector = JS::GCVector<JSScript*>;
 using StringVector = JS::GCVector<JSString*>;
 
-template<class Key, class Value>
-class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter
-{
-  private:
-    typedef js::HashMap<Key, Value> HashMapImpl;
-
-  public:
-    explicit AutoHashMapRooter(JSContext* cx, ptrdiff_t tag
-                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, tag), map(cx)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    typedef Key KeyType;
-    typedef Value ValueType;
-    typedef typename HashMapImpl::Entry Entry;
-    typedef typename HashMapImpl::Lookup Lookup;
-    typedef typename HashMapImpl::Ptr Ptr;
-    typedef typename HashMapImpl::AddPtr AddPtr;
-
-    bool init(uint32_t len = 16) {
-        return map.init(len);
-    }
-    bool initialized() const {
-        return map.initialized();
-    }
-    Ptr lookup(const Lookup& l) const {
-        return map.lookup(l);
-    }
-    void remove(Ptr p) {
-        map.remove(p);
-    }
-    AddPtr lookupForAdd(const Lookup& l) const {
-        return map.lookupForAdd(l);
-    }
-
-    template<typename KeyInput, typename ValueInput>
-    bool add(AddPtr& p, const KeyInput& k, const ValueInput& v) {
-        return map.add(p, k, v);
-    }
-
-    bool add(AddPtr& p, const Key& k) {
-        return map.add(p, k);
-    }
-
-    template<typename KeyInput, typename ValueInput>
-    bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) {
-        return map.relookupOrAdd(p, k, v);
-    }
-
-    typedef typename HashMapImpl::Range Range;
-    Range all() const {
-        return map.all();
-    }
-
-    typedef typename HashMapImpl::Enum Enum;
-
-    void clear() {
-        map.clear();
-    }
-
-    void finish() {
-        map.finish();
-    }
-
-    bool empty() const {
-        return map.empty();
-    }
-
-    uint32_t count() const {
-        return map.count();
-    }
-
-    size_t capacity() const {
-        return map.capacity();
-    }
-
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return map.sizeOfExcludingThis(mallocSizeOf);
-    }
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return map.sizeOfIncludingThis(mallocSizeOf);
-    }
-
-    /************************************************** Shorthand operations */
-
-    bool has(const Lookup& l) const {
-        return map.has(l);
-    }
-
-    template<typename KeyInput, typename ValueInput>
-    bool put(const KeyInput& k, const ValueInput& v) {
-        return map.put(k, v);
-    }
-
-    template<typename KeyInput, typename ValueInput>
-    bool putNew(const KeyInput& k, const ValueInput& v) {
-        return map.putNew(k, v);
-    }
-
-    Ptr lookupWithDefault(const Key& k, const Value& defaultValue) {
-        return map.lookupWithDefault(k, defaultValue);
-    }
-
-    void remove(const Lookup& l) {
-        map.remove(l);
-    }
-
-    friend void AutoGCRooter::trace(JSTracer* trc);
-
-  private:
-    AutoHashMapRooter(const AutoHashMapRooter& hmr) = delete;
-    AutoHashMapRooter& operator=(const AutoHashMapRooter& hmr) = delete;
-
-    HashMapImpl map;
-
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-template<class T>
-class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter
-{
-  private:
-    typedef js::HashSet<T> HashSetImpl;
-
-  public:
-    explicit AutoHashSetRooter(JSContext* cx, ptrdiff_t tag
-                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, tag), set(cx)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    typedef typename HashSetImpl::Lookup Lookup;
-    typedef typename HashSetImpl::Ptr Ptr;
-    typedef typename HashSetImpl::AddPtr AddPtr;
-
-    bool init(uint32_t len = 16) {
-        return set.init(len);
-    }
-    bool initialized() const {
-        return set.initialized();
-    }
-    Ptr lookup(const Lookup& l) const {
-        return set.lookup(l);
-    }
-    void remove(Ptr p) {
-        set.remove(p);
-    }
-    AddPtr lookupForAdd(const Lookup& l) const {
-        return set.lookupForAdd(l);
-    }
-
-    bool add(AddPtr& p, const T& t) {
-        return set.add(p, t);
-    }
-
-    bool relookupOrAdd(AddPtr& p, const Lookup& l, const T& t) {
-        return set.relookupOrAdd(p, l, t);
-    }
-
-    typedef typename HashSetImpl::Range Range;
-    Range all() const {
-        return set.all();
-    }
-
-    typedef typename HashSetImpl::Enum Enum;
-
-    void clear() {
-        set.clear();
-    }
-
-    void finish() {
-        set.finish();
-    }
-
-    bool empty() const {
-        return set.empty();
-    }
-
-    uint32_t count() const {
-        return set.count();
-    }
-
-    size_t capacity() const {
-        return set.capacity();
-    }
-
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return set.sizeOfExcludingThis(mallocSizeOf);
-    }
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return set.sizeOfIncludingThis(mallocSizeOf);
-    }
-
-    /************************************************** Shorthand operations */
-
-    bool has(const Lookup& l) const {
-        return set.has(l);
-    }
-
-    bool put(const T& t) {
-        return set.put(t);
-    }
-
-    bool putNew(const T& t) {
-        return set.putNew(t);
-    }
-
-    void remove(const Lookup& l) {
-        set.remove(l);
-    }
-
-    friend void AutoGCRooter::trace(JSTracer* trc);
-
-  private:
-    AutoHashSetRooter(const AutoHashSetRooter& hmr) = delete;
-    AutoHashSetRooter& operator=(const AutoHashSetRooter& hmr) = delete;
-
-    HashSetImpl set;
-
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 /**
  * Custom rooting behavior for internal and external clients.
  */
 class MOZ_RAII JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter
 {
   public:
     template <typename CX>
     explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, CUSTOM)
+      : AutoGCRooter(cx, AutoGCRooter::Tag::Custom)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     friend void AutoGCRooter::trace(JSTracer* trc);
 
   protected:
     virtual ~CustomAutoRooter() {}
@@ -1265,27 +1040,27 @@ JS_RefreshCrossCompartmentWrappers(JSCon
  *     }                                 // destructor leaves
  *     // back in realm 'r'
  *   }
  *
  * For more complicated uses that don't neatly fit in a C++ stack frame, the
  * realm can be entered and left using separate function calls:
  *
  *   void foo(JSContext* cx, JSObject* obj) {
- *     // in 'oldCompartment'
- *     JSCompartment* oldCompartment = JS_EnterCompartment(cx, obj);
- *     // in the compartment of 'obj'
- *     JS_LeaveCompartment(cx, oldCompartment);
- *     // back in 'oldCompartment'
+ *     // in 'oldRealm'
+ *     JSCompartment* oldRealm = JS::EnterRealm(cx, obj);
+ *     // in the realm of 'obj'
+ *     JS::LeaveRealm(cx, oldRealm);
+ *     // back in 'oldRealm'
  *   }
  *
  * Note: these calls must still execute in a LIFO manner w.r.t all other
  * enter/leave calls on the context. Furthermore, only the return value of a
- * JS_EnterCompartment call may be passed as the 'oldCompartment' argument of
- * the corresponding JS_LeaveCompartment call.
+ * JS::EnterRealm call may be passed as the 'oldRealm' argument of
+ * the corresponding JS::LeaveRealm call.
  *
  * Entering a realm roots the realm and its global object for the lifetime of
  * the JSAutoRealm.
  */
 
 class MOZ_RAII JS_PUBLIC_API(JSAutoRealm)
 {
     JSContext* cx_;
@@ -1305,26 +1080,30 @@ class MOZ_RAII JS_PUBLIC_API(JSAutoNulla
   public:
     explicit JSAutoNullableRealm(JSContext* cx, JSObject* targetOrNull
                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     ~JSAutoNullableRealm();
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+namespace JS {
+
 /** NB: This API is infallible; a nullptr return value does not indicate error.
  *
  * Entering a compartment roots the compartment and its global object until the
- * matching JS_LeaveCompartment() call.
+ * matching JS::LeaveRealm() call.
  */
 extern JS_PUBLIC_API(JSCompartment*)
-JS_EnterCompartment(JSContext* cx, JSObject* target);
+EnterRealm(JSContext* cx, JSObject* target);
 
 extern JS_PUBLIC_API(void)
-JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment);
+LeaveRealm(JSContext* cx, JSCompartment* oldRealm);
+
+} // namespace JS
 
 typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, JSCompartment* compartment);
 
 /**
  * This function calls |compartmentCallback| on every compartment. Beware that
  * there is no guarantee that the compartment will survive after the callback
  * returns. Also, barriers are disabled via the TraceSession.
  */
@@ -1463,23 +1242,16 @@ extern JS_PUBLIC_API(JSObject*)
 JS_GlobalLexicalEnvironment(JSObject* obj);
 
 extern JS_PUBLIC_API(bool)
 JS_HasExtensibleLexicalEnvironment(JSObject* obj);
 
 extern JS_PUBLIC_API(JSObject*)
 JS_ExtensibleLexicalEnvironment(JSObject* obj);
 
-/**
- * May return nullptr, if |c| never had a global (e.g. the atoms compartment),
- * or if |c|'s global has been collected.
- */
-extern JS_PUBLIC_API(JSObject*)
-JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c);
-
 namespace JS {
 
 extern JS_PUBLIC_API(JSObject*)
 CurrentGlobalOrNull(JSContext* cx);
 
 } // namespace JS
 
 /**
@@ -1942,104 +1714,104 @@ enum ZoneSpecifier {
     // Use a particular existing zone.
     ExistingZone,
 
     // Create a new zone.
     NewZone
 };
 
 /**
- * CompartmentCreationOptions specifies options relevant to creating a new
- * compartment, that are either immutable characteristics of that compartment
- * or that are discarded after the compartment has been created.
- *
- * Access to these options on an existing compartment is read-only: if you
- * need particular selections, make them before you create the compartment.
- */
-class JS_PUBLIC_API(CompartmentCreationOptions)
+ * RealmCreationOptions specifies options relevant to creating a new realm, that
+ * are either immutable characteristics of that realm or that are discarded
+ * after the realm has been created.
+ *
+ * Access to these options on an existing realm is read-only: if you need
+ * particular selections, make them before you create the realm.
+ */
+class JS_PUBLIC_API(RealmCreationOptions)
 {
   public:
-    CompartmentCreationOptions()
+    RealmCreationOptions()
       : traceGlobal_(nullptr),
         zoneSpec_(NewZone),
         zone_(nullptr),
         invisibleToDebugger_(false),
         mergeable_(false),
         preserveJitCode_(false),
         cloneSingletons_(false),
         sharedMemoryAndAtomics_(false),
         secureContext_(false),
         clampAndJitterTime_(true)
     {}
 
     JSTraceOp getTrace() const {
         return traceGlobal_;
     }
-    CompartmentCreationOptions& setTrace(JSTraceOp op) {
+    RealmCreationOptions& setTrace(JSTraceOp op) {
         traceGlobal_ = op;
         return *this;
     }
 
     JS::Zone* zone() const { return zone_; }
     ZoneSpecifier zoneSpecifier() const { return zoneSpec_; }
 
-    // Set the zone to use for the compartment. See ZoneSpecifier above.
-    CompartmentCreationOptions& setSystemZone();
-    CompartmentCreationOptions& setExistingZone(JSObject* obj);
-    CompartmentCreationOptions& setNewZone();
+    // Set the zone to use for the realm. See ZoneSpecifier above.
+    RealmCreationOptions& setSystemZone();
+    RealmCreationOptions& setExistingZone(JSObject* obj);
+    RealmCreationOptions& setNewZone();
 
     // Certain scopes (i.e. XBL compilation scopes) are implementation details
     // of the embedding, and references to them should never leak out to script.
-    // This flag causes the this compartment to skip firing onNewGlobalObject
-    // and makes addDebuggee a no-op for this global.
+    // This flag causes the this realm to skip firing onNewGlobalObject and
+    // makes addDebuggee a no-op for this global.
     bool invisibleToDebugger() const { return invisibleToDebugger_; }
-    CompartmentCreationOptions& setInvisibleToDebugger(bool flag) {
+    RealmCreationOptions& setInvisibleToDebugger(bool flag) {
         invisibleToDebugger_ = flag;
         return *this;
     }
 
-    // Compartments used for off-thread compilation have their contents merged
-    // into a target compartment when the compilation is finished. This is only
-    // allowed if this flag is set. The invisibleToDebugger flag must also be
-    // set for such compartments.
+    // Realms used for off-thread compilation have their contents merged into a
+    // target realm when the compilation is finished. This is only allowed if
+    // this flag is set. The invisibleToDebugger flag must also be set for such
+    // realms.
     bool mergeable() const { return mergeable_; }
-    CompartmentCreationOptions& setMergeable(bool flag) {
+    RealmCreationOptions& setMergeable(bool flag) {
         mergeable_ = flag;
         return *this;
     }
 
-    // Determines whether this compartment should preserve JIT code on
-    // non-shrinking GCs.
+    // Determines whether this realm should preserve JIT code on non-shrinking
+    // GCs.
     bool preserveJitCode() const { return preserveJitCode_; }
-    CompartmentCreationOptions& setPreserveJitCode(bool flag) {
+    RealmCreationOptions& setPreserveJitCode(bool flag) {
         preserveJitCode_ = flag;
         return *this;
     }
 
     bool cloneSingletons() const { return cloneSingletons_; }
-    CompartmentCreationOptions& setCloneSingletons(bool flag) {
+    RealmCreationOptions& setCloneSingletons(bool flag) {
         cloneSingletons_ = flag;
         return *this;
     }
 
     bool getSharedMemoryAndAtomicsEnabled() const;
-    CompartmentCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag);
+    RealmCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag);
 
     // This flag doesn't affect JS engine behavior.  It is used by Gecko to
     // mark whether content windows and workers are "Secure Context"s. See
     // https://w3c.github.io/webappsec-secure-contexts/
     // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34
     bool secureContext() const { return secureContext_; }
-    CompartmentCreationOptions& setSecureContext(bool flag) {
+    RealmCreationOptions& setSecureContext(bool flag) {
         secureContext_ = flag;
         return *this;
     }
 
     bool clampAndJitterTime() const { return clampAndJitterTime_; }
-    CompartmentCreationOptions& setClampAndJitterTime(bool flag) {
+    RealmCreationOptions& setClampAndJitterTime(bool flag) {
         clampAndJitterTime_ = flag;
         return *this;
     }
 
   private:
     JSTraceOp traceGlobal_;
     ZoneSpecifier zoneSpec_;
     JS::Zone* zone_;
@@ -2048,20 +1820,20 @@ class JS_PUBLIC_API(CompartmentCreationO
     bool preserveJitCode_;
     bool cloneSingletons_;
     bool sharedMemoryAndAtomics_;
     bool secureContext_;
     bool clampAndJitterTime_;
 };
 
 /**
- * CompartmentBehaviors specifies behaviors of a compartment that can be
- * changed after the compartment's been created.
- */
-class JS_PUBLIC_API(CompartmentBehaviors)
+ * RealmBehaviors specifies behaviors of a realm that can be changed after the
+ * realm's been created.
+ */
+class JS_PUBLIC_API(RealmBehaviors)
 {
   public:
     class Override {
       public:
         Override() : mode_(Default) {}
 
         bool get(bool defaultValue) const {
             if (mode_ == Default)
@@ -2082,120 +1854,118 @@ class JS_PUBLIC_API(CompartmentBehaviors
             Default,
             ForceTrue,
             ForceFalse
         };
 
         Mode mode_;
     };
 
-    CompartmentBehaviors()
+    RealmBehaviors()
       : discardSource_(false)
       , disableLazyParsing_(false)
       , singletonsAsTemplates_(true)
     {
     }
 
     // For certain globals, we know enough about the code that will run in them
     // that we can discard script source entirely.
     bool discardSource() const { return discardSource_; }
-    CompartmentBehaviors& setDiscardSource(bool flag) {
+    RealmBehaviors& setDiscardSource(bool flag) {
         discardSource_ = flag;
         return *this;
     }
 
     bool disableLazyParsing() const { return disableLazyParsing_; }
-    CompartmentBehaviors& setDisableLazyParsing(bool flag) {
+    RealmBehaviors& setDisableLazyParsing(bool flag) {
         disableLazyParsing_ = flag;
         return *this;
     }
 
     bool extraWarnings(JSContext* cx) const;
     Override& extraWarningsOverride() { return extraWarningsOverride_; }
 
     bool getSingletonsAsTemplates() const {
         return singletonsAsTemplates_;
     }
-    CompartmentBehaviors& setSingletonsAsValues() {
+    RealmBehaviors& setSingletonsAsValues() {
         singletonsAsTemplates_ = false;
         return *this;
     }
 
   private:
     bool discardSource_;
     bool disableLazyParsing_;
     Override extraWarningsOverride_;
 
     // To XDR singletons, we need to ensure that all singletons are all used as
     // templates, by making JSOP_OBJECT return a clone of the JSScript
     // singleton, instead of returning the value which is baked in the JSScript.
     bool singletonsAsTemplates_;
 };
 
 /**
- * CompartmentOptions specifies compartment characteristics: both those that
- * can't be changed on a compartment once it's been created
- * (CompartmentCreationOptions), and those that can be changed on an existing
- * compartment (CompartmentBehaviors).
- */
-class JS_PUBLIC_API(CompartmentOptions)
+ * RealmOptions specifies realm characteristics: both those that can't be
+ * changed on a realm once it's been created (RealmCreationOptions), and those
+ * that can be changed on an existing realm (RealmBehaviors).
+ */
+class JS_PUBLIC_API(RealmOptions)
 {
   public:
-    explicit CompartmentOptions()
+    explicit RealmOptions()
       : creationOptions_(),
         behaviors_()
     {}
 
-    CompartmentOptions(const CompartmentCreationOptions& compartmentCreation,
-                       const CompartmentBehaviors& compartmentBehaviors)
-      : creationOptions_(compartmentCreation),
-        behaviors_(compartmentBehaviors)
+    RealmOptions(const RealmCreationOptions& realmCreation, const RealmBehaviors& realmBehaviors)
+      : creationOptions_(realmCreation),
+        behaviors_(realmBehaviors)
     {}
 
-    // CompartmentCreationOptions specify fundamental compartment
-    // characteristics that must be specified when the compartment is created,
-    // that can't be changed after the compartment is created.
-    CompartmentCreationOptions& creationOptions() {
+    // RealmCreationOptions specify fundamental realm characteristics that must
+    // be specified when the realm is created, that can't be changed after the
+    // realm is created.
+    RealmCreationOptions& creationOptions() {
         return creationOptions_;
     }
-    const CompartmentCreationOptions& creationOptions() const {
+    const RealmCreationOptions& creationOptions() const {
         return creationOptions_;
     }
 
-    // CompartmentBehaviors specify compartment characteristics that can be
-    // changed after the compartment is created.
-    CompartmentBehaviors& behaviors() {
+    // RealmBehaviors specify realm characteristics that can be changed after
+    // the realm is created.
+    RealmBehaviors& behaviors() {
         return behaviors_;
     }
-    const CompartmentBehaviors& behaviors() const {
+    const RealmBehaviors& behaviors() const {
         return behaviors_;
     }
 
   private:
-    CompartmentCreationOptions creationOptions_;
-    CompartmentBehaviors behaviors_;
+    RealmCreationOptions creationOptions_;
+    RealmBehaviors behaviors_;
 };
 
-JS_PUBLIC_API(const CompartmentCreationOptions&)
-CompartmentCreationOptionsRef(JSCompartment* compartment);
-
-JS_PUBLIC_API(const CompartmentCreationOptions&)
-CompartmentCreationOptionsRef(JSObject* obj);
-
-JS_PUBLIC_API(const CompartmentCreationOptions&)
-CompartmentCreationOptionsRef(JSContext* cx);
-
-JS_PUBLIC_API(CompartmentBehaviors&)
-CompartmentBehaviorsRef(JSCompartment* compartment);
-
-JS_PUBLIC_API(CompartmentBehaviors&)
-CompartmentBehaviorsRef(JSObject* obj);
-
-JS_PUBLIC_API(CompartmentBehaviors&)
-CompartmentBehaviorsRef(JSContext* cx);
+JS_PUBLIC_API(const RealmCreationOptions&)
+RealmCreationOptionsRef(JSCompartment* compartment);
+
+JS_PUBLIC_API(const RealmCreationOptions&)
+RealmCreationOptionsRef(JSObject* obj);
+
+JS_PUBLIC_API(const RealmCreationOptions&)
+RealmCreationOptionsRef(JSContext* cx);
+
+JS_PUBLIC_API(RealmBehaviors&)
+RealmBehaviorsRef(JSCompartment* compartment);
+
+JS_PUBLIC_API(RealmBehaviors&)
+RealmBehaviorsRef(JSObject* obj);
+
+JS_PUBLIC_API(RealmBehaviors&)
+RealmBehaviorsRef(JSContext* cx);
 
 /**
  * During global creation, we fire notifications to callbacks registered
  * via the Debugger API. These callbacks are arbitrary script, and can touch
  * the global in arbitrary ways. When that happens, the global should not be
  * in a half-baked state. But this creates a problem for consumers that need
  * to set slots on the global to put it in a consistent state.
  *
@@ -2219,25 +1989,25 @@ enum OnNewGlobalHookOption {
     DontFireOnNewGlobalHook
 };
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSObject*)
 JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals,
                    JS::OnNewGlobalHookOption hookOption,
-                   const JS::CompartmentOptions& options);
+                   const JS::RealmOptions& options);
 /**
  * Spidermonkey does not have a good way of keeping track of what compartments should be marked on
  * their own. We can mark the roots unconditionally, but marking GC things only relevant in live
  * compartments is hard. To mitigate this, we create a static trace hook, installed on each global
  * object, from which we can be sure the compartment is relevant, and mark it.
  *
  * It is still possible to specify custom trace hooks for global object classes. They can be
- * provided via the CompartmentOptions passed to JS_NewGlobalObject.
+ * provided via the RealmOptions passed to JS_NewGlobalObject.
  */
 extern JS_PUBLIC_API(void)
 JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global);
 
 extern JS_PUBLIC_API(void)
 JS_FireOnNewGlobalObject(JSContext* cx, JS::HandleObject global);
 
 extern JS_PUBLIC_API(JSObject*)
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1307,17 +1307,17 @@ date_parse(JSContext* cx, unsigned argc,
     args.rval().set(TimeValue(result));
     return true;
 }
 
 static ClippedTime
 NowAsMillis(JSContext* cx)
 {
     double now = PRMJ_Now();
-    bool clampAndJitter = JS::CompartmentCreationOptionsRef(js::GetContextCompartment(cx)).clampAndJitterTime();
+    bool clampAndJitter = JS::RealmCreationOptionsRef(js::GetContextCompartment(cx)).clampAndJitterTime();
     if (clampAndJitter && sReduceMicrosecondTimePrecisionCallback)
         now = sReduceMicrosecondTimePrecisionCallback(now);
     else if (clampAndJitter && sResolutionUsec) {
         double clamped = floor(now / sResolutionUsec) * sResolutionUsec;
 
         if (sJitter) {
             // Calculate a random midpoint for jittering. In the browser, we are adversarial:
             // Web Content may try to calculate the midpoint themselves and use that to bypass
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1087,18 +1087,18 @@ js::ValueToSourceForError(JSContext* cx,
     return bytes.encodeLatin1(cx, str);
 }
 
 bool
 js::GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
 {
     FixedInvokeArgs<1> args(cx);
     args[0].set(Int32Value(errorNumber));
-    return CallSelfHostedFunction(cx, "GetInternalError", NullHandleValue, args, error);
+    return CallSelfHostedFunction(cx, cx->names().GetInternalError, NullHandleValue, args, error);
 }
 
 bool
 js::GetTypeError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
 {
     FixedInvokeArgs<1> args(cx);
     args[0].set(Int32Value(errorNumber));
-    return CallSelfHostedFunction(cx, "GetTypeError", NullHandleValue, args, error);
+    return CallSelfHostedFunction(cx, cx->names().GetTypeError, NullHandleValue, args, error);
 }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1799,17 +1799,17 @@ JS_NewFloat32ArrayWithBuffer(JSContext* 
                              uint32_t byteOffset, int32_t length);
 extern JS_FRIEND_API(JSObject*)
 JS_NewFloat64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
                              uint32_t byteOffset, int32_t length);
 
 /**
  * Create a new SharedArrayBuffer with the given byte length.  This
  * may only be called if
- * JS::CompartmentCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is
+ * JS::RealmCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is
  * true.
  */
 extern JS_FRIEND_API(JSObject*)
 JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes);
 
 /**
  * Create a new ArrayBuffer with the given byte length.
  */
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -30,17 +30,17 @@ using AutoValueVector = AutoVector<Value
 using AutoObjectVector = AutoVector<JSObject*>;
 
 class CallArgs;
 
 class JS_FRIEND_API(CompileOptions);
 class JS_FRIEND_API(ReadOnlyCompileOptions);
 class JS_FRIEND_API(OwningCompileOptions);
 class JS_FRIEND_API(TransitiveCompileOptions);
-class JS_PUBLIC_API(CompartmentOptions);
+class JS_PUBLIC_API(RealmOptions);
 
 } // namespace JS
 
 /* Result of typeof operator enumeration. */
 enum JSType {
     JSTYPE_UNDEFINED,           /* undefined */
     JSTYPE_OBJECT,              /* object */
     JSTYPE_FUNCTION,            /* function */
--- a/js/src/jstypes.h
+++ b/js/src/jstypes.h
@@ -63,18 +63,25 @@
 #define JS_FASTCALL
 #define JS_NO_FASTCALL
 #endif
 
 // gcc is buggy and warns on our attempts to JS_PUBLIC_API our
 // forward-declarations or explicit template instantiations.  See
 // <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50044>.  Add a way to detect
 // that so we can locally disable that warning.
+//
+// This version-check is written such that the version-number mentioned below
+// must be bumped every time a new gcc that *doesn't* fix this bug is released.
+// (The gcc release that *fixes* this bug will trigger no warning, and we'll
+// naturally stop bumping this number.)  If you ever trigger this warning with
+// the latest stable gcc, you have rs=jwalden to bump it to the next gcc minor
+// version, e.g. (8, 1, 0) to (8, 2, 0).
 #if MOZ_IS_GCC
-#  if MOZ_GCC_VERSION_AT_MOST(8, 0, 0)
+#  if !MOZ_GCC_VERSION_AT_LEAST(8, 1, 0)
 #    define JS_BROKEN_GCC_ATTRIBUTE_WARNING
 #  endif
 #endif
 
 /***********************************************************************
 ** MACROS:      JS_BEGIN_MACRO
 **              JS_END_MACRO
 ** DESCRIPTION:
new file mode 100644
--- /dev/null
+++ b/js/src/shell/fuzz-flags.txt
@@ -0,0 +1,28 @@
+# This lists all the possible flags we'd like to see tested out in the shell by
+# fuzzers. A non-empty line not starting with # should be considered a valid
+# one. Note the following flag is recommended in ALL the cases: --fuzzing-safe
+
+# general jit flags
+--ion-eager
+--baseline-eager
+--ion-offthread-compile=off
+--ion-check-range-analysis
+--ion-extra-checks
+--spectre-mitigations=on
+--spectre-mitigations=off
+--nursery-strings=on
+--ion-warmup-threshold=100
+--no-native-regexp
+--no-sse3
+--no-sse4
+
+# wasm flags
+--wasm-gc
+--no-wasm-baseline
+--no-wasm-ion
+--test-wasm-await-tier2
+
+# arm specific, no-ops on other platforms.
+--arm-sim-icache-checks
+--arm-asm-nop-fill=1
+--arm-hwcap=vfp
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -520,17 +520,17 @@ KillWatchdog(JSContext* cx);
 
 static bool
 ScheduleWatchdog(JSContext* cx, double t);
 
 static void
 CancelExecution(JSContext* cx);
 
 static JSObject*
-NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
+NewGlobalObject(JSContext* cx, JS::RealmOptions& options,
                 JSPrincipals* principals);
 
 /*
  * A toy principals type for the shell.
  *
  * In the shell, a principal is simply a 32-bit mask: P subsumes Q if the
  * set bits in P are a superset of those in Q. Thus, the principal 0 is
  * subsumed by everything, and the principal ~0 subsumes everything.
@@ -1946,24 +1946,24 @@ Evaluate(JSContext* cx, unsigned argc, V
     }
 
     {
         JSAutoRealm ar(cx, global);
         RootedScript script(cx);
 
         {
             if (saveBytecode) {
-                if (!JS::CompartmentCreationOptionsRef(cx).cloneSingletons()) {
+                if (!JS::RealmCreationOptionsRef(cx).cloneSingletons()) {
                     JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr,
                                               JSSMSG_CACHE_SINGLETON_FAILED);
                     return false;
                 }
 
                 // cloneSingletons implies that singletons are used as template objects.
-                MOZ_ASSERT(JS::CompartmentBehaviorsRef(cx).getSingletonsAsTemplates());
+                MOZ_ASSERT(JS::RealmBehaviorsRef(cx).getSingletonsAsTemplates());
             }
 
             if (loadBytecode) {
                 JS::TranscodeResult rv = JS::DecodeScript(cx, loadBuffer, &script);
                 if (!ConvertTranscodeResultToJSException(cx, rv))
                     return false;
             } else {
                 mozilla::Range<const char16_t> chars = codeChars.twoByteRange();
@@ -3413,26 +3413,26 @@ static const JSClassOps sandbox_classOps
 
 static const JSClass sandbox_class = {
     "sandbox",
     JSCLASS_GLOBAL_FLAGS,
     &sandbox_classOps
 };
 
 static void
-SetStandardCompartmentOptions(JS::CompartmentOptions& options)
+SetStandardRealmOptions(JS::RealmOptions& options)
 {
     options.creationOptions().setSharedMemoryAndAtomicsEnabled(enableSharedMemory);
 }
 
 static JSObject*
 NewSandbox(JSContext* cx, bool lazy)
 {
-    JS::CompartmentOptions options;
-    SetStandardCompartmentOptions(options);
+    JS::RealmOptions options;
+    SetStandardRealmOptions(options);
     RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, nullptr,
                                             JS::DontFireOnNewGlobalHook, options));
     if (!obj)
         return nullptr;
 
     {
         JSAutoRealm ar(cx, obj);
         if (!lazy && !JS_InitStandardClasses(cx, obj))
@@ -3600,18 +3600,18 @@ WorkerMain(void* arg)
     if (!JS::InitSelfHostedCode(cx))
         return;
 
     EnvironmentPreparer environmentPreparer(cx);
 
     do {
         JSAutoRequest areq(cx);
 
-        JS::CompartmentOptions compartmentOptions;
-        SetStandardCompartmentOptions(compartmentOptions);
+        JS::RealmOptions compartmentOptions;
+        SetStandardRealmOptions(compartmentOptions);
 
         RootedObject global(cx, NewGlobalObject(cx, compartmentOptions, nullptr));
         if (!global)
             break;
 
         JSAutoRealm ar(cx, global);
 
         JS::CompileOptions options(cx);
@@ -5185,21 +5185,21 @@ WrapWithProto(JSContext* cx, unsigned ar
     return true;
 }
 
 static bool
 NewGlobal(JSContext* cx, unsigned argc, Value* vp)
 {
     JSPrincipals* principals = nullptr;
 
-    JS::CompartmentOptions options;
-    JS::CompartmentCreationOptions& creationOptions = options.creationOptions();
-    JS::CompartmentBehaviors& behaviors = options.behaviors();
-
-    SetStandardCompartmentOptions(options);
+    JS::RealmOptions options;
+    JS::RealmCreationOptions& creationOptions = options.creationOptions();
+    JS::RealmBehaviors& behaviors = options.behaviors();
+
+    SetStandardRealmOptions(options);
     options.creationOptions().setNewZone();
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() == 1 && args[0].isObject()) {
         RootedObject opts(cx, &args[0].toObject());
         RootedValue v(cx);
 
         if (!JS_GetProperty(cx, opts, "invisibleToDebugger", &v))
@@ -8219,17 +8219,17 @@ TimesAccessed(JSContext* cx, unsigned ar
 }
 
 static const JSPropertySpec TestingProperties[] = {
     JS_PSG("timesAccessed", TimesAccessed, 0),
     JS_PS_END
 };
 
 static JSObject*
-NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
+NewGlobalObject(JSContext* cx, JS::RealmOptions& options,
                 JSPrincipals* principals)
 {
     RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, principals,
                                              JS::DontFireOnNewGlobalHook, options));
     if (!glob)
         return nullptr;
 
     {
@@ -8831,18 +8831,18 @@ Shell(JSContext* cx, OptionParser* op, c
     if (op->getBoolOption("fuzzing-safe"))
         fuzzingSafe = true;
     else
         fuzzingSafe = (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0');
 
     if (op->getBoolOption("disable-oom-functions"))
         disableOOMFunctions = true;
 
-    JS::CompartmentOptions options;
-    SetStandardCompartmentOptions(options);
+    JS::RealmOptions options;
+    SetStandardRealmOptions(options);
     RootedObject glob(cx, NewGlobalObject(cx, options, nullptr));
     if (!glob)
         return 1;
 
     JSAutoRealm ar(cx, glob);
 
     ShellContext* sc = GetShellContext(cx);
     int result = EXIT_SUCCESS;
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -68,17 +68,17 @@ ArrayObject::createArrayInternal(JSConte
 
 /* static */ inline ArrayObject*
 ArrayObject::finishCreateArray(ArrayObject* obj, HandleShape shape, AutoSetNewObjectMetadata& metadata)
 {
     size_t span = shape->slotSpan();
     if (span)
         obj->initializeSlotRange(0, span);
 
-    gc::TraceCreateObject(obj);
+    gc::gcTracer.traceCreateObject(obj);
 
     return obj;
 }
 
 /* static */ inline ArrayObject*
 ArrayObject::createArray(JSContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
                          HandleShape shape, HandleObjectGroup group,
                          uint32_t length, AutoSetNewObjectMetadata& metadata)
--- a/js/src/vm/Caches-inl.h
+++ b/js/src/vm/Caches-inl.h
@@ -71,15 +71,15 @@ NewObjectCache::newObjectFromHit(JSConte
     copyCachedToObject(obj, templateObj, entry->kind);
 
     if (group->clasp()->shouldDelayMetadataBuilder())
         cx->compartment()->setObjectPendingMetadata(cx, obj);
     else
         obj = static_cast<NativeObject*>(SetNewObjectMetadata(cx, obj));
 
     probes::CreateObject(cx, obj);
-    gc::TraceCreateObject(obj);
+    gc::gcTracer.traceCreateObject(obj);
     return obj;
 }
 
 }  /* namespace js */
 
 #endif /* vm_Caches_inl_h */
--- a/js/src/vm/Caches.h
+++ b/js/src/vm/Caches.h
@@ -2,16 +2,18 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_Caches_h
 #define vm_Caches_h
 
+#include <new>
+
 #include "jsmath.h"
 
 #include "frontend/SourceNotes.h"
 #include "gc/Tracer.h"
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/UniquePtr.h"
 #include "vm/ArrayObject.h"
@@ -137,24 +139,30 @@ class NewObjectCache
 
         /*
          * Template object to copy from, with the initial values of fields,
          * fixed slots (undefined) and private data (nullptr).
          */
         char templateObject[MAX_OBJ_SIZE];
     };
 
-    Entry entries[41];  // TODO: reconsider size
+    using EntryArray = Entry[41]; // TODO: reconsider size;
+    EntryArray entries;
 
   public:
 
-    typedef int EntryIndex;
+    using EntryIndex = int;
 
-    NewObjectCache() { mozilla::PodZero(this); }
-    void purge() { mozilla::PodZero(this); }
+    NewObjectCache()
+      : entries{} // zeroes out the array
+    {}
+
+    void purge() {
+        new (&entries) EntryArray{}; // zeroes out the array
+    }
 
     /* Remove any cached items keyed on moved objects. */
     void clearNurseryObjects(JSRuntime* rt);
 
     /*
      * Get the entry index for the given lookup, return whether there was a hit
      * on an existing entry.
      */
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -152,23 +152,25 @@
     macro(futexTimedOut, futexTimedOut, "timed-out") \
     macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
     macro(Generator, Generator, "Generator") \
     macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
     macro(GeneratorNext, GeneratorNext, "GeneratorNext") \
     macro(GeneratorReturn, GeneratorReturn, "GeneratorReturn") \
     macro(GeneratorThrow, GeneratorThrow, "GeneratorThrow") \
     macro(get, get, "get") \
+    macro(GetInternalError, GetInternalError, "GetInternalError") \
     macro(getInternals, getInternals, "getInternals") \
     macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
     macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
     macro(getPrefix, getPrefix, "get ") \
     macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
     macro(getPropertySuper, getPropertySuper, "getPropertySuper") \
     macro(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \
+    macro(GetTypeError, GetTypeError, "GetTypeError") \
     macro(global, global, "global") \
     macro(group, group, "group") \
     macro(Handle, Handle, "Handle") \
     macro(has, has, "has") \
     macro(hasOwn, hasOwn, "hasOwn") \
     macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
     macro(highWaterMark, highWaterMark, "highWaterMark") \
     macro(hour, hour, "hour") \
--- a/js/src/vm/ErrorObject.cpp
+++ b/js/src/vm/ErrorObject.cpp
@@ -9,16 +9,17 @@
 
 #include "mozilla/Range.h"
 
 #include "jsexn.h"
 
 #include "js/CallArgs.h"
 #include "js/CharacterEncoding.h"
 #include "vm/GlobalObject.h"
+#include "vm/SelfHosting.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/SavedStacks-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
@@ -237,26 +238,25 @@ js::ErrorObject::getStack_impl(JSContext
     RootedString stackString(cx);
     if (!BuildStackString(cx, savedFrameObj, &stackString))
         return false;
 
     if (cx->runtime()->stackFormat() == js::StackFormat::V8) {
         // When emulating V8 stack frames, we also need to prepend the
         // stringified Error to the stack string.
         HandlePropertyName name = cx->names().ErrorToStringWithTrailingNewline;
-        RootedValue val(cx);
-        if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), name, name, 0, &val))
+        FixedInvokeArgs<0> args2(cx);
+        RootedValue rval(cx);
+        if (!CallSelfHostedFunction(cx, name, args.thisv(), args2, &rval))
             return false;
 
-        RootedValue rval(cx);
-        if (!js::Call(cx, val, args.thisv(), &rval))
-            return false;
-
-        if (!rval.isString())
-            return false;
+        if (!rval.isString()) {
+            args.rval().setString(cx->runtime()->emptyString);
+            return true;
+        }
 
         RootedString stringified(cx, rval.toString());
         stackString = ConcatStrings<CanGC>(cx, stringified, stackString);
     }
 
     args.rval().setString(stackString);
     return true;
 }
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -493,17 +493,17 @@ GlobalObject::createInternal(JSContext* 
         return nullptr;
 
     return global;
 }
 
 /* static */ GlobalObject*
 GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals,
                    JS::OnNewGlobalHookOption hookOption,
-                   const JS::CompartmentOptions& options)
+                   const JS::RealmOptions& options)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
     JSCompartment* compartment = NewCompartment(cx, principals, options);
     if (!compartment)
         return nullptr;
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -255,17 +255,17 @@ class GlobalObject : public NativeObject
     static GlobalObject* create(...) = delete;
 
     friend struct ::JSRuntime;
     static GlobalObject* createInternal(JSContext* cx, const Class* clasp);
 
   public:
     static GlobalObject*
     new_(JSContext* cx, const Class* clasp, JSPrincipals* principals,
-         JS::OnNewGlobalHookOption hookOption, const JS::CompartmentOptions& options);
+         JS::OnNewGlobalHookOption hookOption, const JS::RealmOptions& options);
 
     /*
      * Create a constructor function with the specified name and length using
      * ctor, a method which creates objects with the given class.
      */
     static JSFunction*
     createConstructor(JSContext* cx,  JSNative ctor, JSAtom* name, unsigned length,
                       gc::AllocKind kind = gc::AllocKind::FUNCTION,
@@ -686,17 +686,17 @@ class GlobalObject : public NativeObject
     static bool
     maybeGetIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, Handle<PropertyName*> name,
                            MutableHandleValue vp, bool* exists)
     {
         NativeObject* holder = getIntrinsicsHolder(cx, global);
         if (!holder)
             return false;
 
-        if (Shape* shape = holder->lookupPure(name)) {
+        if (Shape* shape = holder->lookup(cx, name)) {
             vp.set(holder->getSlot(shape->slot()));
             *exists = true;
         } else {
             *exists = false;
         }
 
         return true;
     }
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -730,30 +730,30 @@ class MOZ_RAII AutoSetCreatedForHelperTh
     }
 };
 
 static JSObject*
 CreateGlobalForOffThreadParse(JSContext* cx, const gc::AutoSuppressGC& nogc)
 {
     JSCompartment* currentCompartment = cx->compartment();
 
-    JS::CompartmentOptions compartmentOptions(currentCompartment->creationOptions(),
-                                              currentCompartment->behaviors());
+    JS::RealmOptions realmOptions(currentCompartment->creationOptions(),
+                                  currentCompartment->behaviors());
 
-    auto& creationOptions = compartmentOptions.creationOptions();
+    auto& creationOptions = realmOptions.creationOptions();
 
     creationOptions.setInvisibleToDebugger(true)
                    .setMergeable(true)
                    .setNewZone();
 
     // Don't falsely inherit the host's global trace hook.
     creationOptions.setTrace(nullptr);
 
     JSObject* obj = JS_NewGlobalObject(cx, &parseTaskGlobalClass, nullptr,
-                                       JS::DontFireOnNewGlobalHook, compartmentOptions);
+                                       JS::DontFireOnNewGlobalHook, realmOptions);
     if (!obj)
         return nullptr;
 
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
 
     JS_SetCompartmentPrincipals(global->compartment(), currentCompartment->principals());
 
     return global;
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -36,17 +36,17 @@
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::jit;
 
 using mozilla::PodArrayZero;
 
-JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = JS::CompartmentOptions())
+JSCompartment::JSCompartment(Zone* zone, const JS::RealmOptions& options = JS::RealmOptions())
   : creationOptions_(options.creationOptions()),
     behaviors_(options.behaviors()),
     zone_(zone),
     runtime_(zone->runtimeFromAnyThread()),
     principals_(nullptr),
     isSystem_(false),
     isAtomsCompartment_(false),
     isSelfHosting(false),
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -545,18 +545,18 @@ struct IteratorHashPolicy
 namespace js {
 class DebugEnvironments;
 class ObjectWeakMap;
 class WeakMapBase;
 } // namespace js
 
 struct JSCompartment
 {
-    const JS::CompartmentCreationOptions creationOptions_;
-    JS::CompartmentBehaviors behaviors_;
+    const JS::RealmCreationOptions creationOptions_;
+    JS::RealmBehaviors behaviors_;
 
   private:
     JS::Zone*                    zone_;
     JSRuntime*                   runtime_;
 
   public:
     /*
      * The principals associated with this compartment. Note that the
@@ -644,19 +644,19 @@ struct JSCompartment
     }
     bool hasBeenEntered() const { return !!enterCompartmentDepth; }
 
     bool shouldTraceGlobal() const { return hasBeenEntered(); }
 
     JS::Zone* zone() { return zone_; }
     const JS::Zone* zone() const { return zone_; }
 
-    const JS::CompartmentCreationOptions& creationOptions() const { return creationOptions_; }
-    JS::CompartmentBehaviors& behaviors() { return behaviors_; }
-    const JS::CompartmentBehaviors& behaviors() const { return behaviors_; }
+    const JS::RealmCreationOptions& creationOptions() const { return creationOptions_; }
+    JS::RealmBehaviors& behaviors() { return behaviors_; }
+    const JS::RealmBehaviors& behaviors() const { return behaviors_; }
 
     JSRuntime* runtimeFromMainThread() const {
         MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
         return runtime_;
     }
 
     // Note: Unrestricted access to the zone's runtime from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
@@ -847,17 +847,17 @@ struct JSCompartment
     // is true before running any code in this compartment.
     bool* validAccessPtr;
 
   public:
     bool isAccessValid() const { return validAccessPtr ? *validAccessPtr : true; }
     void setValidAccessPtr(bool* accessp) { validAccessPtr = accessp; }
 
   public:
-    JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options);
+    JSCompartment(JS::Zone* zone, const JS::RealmOptions& options);
     ~JSCompartment();
 
     MOZ_MUST_USE bool init(JSContext* maybecx);
     void destroy(js::FreeOp* fop);
 
     MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
 
     MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
@@ -1361,31 +1361,31 @@ struct WrapperValue
 
 class MOZ_RAII AutoWrapperVector : public JS::GCVector<WrapperValue, 8>,
                                    private JS::AutoGCRooter
 {
   public:
     explicit AutoWrapperVector(JSContext* cx
                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : JS::GCVector<WrapperValue, 8>(cx),
-        JS::AutoGCRooter(cx, WRAPVECTOR)
+        JS::AutoGCRooter(cx, JS::AutoGCRooter::Tag::WrapperVector)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     friend void AutoGCRooter::trace(JSTracer* trc);
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class MOZ_RAII AutoWrapperRooter : private JS::AutoGCRooter {
   public:
     AutoWrapperRooter(JSContext* cx, const WrapperValue& v
                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : JS::AutoGCRooter(cx, WRAPPER), value(v)
+      : JS::AutoGCRooter(cx, JS::AutoGCRooter::Tag::Wrapper), value(v)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     operator JSObject*() const {
         return value.get().toObjectOrNull();
     }
 
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -972,25 +972,16 @@ DestroyContext(JSContext* cx);
 
 enum ErrorArgumentsType {
     ArgumentsAreUnicode,
     ArgumentsAreASCII,
     ArgumentsAreLatin1,
     ArgumentsAreUTF8
 };
 
-/*
- * Loads and returns a self-hosted function by name. For performance, define
- * the property name in vm/CommonPropertyNames.h.
- *
- * Defined in SelfHosting.cpp.
- */
-JSFunction*
-SelfHostedFunction(JSContext* cx, HandlePropertyName propName);
-
 /**
  * Report an exception, using printf-style APIs to generate the error
  * message.
  */
 #ifdef va_start
 extern bool
 ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
               ErrorArgumentsType argumentsType, va_list ap) MOZ_FORMAT_PRINTF(3, 0);
@@ -1083,62 +1074,34 @@ namespace js {
 /************************************************************************/
 
 /* AutoArrayRooter roots an external array of Values. */
 class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter
 {
   public:
     AutoArrayRooter(JSContext* cx, size_t len, Value* vec
                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : JS::AutoGCRooter(cx, len), array(vec)
+      : JS::AutoGCRooter(cx, JS::AutoGCRooter::Tag::Array), array_(vec), length_(len)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        MOZ_ASSERT(tag_ >= 0);
     }
 
-    void changeLength(size_t newLength) {
-        tag_ = ptrdiff_t(newLength);
-        MOZ_ASSERT(tag_ >= 0);
-    }
-
-    void changeArray(Value* newArray, size_t newLength) {
-        changeLength(newLength);
-        array = newArray;
-    }
-
-    Value* start() {
-        return array;
+    Value* begin() {
+        return array_;
     }
 
     size_t length() {
-        MOZ_ASSERT(tag_ >= 0);
-        return size_t(tag_);
-    }
-
-    MutableHandleValue handleAt(size_t i) {
-        MOZ_ASSERT(i < size_t(tag_));
-        return MutableHandleValue::fromMarkedLocation(&array[i]);
-    }
-    HandleValue handleAt(size_t i) const {
-        MOZ_ASSERT(i < size_t(tag_));
-        return HandleValue::fromMarkedLocation(&array[i]);
-    }
-    MutableHandleValue operator[](size_t i) {
-        MOZ_ASSERT(i < size_t(tag_));
-        return MutableHandleValue::fromMarkedLocation(&array[i]);
-    }
-    HandleValue operator[](size_t i) const {
-        MOZ_ASSERT(i < size_t(tag_));
-        return HandleValue::fromMarkedLocation(&array[i]);
+        return length_;
     }
 
     friend void JS::AutoGCRooter::trace(JSTracer* trc);
 
   private:
-    Value* array;
+    Value* array_;
+    size_t length_;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class AutoAssertNoException
 {
 #ifdef DEBUG
     JSContext* cx;
     bool hadException;
--- a/js/src/vm/JSFunction-inl.h
+++ b/js/src/vm/JSFunction-inl.h
@@ -139,14 +139,14 @@ JSFunction::create(JSContext* cx, js::gc
     }
 
     MOZ_ASSERT(!clasp->shouldDelayMetadataBuilder(),
                "Function has no extra data hanging off it, that wouldn't be "
                "allocated at this point, that would require delaying the "
                "building of metadata for it");
     fun = SetNewObjectMetadata(cx, fun);
 
-    js::gc::TraceCreateObject(fun);
+    js::gc::gcTracer.traceCreateObject(fun);
 
     return fun;
 }
 
 #endif /* vm_JSFunction_inl_h */
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -552,17 +552,17 @@ NativeObject::create(JSContext* cx, js::
     if (size_t span = shape->slotSpan())
         nobj->initializeSlotRange(0, span);
 
     if (clasp->shouldDelayMetadataBuilder())
         cx->compartment()->setObjectPendingMetadata(cx, nobj);
     else
         nobj = SetNewObjectMetadata(cx, nobj);
 
-    js::gc::TraceCreateObject(nobj);
+    js::gc::gcTracer.traceCreateObject(nobj);
 
     return nobj;
 }
 
 /* static */ inline JS::Result<NativeObject*, JS::OOM&>
 NativeObject::createWithTemplate(JSContext* cx, js::gc::InitialHeap heap,
                                  HandleObject templateObject)
 {
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -6,16 +6,17 @@
 
 #ifndef vm_ObjectGroup_h
 #define vm_ObjectGroup_h
 
 #include "jsfriendapi.h"
 
 #include "ds/IdValuePair.h"
 #include "gc/Barrier.h"
+#include "gc/GCTrace.h"
 #include "js/CharacterEncoding.h"
 #include "js/GCHashTable.h"
 #include "js/TypeDecls.h"
 #include "vm/TaggedProto.h"
 #include "vm/TypeInference.h"
 
 namespace js {
 
@@ -82,16 +83,17 @@ enum NewObjectKind {
  * to the property (whether those uncovered by analysis or those occurring
  * in the VM) will treat these properties like those of any other object group.
  */
 
 /* Type information about an object accessed by a script. */
 class ObjectGroup : public gc::TenuredCell
 {
     friend class gc::GCRuntime;
+    friend class gc::GCTrace;
 
     /* Class shared by objects in this group. */
     const Class* clasp_;
 
     /* Prototype shared by objects in this group. */
     GCPtr<TaggedProto> proto_;
 
     /* Compartment shared by objects in this group. */
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -186,17 +186,17 @@ ProxyObject::create(JSContext* cx, const
 
     ProxyObject* pobj = static_cast<ProxyObject*>(obj);
     pobj->initGroup(group);
     pobj->initShape(shape);
 
     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
     cx->compartment()->setObjectPendingMetadata(cx, pobj);
 
-    js::gc::TraceCreateObject(pobj);
+    js::gc::gcTracer.traceCreateObject(pobj);
 
     if (newKind == SingletonObject) {
         Rooted<ProxyObject*> pobjRoot(cx, pobj);
         if (!JSObject::setSingleton(cx, pobjRoot))
             return cx->alreadyReportedOOM();
         pobj = pobjRoot;
     }
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -216,17 +216,17 @@ JSRuntime::init(JSContext* cx, uint32_t 
 
     if (!gc.init(maxbytes, maxNurseryBytes))
         return false;
 
     ScopedJSDeletePtr<Zone> atomsZone(js_new<Zone>(this));
     if (!atomsZone || !atomsZone->init(true))
         return false;
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     ScopedJSDeletePtr<JSCompartment> atomsCompartment(js_new<JSCompartment>(atomsZone.get(), options));
     if (!atomsCompartment || !atomsCompartment->init(nullptr))
         return false;
 
     gc.atomsZone = atomsZone.get();
     if (!atomsZone->compartments().append(atomsCompartment.get()))
         return false;
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -9,21 +9,21 @@
 
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DoublyLinkedList.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MaybeOneOf.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/PodOperations.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/Vector.h"
 
+#include <algorithm>
 #include <setjmp.h>
 
 #include "builtin/AtomicsObject.h"
 #include "builtin/intl/SharedIntlData.h"
 #include "builtin/Promise.h"
 #include "frontend/BinSourceRuntimeSupport.h"
 #include "frontend/NameCollections.h"
 #include "gc/GCRuntime.h"
@@ -1088,48 +1088,49 @@ class MOZ_RAII AutoUnlockGC
     AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
 };
 
 /************************************************************************/
 
 static MOZ_ALWAYS_INLINE void
 MakeRangeGCSafe(Value* vec, size_t len)
 {
-    mozilla::PodZero(vec, len);
+    // Don't PodZero here because JS::Value is non-trivial.
+    for (size_t i = 0; i < len; i++)
+        vec[i].setDouble(+0.0);
 }
 
 static MOZ_ALWAYS_INLINE void
 MakeRangeGCSafe(Value* beg, Value* end)
 {
-    mozilla::PodZero(beg, end - beg);
+    MakeRangeGCSafe(beg, end - beg);
 }
 
 static MOZ_ALWAYS_INLINE void
 MakeRangeGCSafe(jsid* beg, jsid* end)
 {
-    for (jsid* id = beg; id != end; ++id)
-        *id = INT_TO_JSID(0);
+    std::fill(beg, end, INT_TO_JSID(0));
 }
 
 static MOZ_ALWAYS_INLINE void
 MakeRangeGCSafe(jsid* vec, size_t len)
 {
     MakeRangeGCSafe(vec, vec + len);
 }
 
 static MOZ_ALWAYS_INLINE void
 MakeRangeGCSafe(Shape** beg, Shape** end)
 {
-    mozilla::PodZero(beg, end - beg);
+    std::fill(beg, end, nullptr);
 }
 
 static MOZ_ALWAYS_INLINE void
 MakeRangeGCSafe(Shape** vec, size_t len)
 {
-    mozilla::PodZero(vec, len);
+    MakeRangeGCSafe(vec, vec + len);
 }
 
 static MOZ_ALWAYS_INLINE void
 SetValueRangeToUndefined(Value* beg, Value* end)
 {
     for (Value* v = beg; v != end; ++v)
         v->setUndefined();
 }
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -199,22 +199,22 @@ PrepareScopeData(JSContext* cx, BindingI
 
     return true;
 }
 
 template <typename ConcreteScope>
 static UniquePtr<typename ConcreteScope::Data>
 NewEmptyScopeData(JSContext* cx, uint32_t length = 0)
 {
-    uint8_t* bytes = cx->zone()->pod_calloc<uint8_t>(ConcreteScope::sizeOfData(length));
+    uint8_t* bytes = cx->zone()->pod_malloc<uint8_t>(ConcreteScope::sizeOfData(length));
     if (!bytes)
         ReportOutOfMemory(cx);
     auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes);
     if (data)
-        new (data) typename ConcreteScope::Data();
+        new (data) typename ConcreteScope::Data(length);
     return UniquePtr<typename ConcreteScope::Data>(data);
 }
 
 static XDRResult
 XDRBindingName(XDRState<XDR_ENCODE>* xdr, BindingName* bindingName)
 {
     JSContext* cx = xdr->cx();
 
@@ -285,17 +285,17 @@ Scope::XDRSizedBindingNames(XDRState<mod
     auto dataGuard = mozilla::MakeScopeExit([&] () {
         if (mode == XDR_DECODE) {
             DeleteScopeData(data.get());
             data.set(nullptr);
         }
     });
 
     for (uint32_t i = 0; i < length; i++)
-        MOZ_TRY(XDRBindingName(xdr, &data->names[i]));
+        MOZ_TRY(XDRBindingName(xdr, &data->trailingNames[i]));
 
     dataGuard.release();
     return Ok();
 }
 
 /* static */ Scope*
 Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
 {
@@ -1248,28 +1248,29 @@ WasmInstanceScope::create(JSContext* cx,
         size_t globalsCount = instance->instance().metadata().globals.length();
         namesCount += globalsCount;
 
         Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmInstanceScope>(cx, namesCount));
         if (!data)
             return nullptr;
 
         size_t nameIndex = 0;
+        RootedAtom name(cx);
         if (instance->instance().memory()) {
-            RootedAtom name(cx, GenerateWasmName(cx, "memory", /* index = */ 0));
+            name = GenerateWasmName(cx, "memory", /* index = */ 0);
             if (!name)
                 return nullptr;
-            data->names[nameIndex] = BindingName(name, false);
+            new (&data->trailingNames[nameIndex]) BindingName(name, false);
             nameIndex++;
         }
         for (size_t i = 0; i < globalsCount; i++) {
-            RootedAtom name(cx, GenerateWasmName(cx, "global", i));
+            name = GenerateWasmName(cx, "global", i);
             if (!name)
                 return nullptr;
-            data->names[nameIndex] = BindingName(name, false);
+            new (&data->trailingNames[nameIndex]) BindingName(name, false);
             nameIndex++;
         }
         MOZ_ASSERT(nameIndex == namesCount);
 
         data->instance.init(instance);
         data->memoriesStart = 0;
         data->globalsStart = globalsStart;
         data->length = namesCount;
@@ -1316,21 +1317,22 @@ WasmFunctionScope::create(JSContext* cx,
     uint32_t namesCount = locals.length();
 
     Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount));
     if (!data)
         return nullptr;
 
     data->funcIndex = funcIndex;
     data->length = namesCount;
+    RootedAtom name(cx);
     for (size_t i = 0; i < namesCount; i++) {
-        RootedAtom name(cx, GenerateWasmName(cx, "var", i));
+        name = GenerateWasmName(cx, "var", i);
         if (!name)
             return nullptr;
-        data->names[i] = BindingName(name, false);
+        new (&data->trailingNames[i]) BindingName(name, false);
     }
 
     Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosing, /* envShape = */ nullptr);
     if (!scope)
         return nullptr;
 
     wasmFunctionScope = &scope->as<WasmFunctionScope>();
     wasmFunctionScope->initData(Move(data.get()));
@@ -1415,29 +1417,29 @@ BindingIter::init(LexicalScope::Data& da
     // Named lambda scopes can only have environment slots. If the callee
     // isn't closed over, it is accessed via JSOP_CALLEE.
     if (flags & IsNamedLambda) {
         // Named lambda binding is weird. Normal BindingKind ordering rules
         // don't apply.
         init(0, 0, 0, 0, 0, 0,
              CanHaveEnvironmentSlots | flags,
              firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
-             data.names, data.length);
+             data.trailingNames.start(), data.length);
     } else {
         //            imports - [0, 0)
         // positional formals - [0, 0)
         //      other formals - [0, 0)
         //    top-level funcs - [0, 0)
         //               vars - [0, 0)
         //               lets - [0, data.constStart)
         //             consts - [data.constStart, data.length)
         init(0, 0, 0, 0, 0, data.constStart,
              CanHaveFrameSlots | CanHaveEnvironmentSlots | flags,
              firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
-             data.names, data.length);
+             data.trailingNames.start(), data.length);
     }
 }
 
 void
 BindingIter::init(FunctionScope::Data& data, uint8_t flags)
 {
     flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags;
     if (!(flags & HasFormalParameterExprs))
@@ -1448,49 +1450,49 @@ BindingIter::init(FunctionScope::Data& d
     //      other formals - [data.nonPositionalParamStart, data.varStart)
     //    top-level funcs - [data.varStart, data.varStart)
     //               vars - [data.varStart, data.length)
     //               lets - [data.length, data.length)
     //             consts - [data.length, data.length)
     init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length,
          flags,
          0, JSSLOT_FREE(&CallObject::class_),
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 void
 BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot)
 {
     //            imports - [0, 0)
     // positional formals - [0, 0)
     //      other formals - [0, 0)
     //    top-level funcs - [0, 0)
     //               vars - [0, data.length)
     //               lets - [data.length, data.length)
     //             consts - [data.length, data.length)
     init(0, 0, 0, 0, data.length, data.length,
          CanHaveFrameSlots | CanHaveEnvironmentSlots,
          firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_),
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 void
 BindingIter::init(GlobalScope::Data& data)
 {
     //            imports - [0, 0)
     // positional formals - [0, 0)
     //      other formals - [0, 0)
     //    top-level funcs - [0, data.varStart)
     //               vars - [data.varStart, data.letStart)
     //               lets - [data.letStart, data.constStart)
     //             consts - [data.constStart, data.length)
     init(0, 0, 0, data.varStart, data.letStart, data.constStart,
          CannotHaveSlots,
          UINT32_MAX, UINT32_MAX,
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 void
 BindingIter::init(EvalScope::Data& data, bool strict)
 {
     uint32_t flags;
     uint32_t firstFrameSlot;
     uint32_t firstEnvironmentSlot;
@@ -1508,65 +1510,65 @@ BindingIter::init(EvalScope::Data& data,
     // positional formals - [0, 0)
     //      other formals - [0, 0)
     //    top-level funcs - [0, data.varStart)
     //               vars - [data.varStart, data.length)
     //               lets - [data.length, data.length)
     //             consts - [data.length, data.length)
     init(0, 0, 0, data.varStart, data.length, data.length,
          flags, firstFrameSlot, firstEnvironmentSlot,
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 void
 BindingIter::init(ModuleScope::Data& data)
 {
     //            imports - [0, data.varStart)
     // positional formals - [data.varStart, data.varStart)
     //      other formals - [data.varStart, data.varStart)
     //    top-level funcs - [data.varStart, data.varStart)
     //               vars - [data.varStart, data.letStart)
     //               lets - [data.letStart, data.constStart)
     //             consts - [data.constStart, data.length)
     init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart,
          CanHaveFrameSlots | CanHaveEnvironmentSlots,
          0, JSSLOT_FREE(&ModuleEnvironmentObject::class_),
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 void
 BindingIter::init(WasmInstanceScope::Data& data)
 {
     //            imports - [0, 0)
     // positional formals - [0, 0)
     //      other formals - [0, 0)
     //    top-level funcs - [0, 0)
     //               vars - [0, data.length)
     //               lets - [data.length, data.length)
     //             consts - [data.length, data.length)
     init(0, 0, 0, 0, data.length, data.length,
          CanHaveFrameSlots | CanHaveEnvironmentSlots,
          UINT32_MAX, UINT32_MAX,
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 void
 BindingIter::init(WasmFunctionScope::Data& data)
 {
     //            imports - [0, 0)
     // positional formals - [0, 0)
     //      other formals - [0, 0)
     //    top-level funcs - [0, 0)
     //               vars - [0, data.length)
     //               lets - [data.length, data.length)
     //             consts - [data.length, data.length)
     init(0, 0, 0, 0, data.length, data.length,
          CanHaveFrameSlots | CanHaveEnvironmentSlots,
          UINT32_MAX, UINT32_MAX,
-         data.names, data.length);
+         data.trailingNames.start(), data.length);
 }
 
 PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script)
   : BindingIter(script)
 {
     // Reinit with flags = 0, i.e., iterate over all positional parameters.
     if (script->bodyScope()->is<FunctionScope>())
         init(script->bodyScope()->as<FunctionScope>().data(), /* flags = */ 0);
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_Scope_h
 #define vm_Scope_h
 
 #include "mozilla/Maybe.h"
 #include "mozilla/Variant.h"
 
+#include "jsutil.h"
+
 #include "gc/DeletePolicy.h"
 #include "gc/Heap.h"
 #include "gc/Policy.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/JSObject.h"
 #include "vm/Xdr.h"
@@ -124,16 +126,58 @@ class BindingName
 
     bool closedOver() const {
         return bits_ & ClosedOverFlag;
     }
 
     void trace(JSTracer* trc);
 };
 
+/**
+ * The various {Global,Module,...}Scope::Data classes consist of always-present
+ * bits, then a trailing array of BindingNames.  The various Data classes all
+ * end in a TrailingNamesArray that contains sized/aligned space for *one*
+ * BindingName.  Data instances that contain N BindingNames, are then allocated
+ * in sizeof(Data) + (space for (N - 1) BindingNames).  Because this class's
+ * |data_| field is properly sized/aligned, the N-BindingName array can start
+ * at |data_|.
+ *
+ * This is concededly a very low-level representation, but we want to only
+ * allocate once for data+bindings both, and this does so approximately as
+ * elegantly as C++ allows.
+ */
+class TrailingNamesArray
+{
+  private:
+    alignas(BindingName) unsigned char data_[sizeof(BindingName)];
+
+  private:
+    // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
+    // -Werror compile error) to reinterpret_cast<> |data_| to |T*|, even
+    // through |void*|.  Placing the latter cast in these separate functions
+    // breaks the chain such that affected GCC versions no longer warn/error.
+    void* ptr() {
+        return data_;
+    }
+
+  public:
+    // Explicitly ensure no one accidentally allocates scope data without
+    // poisoning its trailing names.
+    TrailingNamesArray() = delete;
+
+    explicit TrailingNamesArray(size_t nameCount) {
+        if (nameCount)
+            JS_POISON(&data_, 0xCC, sizeof(BindingName) * nameCount, MemCheckKind::MakeUndefined);
+    }
+
+    BindingName* start() { return reinterpret_cast<BindingName*>(ptr()); }
+
+    BindingName& operator[](size_t i) { return start()[i]; }
+};
+
 class BindingLocation
 {
   public:
     enum class Kind {
         Global,
         Argument,
         Frame,
         Environment,
@@ -374,36 +418,39 @@ class LexicalScope : public Scope
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newLexicalScopeData.
     struct Data
     {
         // Bindings are sorted by kind in both frames and environments.
         //
         //   lets - [0, constStart)
         // consts - [constStart, length)
-        uint32_t constStart;
-        uint32_t length;
+        uint32_t constStart = 0;
+        uint32_t length = 0;
 
         // Frame slots [0, nextFrameSlot) are live when this is the innermost
         // scope.
-        uint32_t nextFrameSlot;
+        uint32_t nextFrameSlot = 0;
 
         // The array of tagged JSAtom* names, allocated beyond the end of the
         // struct.
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
     }
 
     static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->names;
+        *names = data->trailingNames.start();
         *length = data->length;
     }
 
     static LexicalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                                 uint32_t firstFrameSlot, HandleScope enclosing);
 
     template <XDRMode mode>
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
@@ -476,57 +523,60 @@ class FunctionScope : public Scope
   public:
     // Data is public because it is created by the
     // frontend. See Parser<FullParseHandler>::newFunctionScopeData.
     struct Data
     {
         // The canonical function of the scope, as during a scope walk we
         // often query properties of the JSFunction (e.g., is the function an
         // arrow).
-        GCPtrFunction canonicalFunction;
+        GCPtrFunction canonicalFunction = {};
 
         // If parameter expressions are present, parameters act like lexical
         // bindings.
-        bool hasParameterExprs;
+        bool hasParameterExprs = false;
 
         // Bindings are sorted by kind in both frames and environments.
         //
         // Positional formal parameter names are those that are not
         // destructured. They may be referred to by argument slots if
         // !script()->hasParameterExprs().
         //
         // An argument slot that needs to be skipped due to being destructured
         // or having defaults will have a nullptr name in the name array to
         // advance the argument slot.
         //
         // positional formals - [0, nonPositionalFormalStart)
         //      other formals - [nonPositionalParamStart, varStart)
         //               vars - [varStart, length)
-        uint16_t nonPositionalFormalStart;
-        uint16_t varStart;
-        uint32_t length;
+        uint16_t nonPositionalFormalStart = 0;
+        uint16_t varStart = 0;
+        uint32_t length = 0;
 
         // Frame slots [0, nextFrameSlot) are live when this is the innermost
         // scope.
-        uint32_t nextFrameSlot;
+        uint32_t nextFrameSlot = 0;
 
         // The array of tagged JSAtom* names, allocated beyond the end of the
         // struct.
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
         Zone* zone() const;
     };
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
     }
 
     static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->names;
+        *names = data->trailingNames.start();
         *length = data->length;
     }
 
     static FunctionScope* create(JSContext* cx, Handle<Data*> data,
                                  bool hasParameterExprs, bool needsEnvironment,
                                  HandleFunction fun, HandleScope enclosing);
 
     static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
@@ -599,35 +649,38 @@ class VarScope : public Scope
     friend class Scope;
 
   public:
     // Data is public because it is created by the
     // frontend. See Parser<FullParseHandler>::newVarScopeData.
     struct Data
     {
         // All bindings are vars.
-        uint32_t length;
+        uint32_t length = 0;
 
         // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is
         // the innermost scope.
-        uint32_t nextFrameSlot;
+        uint32_t nextFrameSlot = 0;
 
         // The array of tagged JSAtom* names, allocated beyond the end of the
         // struct.
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
     }
 
     static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->names;
+        *names = data->trailingNames.start();
         *length = data->length;
     }
 
     static VarScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                             uint32_t firstFrameSlot, bool needsEnvironment,
                             HandleScope enclosing);
 
     template <XDRMode mode>
@@ -694,34 +747,37 @@ class GlobalScope : public Scope
     struct Data
     {
         // Bindings are sorted by kind.
         //
         // top-level funcs - [0, varStart)
         //            vars - [varStart, letStart)
         //            lets - [letStart, constStart)
         //          consts - [constStart, length)
-        uint32_t varStart;
-        uint32_t letStart;
-        uint32_t constStart;
-        uint32_t length;
+        uint32_t varStart = 0;
+        uint32_t letStart = 0;
+        uint32_t constStart = 0;
+        uint32_t length = 0;
 
         // The array of tagged JSAtom* names, allocated beyond the end of the
         // struct.
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
     }
 
     static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->names;
+        *names = data->trailingNames.start();
         *length = data->length;
     }
 
     static GlobalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data);
 
     static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind) {
         return create(cx, kind, nullptr);
     }
@@ -797,36 +853,39 @@ class EvalScope : public Scope
     {
         // All bindings in an eval script are 'var' bindings. The implicit
         // lexical scope around the eval is present regardless of strictness
         // and is its own LexicalScope. However, we need to track top-level
         // functions specially for redeclaration checks.
         //
         // top-level funcs - [0, varStart)
         //            vars - [varStart, length)
-        uint32_t varStart;
-        uint32_t length;
+        uint32_t varStart = 0;
+        uint32_t length = 0;
 
         // Frame slots [0, nextFrameSlot) are live when this is the innermost
         // scope.
-        uint32_t nextFrameSlot;
+        uint32_t nextFrameSlot = 0;
 
         // The array of tagged JSAtom* names, allocated beyond the end of the
         // struct.
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
     }
 
     static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->names;
+        *names = data->trailingNames.start();
         *length = data->length;
     }
 
     static EvalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                              HandleScope enclosing);
 
     template <XDRMode mode>
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
@@ -893,47 +952,50 @@ class ModuleScope : public Scope
     static const ScopeKind classScopeKind_ = ScopeKind::Module;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newModuleScopeData.
     struct Data
     {
         // The module of the scope.
-        GCPtr<ModuleObject*> module;
+        GCPtr<ModuleObject*> module = {};
 
         // Bindings are sorted by kind.
         //
         // imports - [0, varStart)
         //    vars - [varStart, letStart)
         //    lets - [letStart, constStart)
         //  consts - [constStart, length)
-        uint32_t varStart;
-        uint32_t letStart;
-        uint32_t constStart;
-        uint32_t length;
+        uint32_t varStart = 0;
+        uint32_t letStart = 0;
+        uint32_t constStart = 0;
+        uint32_t length = 0;
 
         // Frame slots [0, nextFrameSlot) are live when this is the innermost
         // scope.
-        uint32_t nextFrameSlot;
+        uint32_t nextFrameSlot = 0;
 
         // The array of tagged JSAtom* names, allocated beyond the end of the
         // struct.
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
         Zone* zone() const;
     };
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
     }
 
     static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->names;
+        *names = data->trailingNames.start();
         *length = data->length;
     }
 
     static ModuleScope* create(JSContext* cx, Handle<Data*> data,
                                Handle<ModuleObject*> module, HandleScope enclosing);
 
   private:
     static ModuleScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
@@ -965,25 +1027,28 @@ class WasmInstanceScope : public Scope
 {
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
 
   public:
     struct Data
     {
-        uint32_t memoriesStart;
-        uint32_t globalsStart;
-        uint32_t length;
-        uint32_t nextFrameSlot;
+        uint32_t memoriesStart = 0;
+        uint32_t globalsStart = 0;
+        uint32_t length = 0;
+        uint32_t nextFrameSlot = 0;
 
         // The wasm instance of the scope.
-        GCPtr<WasmInstanceObject*> instance;
+        GCPtr<WasmInstanceObject*> instance = {};
 
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
@@ -1025,21 +1090,24 @@ class WasmFunctionScope : public Scope
 {
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
 
   public:
     struct Data
     {
-        uint32_t length;
-        uint32_t nextFrameSlot;
-        uint32_t funcIndex;
+        uint32_t length = 0;
+        uint32_t nextFrameSlot = 0;
+        uint32_t funcIndex = 0;
 
-        BindingName names[1];
+        TrailingNamesArray trailingNames;
+
+        explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+        Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex);
 
     static size_t sizeOfData(uint32_t length) {
         return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1808,42 +1808,38 @@ CallSelfHostedNonGenericMethod(JSContext
     // This function is called when a self-hosted method is invoked on a
     // wrapper object, like a CrossCompartmentWrapper. The last argument is
     // the name of the self-hosted function. The other arguments are the
     // arguments to pass to this function.
 
     MOZ_ASSERT(args.length() > 0);
     RootedPropertyName name(cx, args[args.length() - 1].toString()->asAtom().asPropertyName());
 
-    RootedValue selfHostedFun(cx);
-    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
-        return false;
-
-    MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
-
     InvokeArgs args2(cx);
     if (!args2.init(cx, args.length() - 1))
         return false;
 
     for (size_t i = 0; i < args.length() - 1; i++)
         args2[i].set(args[i]);
 
-    return js::Call(cx, selfHostedFun, args.thisv(), args2, args.rval());
+    return CallSelfHostedFunction(cx, name, args.thisv(), args2, args.rval());
 }
 
+#ifdef DEBUG
 bool
 js::CallSelfHostedFunction(JSContext* cx, const char* name, HandleValue thisv,
                            const AnyInvokeArgs& args, MutableHandleValue rval)
 {
-    RootedAtom funAtom(cx, Atomize(cx, name, strlen(name)));
+    JSAtom* funAtom = Atomize(cx, name, strlen(name));
     if (!funAtom)
         return false;
     RootedPropertyName funName(cx, funAtom->asPropertyName());
     return CallSelfHostedFunction(cx, funName, thisv, args, rval);
 }
+#endif
 
 bool
 js::CallSelfHostedFunction(JSContext* cx, HandlePropertyName name, HandleValue thisv,
                            const AnyInvokeArgs& args, MutableHandleValue rval)
 {
     RootedValue fun(cx);
     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &fun))
         return false;
@@ -2786,17 +2782,17 @@ js::FillSelfHostingCompileOptions(Compil
 }
 
 GlobalObject*
 JSRuntime::createSelfHostingGlobal(JSContext* cx)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     options.creationOptions().setNewZone();
     options.behaviors().setDiscardSource(true);
 
     JSCompartment* compartment = NewCompartment(cx, nullptr, options);
     if (!compartment)
         return nullptr;
 
     static const ClassOps shgClassOps = {
@@ -3331,28 +3327,16 @@ JSRuntime::assertSelfHostedFunctionHasCa
 {
 #ifdef DEBUG
     JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name);
     MOZ_ASSERT(selfHostedFun);
     MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
 #endif
 }
 
-JSFunction*
-js::SelfHostedFunction(JSContext* cx, HandlePropertyName propName)
-{
-    RootedValue func(cx);
-    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
-        return nullptr;
-
-    MOZ_ASSERT(func.isObject());
-    MOZ_ASSERT(func.toObject().is<JSFunction>());
-    return &func.toObject().as<JSFunction>();
-}
-
 bool
 js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name)
 {
     return fun->isSelfHostedBuiltin() && GetSelfHostedFunctionName(fun) == name;
 }
 
 JSAtom*
 js::GetSelfHostedFunctionName(JSFunction* fun)
--- a/js/src/vm/SelfHosting.h
+++ b/js/src/vm/SelfHosting.h
@@ -29,20 +29,31 @@ IsCallSelfHostedNonGenericMethod(NativeI
 
 bool
 ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args);
 
 /* Get the compile options used when compiling self hosted code. */
 void
 FillSelfHostingCompileOptions(JS::CompileOptions& options);
 
+#ifdef DEBUG
+/*
+ * Calls a self-hosted function by name.
+ *
+ * This function is only available in debug mode, because it always atomizes
+ * its |name| parameter. Use the alternative function below in non-debug code.
+ */
 bool
 CallSelfHostedFunction(JSContext* cx, char const* name, HandleValue thisv,
                        const AnyInvokeArgs& args, MutableHandleValue rval);
+#endif
 
+/*
+ * Calls a self-hosted function by name.
+ */
 bool
 CallSelfHostedFunction(JSContext* cx, HandlePropertyName name, HandleValue thisv,
                        const AnyInvokeArgs& args, MutableHandleValue rval);
 
 bool
 intrinsic_StringSplitString(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -3,17 +3,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_StringType_h
 #define vm_StringType_h
 
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/PodOperations.h"
 #include "mozilla/Range.h"
 #include "mozilla/TextUtils.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
 #include "builtin/String.h"
 #include "gc/Barrier.h"
@@ -1275,29 +1274,27 @@ namespace js {
 
 class StaticStrings
 {
   private:
     /* Bigger chars cannot be in a length-2 string. */
     static const size_t SMALL_CHAR_LIMIT    = 128U;
     static const size_t NUM_SMALL_CHARS     = 64U;
 
-    JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS];
+    JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS] = {}; // zeroes
 
   public:
     /* We keep these public for the JITs. */
     static const size_t UNIT_STATIC_LIMIT   = 256U;
-    JSAtom* unitStaticTable[UNIT_STATIC_LIMIT];
+    JSAtom* unitStaticTable[UNIT_STATIC_LIMIT] = {}; // zeroes
 
     static const size_t INT_STATIC_LIMIT    = 256U;
-    JSAtom* intStaticTable[INT_STATIC_LIMIT];
+    JSAtom* intStaticTable[INT_STATIC_LIMIT] = {}; // zeroes
 
-    StaticStrings() {
-        mozilla::PodZero(this);
-    }
+    StaticStrings() = default;
 
     bool init(JSContext* cx);
     void trace(JSTracer* trc);
 
     static bool hasUint(uint32_t u) { return u < INT_STATIC_LIMIT; }
 
     JSAtom* getUint(uint32_t u) {
         MOZ_ASSERT(hasUint(u));
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3691,17 +3691,17 @@ TypeNewScript::make(JSContext* cx, Objec
     newScript->function_ = fun;
 
     newScript->preliminaryObjects = group->zone()->new_<PreliminaryObjectArray>();
     if (!newScript->preliminaryObjects)
         return true;
 
     group->setNewScript(newScript.forget());
 
-    gc::TraceTypeNewScript(group);
+    gc::gcTracer.traceTypeNewScript(group);
     return true;
 }
 
 // Make a TypeNewScript with the same initializer list as |newScript| but with
 // a new template object.
 /* static */ TypeNewScript*
 TypeNewScript::makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
                                  PlainObject* templateObject)
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -952,22 +952,20 @@ AddClearDefiniteFunctionUsesInScript(JSC
 class PreliminaryObjectArray
 {
   public:
     static const uint32_t COUNT = 20;
 
   private:
     // All objects with the type which have been allocated. The pointers in
     // this array are weak.
-    JSObject* objects[COUNT];
+    JSObject* objects[COUNT] = {}; // zeroes
 
   public:
-    PreliminaryObjectArray() {
-        mozilla::PodZero(this);
-    }
+    PreliminaryObjectArray() = default;
 
     void registerNewObject(PlainObject* res);
     void unregisterObject(PlainObject* obj);
 
     JSObject* get(size_t i) const {
         MOZ_ASSERT(i < COUNT);
         return objects[i];
     }
@@ -1051,53 +1049,53 @@ class TypeNewScript
         uint32_t offset;
         Initializer(Kind kind, uint32_t offset)
           : kind(kind), offset(offset)
         {}
     };
 
   private:
     // Scripted function which this information was computed for.
-    HeapPtr<JSFunction*> function_;
+    HeapPtr<JSFunction*> function_ = {};
 
     // Any preliminary objects with the type. The analyses are not performed
     // until this array is cleared.
-    PreliminaryObjectArray* preliminaryObjects;
+    PreliminaryObjectArray* preliminaryObjects = nullptr;
 
     // After the new script properties analyses have been performed, a template
     // object to use for newly constructed objects. The shape of this object
     // reflects all definite properties the object will have, and the
     // allocation kind to use. This is null if the new objects have an unboxed
     // layout, in which case the UnboxedLayout provides the initial structure
     // of the object.
-    HeapPtr<PlainObject*> templateObject_;
+    HeapPtr<PlainObject*> templateObject_ = {};
 
     // Order in which definite properties become initialized. We need this in
     // case the definite properties are invalidated (such as by adding a setter
     // to an object on the prototype chain) while an object is in the middle of
     // being initialized, so we can walk the stack and fixup any objects which
     // look for in-progress objects which were prematurely set with an incorrect
     // shape. Property assignments in inner frames are preceded by a series of
     // SETPROP_FRAME entries specifying the stack down to the frame containing
     // the write.
-    Initializer* initializerList;
+    Initializer* initializerList = nullptr;
 
     // If there are additional properties found by the acquired properties
     // analysis which were not found by the definite properties analysis, this
     // shape contains all such additional properties (plus the definite
     // properties). When an object of this group acquires this shape, it is
     // fully initialized and its group can be changed to initializedGroup.
-    HeapPtr<Shape*> initializedShape_;
+    HeapPtr<Shape*> initializedShape_ = {};
 
     // Group with definite properties set for all properties found by
     // both the definite and acquired properties analyses.
-    HeapPtr<ObjectGroup*> initializedGroup_;
+    HeapPtr<ObjectGroup*> initializedGroup_ = {};
 
   public:
-    TypeNewScript() { mozilla::PodZero(this); }
+    TypeNewScript() = default;
     ~TypeNewScript() {
         js_delete(preliminaryObjects);
         js_free(initializerList);
     }
 
     void clear() {
         function_ = nullptr;
         templateObject_ = nullptr;
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -579,17 +579,17 @@ UnboxedLayout::makeNativeGroup(JSContext
             return false;
 
         TypeNewScript* replacementNewScript =
             TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject);
         if (!replacementNewScript)
             return false;
 
         replacementGroup->setNewScript(replacementNewScript);
-        gc::TraceTypeNewScript(replacementGroup);
+        gc::gcTracer.traceTypeNewScript(replacementGroup);
 
         group->clearNewScript(cx, replacementGroup);
     }
 
     // Similarly, if this group is keyed to an allocation site, replace its
     // entry with a new group that has no unboxed layout.
     if (layout.allocationScript()) {
         RootedScript script(cx, layout.allocationScript());
@@ -776,17 +776,17 @@ UnboxedObject::createInternal(JSContext*
         return cx->alreadyReportedOOM();
 
     UnboxedObject* uobj = static_cast<UnboxedObject*>(obj);
     uobj->initGroup(group);
 
     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
     cx->compartment()->setObjectPendingMetadata(cx, uobj);
 
-    js::gc::TraceCreateObject(uobj);
+    js::gc::gcTracer.traceCreateObject(uobj);
 
     return uobj;
 }
 
 /* static */
 UnboxedPlainObject*
 UnboxedPlainObject::create(JSContext* cx, HandleObjectGroup group, NewObjectKind newKind)
 {
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -248,24 +248,24 @@ class AsmJSImport
 
 typedef Vector<AsmJSImport, 0, SystemAllocPolicy> AsmJSImportVector;
 
 // An AsmJSExport logically extends Export with the extra information needed for
 // an asm.js exported function, viz., the offsets in module's source chars in
 // case the function is toString()ed.
 class AsmJSExport
 {
-    uint32_t funcIndex_;
+    uint32_t funcIndex_ = 0;
 
     // All fields are treated as cacheable POD:
-    uint32_t startOffsetInModule_;  // Store module-start-relative offsets
-    uint32_t endOffsetInModule_;    // so preserved by serialization.
+    uint32_t startOffsetInModule_ = 0;  // Store module-start-relative offsets
+    uint32_t endOffsetInModule_ = 0;    // so preserved by serialization.
 
   public:
-    AsmJSExport() { PodZero(this); }
+    AsmJSExport() = default;
     AsmJSExport(uint32_t funcIndex, uint32_t startOffsetInModule, uint32_t endOffsetInModule)
       : funcIndex_(funcIndex),
         startOffsetInModule_(startOffsetInModule),
         endOffsetInModule_(endOffsetInModule)
     {}
     uint32_t funcIndex() const {
         return funcIndex_;
     }
@@ -287,22 +287,22 @@ enum class CacheResult
 
 // Holds the immutable guts of an AsmJSModule.
 //
 // AsmJSMetadata is built incrementally by ModuleValidator and then shared
 // immutably between AsmJSModules.
 
 struct AsmJSMetadataCacheablePod
 {
-    uint32_t                numFFIs;
-    uint32_t                srcLength;
-    uint32_t                srcLengthWithRightBrace;
-    bool                    usesSimd;
-
-    AsmJSMetadataCacheablePod() { PodZero(this); }
+    uint32_t                numFFIs = 0;
+    uint32_t                srcLength = 0;
+    uint32_t                srcLengthWithRightBrace = 0;
+    bool                    usesSimd = false;
+
+    AsmJSMetadataCacheablePod() = default;
 };
 
 struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
 {
     AsmJSGlobalVector       asmJSGlobals;
     AsmJSImportVector       asmJSImports;
     AsmJSExportVector       asmJSExports;
     CacheableCharsVector    asmJSFuncNames;
--- a/js/src/wasm/WasmModule.h
+++ b/js/src/wasm/WasmModule.h
@@ -38,21 +38,21 @@ struct CompileArgs;
 //
 // LinkData is built incrementally by ModuleGenerator and then stored immutably
 // in Module. LinkData is distinct from Metadata in that LinkData is owned and
 // destroyed by the Module since it is not needed after instantiation; Metadata
 // is needed at runtime.
 
 struct LinkDataTierCacheablePod
 {
-    uint32_t outOfBoundsOffset;
-    uint32_t unalignedAccessOffset;
-    uint32_t trapOffset;
+    uint32_t outOfBoundsOffset = 0;
+    uint32_t unalignedAccessOffset = 0;
+    uint32_t trapOffset = 0;
 
-    LinkDataTierCacheablePod() { mozilla::PodZero(this); }
+    LinkDataTierCacheablePod() = default;
 };
 
 struct LinkDataTier : LinkDataTierCacheablePod
 {
     const Tier tier;
 
     explicit LinkDataTier(Tier tier) : tier(tier) {}
 
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -369,16 +369,18 @@ ScriptPreloader::Observe(nsISupports* su
 
     return NS_OK;
 }
 
 
 Result<nsCOMPtr<nsIFile>, nsresult>
 ScriptPreloader::GetCacheFile(const nsAString& suffix)
 {
+    NS_ENSURE_TRUE(mProfD, Err(NS_ERROR_NOT_INITIALIZED));
+
     nsCOMPtr<nsIFile> cacheFile;
     MOZ_TRY(mProfD->Clone(getter_AddRefs(cacheFile)));
 
     MOZ_TRY(cacheFile->AppendNative(NS_LITERAL_CSTRING("startupCache")));
     Unused << cacheFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
 
     MOZ_TRY(cacheFile->Append(mBaseName + suffix));
 
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -568,17 +568,17 @@ void
 mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
                                          const nsACString& aLocation,
                                          MutableHandleObject aGlobal)
 {
     RefPtr<BackstagePass> backstagePass;
     nsresult rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
     NS_ENSURE_SUCCESS_VOID(rv);
 
-    CompartmentOptions options;
+    RealmOptions options;
 
     options.creationOptions()
            .setSystemZone();
 
     if (xpc::SharedMemoryEnabled())
         options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
 
     // Defer firing OnNewGlobalObject until after the __URI__ property has
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1014,19 +1014,19 @@ xpc::CreateSandboxObject(JSContext* cx, 
             principal = sop->GetPrincipal();
         } else {
             RefPtr<NullPrincipal> nullPrin = NullPrincipal::CreateWithoutOriginAttributes();
             principal = nullPrin;
         }
     }
     MOZ_ASSERT(principal);
 
-    JS::CompartmentOptions compartmentOptions;
+    JS::RealmOptions realmOptions;
 
-    auto& creationOptions = compartmentOptions.creationOptions();
+    auto& creationOptions = realmOptions.creationOptions();
 
     // XXXjwatt: Consider whether/when sandboxes should be able to see
     // [SecureContext] API (bug 1273687).  In that case we'd call
     // creationOptions.setSecureContext(true).
 
     if (principal == nsXPConnect::SystemPrincipal())
         creationOptions.setClampAndJitterTime(false);
 
@@ -1038,22 +1038,22 @@ xpc::CreateSandboxObject(JSContext* cx, 
     else if (options.freshZone)
         creationOptions.setNewZone();
     else
         creationOptions.setSystemZone();
 
     creationOptions.setInvisibleToDebugger(options.invisibleToDebugger)
                    .setTrace(TraceXPCGlobal);
 
-    compartmentOptions.behaviors().setDiscardSource(options.discardSource);
+    realmOptions.behaviors().setDiscardSource(options.discardSource);
 
     const js::Class* clasp = &SandboxClass;
 
     RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, js::Jsvalify(clasp),
-                                                     principal, compartmentOptions));
+                                                     principal, realmOptions));
     if (!sandbox)
         return NS_ERROR_FAILURE;
 
     CompartmentPrivate* priv = CompartmentPrivate::Get(sandbox);
     priv->allowWaivers = options.allowWaivers;
     priv->isWebExtensionContentScript = options.isWebExtensionContentScript;
     priv->isContentXBLCompartment = options.isContentXBLScope;
 
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1277,17 +1277,17 @@ XRE_XPCShellMain(int argc, char** argv, 
         if (NS_FAILED(rv)) {
             fprintf(gErrFile, "+++ Failed to create BackstagePass: %8x\n",
                     static_cast<uint32_t>(rv));
             return 1;
         }
 
         // Make the default XPCShell global use a fresh zone (rather than the
         // System Zone) to improve cross-zone test coverage.
-        JS::CompartmentOptions options;
+        JS::RealmOptions options;
         options.creationOptions().setNewZone();
         if (xpc::SharedMemoryEnabled())
             options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
         JS::Rooted<JSObject*> glob(cx);
         rv = xpc::InitClassesWithNewWrappedGlobal(cx,
                                                   static_cast<nsIGlobalObject*>(backstagePass),
                                                   systemprincipal,
                                                   0,
@@ -1330,17 +1330,17 @@ XRE_XPCShellMain(int argc, char** argv, 
         {
             if (!glob) {
                 return 1;
             }
 
             // Even if we're building in a configuration where source is
             // discarded, there's no reason to do that on XPCShell, and doing so
             // might break various automation scripts.
-            JS::CompartmentBehaviorsRef(glob).setDiscardSource(false);
+            JS::RealmBehaviorsRef(glob).setDiscardSource(false);
 
             backstagePass->SetGlobalObject(glob);
 
             JSAutoRealm ar(cx, glob);
 
             if (!JS_InitReflectParse(cx, glob)) {
                 return 1;
             }
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -147,17 +147,17 @@ FinishCreate(XPCWrappedNativeScope* Scop
 // and finally into XPCWrappedNative::Init. Unfortunately, this path assumes
 // very early on that we have an XPCWrappedNativeScope and corresponding global
 // JS object, which are the very things we need to create here. So we special-
 // case the logic and do some things in a different order.
 nsresult
 XPCWrappedNative::WrapNewGlobal(xpcObjectHelper& nativeHelper,
                                 nsIPrincipal* principal,
                                 bool initStandardClasses,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 XPCWrappedNative** wrappedGlobal)
 {
     AutoJSContext cx;
     nsCOMPtr<nsISupports> identity = do_QueryInterface(nativeHelper.Object());
 
     // The object should specify that it's meant to be global.
     MOZ_ASSERT(nativeHelper.GetScriptableFlags() & XPC_SCRIPTABLE_IS_GLOBAL_OBJECT);
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -428,17 +428,17 @@ xpc::TraceXPCGlobal(JSTracer* trc, JSObj
         realmPrivate->scope->TraceInside(trc);
 }
 
 
 namespace xpc {
 
 JSObject*
 CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
-                   JS::CompartmentOptions& aOptions)
+                   JS::RealmOptions& aOptions)
 {
     MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
     MOZ_ASSERT(principal);
 
     MOZ_RELEASE_ASSERT(principal != nsContentUtils::GetNullSubjectPrincipal(),
                        "The null subject principal is getting inherited - fix that!");
 
     RootedObject global(cx,
@@ -475,17 +475,17 @@ CreateGlobalObject(JSContext* cx, const 
                                    ? ProtoAndIfaceCache::WindowLike
                                    : ProtoAndIfaceCache::NonWindowLike);
     }
 
     return global;
 }
 
 void
-InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
+InitGlobalObjectOptions(JS::RealmOptions& aOptions,
                         nsIPrincipal* aPrincipal)
 {
     bool shouldDiscardSystemSource = ShouldDiscardSystemSource();
     bool extraWarningsForSystemJS = ExtraWarningsForSystemJS();
 
     bool isSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
 
     if (isSystem) {
@@ -530,17 +530,17 @@ InitGlobalObject(JSContext* aJSContext, 
     return true;
 }
 
 nsresult
 InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
                                 nsISupports* aCOMObj,
                                 nsIPrincipal* aPrincipal,
                                 uint32_t aFlags,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 MutableHandleObject aNewGlobal)
 {
     MOZ_ASSERT(aJSContext, "bad param");
     MOZ_ASSERT(aCOMObj, "bad param");
 
     // We pass null for the 'extra' pointer during global object creation, so
     // we need to have a principal.
     MOZ_ASSERT(aPrincipal);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1518,17 +1518,17 @@ public:
 
     XPCJSRuntime*
     GetRuntime() const {XPCWrappedNativeScope* scope = GetScope();
                         return scope ? scope->GetRuntime() : nullptr;}
 
     static nsresult
     WrapNewGlobal(xpcObjectHelper& nativeHelper,
                   nsIPrincipal* principal, bool initStandardClasses,
-                  JS::CompartmentOptions& aOptions,
+                  JS::RealmOptions& aOptions,
                   XPCWrappedNative** wrappedGlobal);
 
     static nsresult
     GetNewOrUsed(xpcObjectHelper& helper,
                  XPCWrappedNativeScope* Scope,
                  XPCNativeInterface* Interface,
                  XPCWrappedNative** wrapper);
 
@@ -2722,28 +2722,28 @@ public:
     bool cloneFunctions;
 
     // If true, the resulting object is deep-frozen after being cloned.
     bool deepFreeze;
 };
 
 JSObject*
 CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
-                   JS::CompartmentOptions& aOptions);
+                   JS::RealmOptions& aOptions);
 
 // Modify the provided compartment options, consistent with |aPrincipal| and
 // with globally-cached values of various preferences.
 //
 // Call this function *before* |aOptions| is used to create the corresponding
 // global object, as not all of the options it sets can be modified on an
 // existing global object.  (The type system should make this obvious, because
-// you can't get a *mutable* JS::CompartmentOptions& from an existing global
+// you can't get a *mutable* JS::RealmOptions& from an existing global
 // object.)
 void
-InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
+InitGlobalObjectOptions(JS::RealmOptions& aOptions,
                         nsIPrincipal* aPrincipal);
 
 // Finish initializing an already-created, not-yet-exposed-to-script global
 // object.  This will attach a Components object (if necessary) and call
 // |JS_FireOnNewGlobalObject| (if necessary).
 //
 // If you must modify compartment options, see InitGlobalObjectOptions above.
 bool
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -176,17 +176,17 @@ TraceXPCGlobal(JSTracer* trc, JSObject* 
  *               global object wants.
  * @param aOptions JSAPI-specific options for the new compartment.
  */
 nsresult
 InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
                                 nsISupports* aCOMObj,
                                 nsIPrincipal* aPrincipal,
                                 uint32_t aFlags,
-                                JS::CompartmentOptions& aOptions,
+                                JS::RealmOptions& aOptions,
                                 JS::MutableHandleObject aNewGlobal);
 
 enum InitClassesFlag {
     INIT_JS_STANDARD_CLASSES  = 1 << 0,
     DONT_FIRE_ONNEWGLOBALHOOK = 1 << 1,
     OMIT_COMPONENTS_OBJECT    = 1 << 2,
 };
 
--- a/netwerk/base/ProxyAutoConfig.cpp
+++ b/netwerk/base/ProxyAutoConfig.cpp
@@ -648,17 +648,17 @@ private:
     JS::SetWarningReporter(mContext, PACWarningReporter);
 
     if (!JS::InitSelfHostedCode(mContext)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     JSAutoRequest areq(mContext);
 
-    JS::CompartmentOptions options;
+    JS::RealmOptions options;
     options.creationOptions().setSystemZone();
     mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
                                  JS::DontFireOnNewGlobalHook, options);
     if (!mGlobal) {
       JS_ClearPendingException(mContext);
       return NS_ERROR_OUT_OF_MEMORY;
     }
     JS::Rooted<JSObject*> global(mContext, mGlobal);
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -456,20 +456,31 @@ class AOMExtensionWrapper extends Extens
         Services.obs.notifyObservers(file, "flush-cache-entry");
         file.remove(false);
       } catch (e) {
         Cu.reportError(e);
       }
     }
   }
 
+  maybeSetID(uri, id) {
+    if (!this.id && uri instanceof Ci.nsIJARURI &&
+        uri.JARFile.QueryInterface(Ci.nsIFileURL)
+           .file.equals(this.file)) {
+      this.id = id;
+    }
+  }
+
   setRestarting() {
     if (this.state !== "restarting") {
       this.startupPromise = new Promise(resolve => {
         this.resolveStartup = resolve;
+      }).then(async result => {
+        await this.addonPromise;
+        return result;
       });
     }
     this.state = "restarting";
   }
 
   onEnabling(addon) {
     if (addon.id === this.id) {
       this.setRestarting();
@@ -492,28 +503,31 @@ class AOMExtensionWrapper extends Extens
     if (addon.id === this.id) {
       this.destroy();
     }
   }
 
   onEvent(kind, ...args) {
     switch (kind) {
       case "addon-manager-started":
-        AddonManager.getAddonByID(this.id).then(addon => {
+        this.addonPromise = AddonManager.getAddonByID(this.id).then(addon => {
           this.addon = addon;
         });
         // FALLTHROUGH
       case "addon-manager-shutdown":
         this.addon = null;
 
         this.setRestarting();
         break;
 
       case "startup": {
         let [extension] = args;
+
+        this.maybeSetID(extension.rootURI, extension.id);
+
         if (extension.id === this.id) {
           this.attachExtension(extension);
           this.state = "pending";
         }
         break;
       }
 
       case "shutdown": {
--- a/toolkit/components/extensions/test/browser/browser_ext_management_themes.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_management_themes.js
@@ -1,14 +1,17 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 const {LightweightThemeManager} = ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
 
+const {PromiseTestUtils} = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", null);
+PromiseTestUtils.whitelistRejectionsGlobally(/Message manager disconnected/);
+
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({
     set: [["extensions.webextensions.themes.enabled", true]],
   });
 });
 
 add_task(async function test_management_themes() {
   const TEST_ID = "test_management_themes@tests.mozilla.com";
@@ -27,16 +30,19 @@ add_task(async function test_management_
     files: {
       "image1.png": BACKGROUND,
     },
     useAddonManager: "temporary",
   });
 
   async function background(TEST_ID) {
     browser.management.onInstalled.addListener(info => {
+      if (info.name == TEST_ID) {
+        return;
+      }
       browser.test.log(`${info.name} was installed`);
       browser.test.assertEq(info.type, "theme", "addon is theme");
       browser.test.sendMessage("onInstalled", info.name);
     });
     browser.management.onDisabled.addListener(info => {
       browser.test.log(`${info.name} was disabled`);
       browser.test.assertEq(info.type, "theme", "addon is theme");
       browser.test.sendMessage("onDisabled", info.name);
--- a/toolkit/components/telemetry/TelemetrySend.jsm
+++ b/toolkit/components/telemetry/TelemetrySend.jsm
@@ -104,16 +104,17 @@ const XHR_ERROR_TYPE = [
  * that would otherwise be very hard to cover.
  */
 var Policy = {
   now: () => new Date(),
   midnightPingFuzzingDelay: () => MIDNIGHT_FUZZING_DELAY_MS,
   pingSubmissionTimeout: () => PING_SUBMIT_TIMEOUT_MS,
   setSchedulerTickTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
   clearSchedulerTickTimeout: (id) => clearTimeout(id),
+  gzipCompressString: (data) => gzipCompressString(data),
 };
 
 /**
  * Determine if the ping has the new v4 ping format or the legacy v2 one or earlier.
  */
 function isV4PingFormat(aPing) {
   return ("id" in aPing) && ("application" in aPing) &&
          ("version" in aPing) && (aPing.version >= 2);
@@ -1209,17 +1210,17 @@ var TelemetrySendImpl = {
     let startTime = Utils.monotonicNow();
     let utf8Payload = converter.ConvertFromUnicode(JSON.stringify(networkPayload));
     utf8Payload += converter.Finish();
     Telemetry.getHistogramById("TELEMETRY_STRINGIFY").add(Utils.monotonicNow() - startTime);
 
     let payloadStream = Cc["@mozilla.org/io/string-input-stream;1"]
                         .createInstance(Ci.nsIStringInputStream);
     startTime = Utils.monotonicNow();
-    payloadStream.data = gzipCompressString(utf8Payload);
+    payloadStream.data = Policy.gzipCompressString(utf8Payload);
 
     // Check the size and drop pings which are too big.
     const compressedPingSizeBytes = payloadStream.data.length;
     if (compressedPingSizeBytes > TelemetryStorage.MAXIMUM_PING_SIZE) {
       this._log.error("_doPing - submitted ping exceeds the size limit, size: " + compressedPingSizeBytes);
       Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND").add();
       Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB")
                .add(Math.floor(compressedPingSizeBytes / 1024 / 1024));
--- a/toolkit/components/telemetry/tests/unit/head.js
+++ b/toolkit/components/telemetry/tests/unit/head.js
@@ -270,16 +270,27 @@ function fakeGeneratePingId(func) {
   module.Policy.generatePingId = func;
 }
 
 function fakeCachedClientId(uuid) {
   let module = ChromeUtils.import("resource://gre/modules/TelemetryController.jsm", {});
   module.Policy.getCachedClientID = () => uuid;
 }
 
+// Fake the gzip compression for the next ping to be sent out
+// and immediately reset to the original function.