Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Fri, 25 May 2018 13:01:23 +0300
changeset 419833 bf4762f10b8d3076d6862e88ca61f90271291508
parent 419832 0f600a7141f24537c6c1284dbd6b11419ae51d3d (current diff)
parent 419784 2aaf8f2a1975c57f5467968734d110ac7becc7ee (diff)
child 419834 d7c126843dc0b7cc7251bbf7c21c954d3f391c49
child 419916 de2a285d00ca5c2aca8b587a5b5588aaa263739d
child 419930 fe66c9e30a203531fe312dc052882e25a34f806e
push id103627
push userbtara@mozilla.com
push dateFri, 25 May 2018 10:05:45 +0000
treeherdermozilla-inbound@d7c126843dc0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
bf4762f10b8d / 62.0a1 / 20180525102548 / files
nightly linux64
bf4762f10b8d / 62.0a1 / 20180525102548 / files
nightly mac
bf4762f10b8d / 62.0a1 / 20180525102548 / files
nightly win32
bf4762f10b8d / 62.0a1 / 20180525102548 / files
nightly win64
bf4762f10b8d / 62.0a1 / 20180525102548 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/interfaces/base/nsIDOMWindowCollection.idl
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-056-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-056.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-052-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-ellipse-052.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-032-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-032.html
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -175,29 +175,31 @@ let gSiteDataSettings = {
   _buildSitesList(sites) {
     // Clear old entries.
     let oldItems = this._list.querySelectorAll("richlistitem");
     for (let item of oldItems) {
       item.remove();
     }
 
     let keyword = this._searchBox.value.toLowerCase().trim();
+    let fragment = document.createDocumentFragment();
     for (let site of sites) {
       let host = site.host;
       if (keyword && !host.includes(keyword)) {
         continue;
       }
 
       if (site.userAction === "remove") {
         continue;
       }
 
       let item = this._createSiteListItem(site);
-      this._list.appendChild(item);
+      fragment.appendChild(item);
     }
+    this._list.appendChild(fragment);
     this._updateButtonsState();
   },
 
   _removeSiteItems(items) {
     for (let i = items.length - 1; i >= 0; --i) {
       let item = items[i];
       let host = item.getAttribute("host");
       let siteForHost = this._sites.find(site => site.host == host);
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -11,19 +11,19 @@
 #include "nsCOMPtr.h"
 #include "nsError.h"
 #include "nsEscape.h"
 #include "nsNetUtil.h"
 #include "nsString.h"
 #include "nsQueryObject.h"
 
 #include "mozilla/dom/URL.h"
+#include "nsDOMWindowList.h"
 #include "nsIConsoleService.h"
 #include "nsIDocument.h"
-#include "nsIDOMWindowCollection.h"
 #include "nsIDOMWindow.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsIWindowMediator.h"
 #include "nsIPrefService.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Printf.h"
@@ -376,24 +376,20 @@ nsChromeRegistry::FlushSkinCaches()
   obsSvc->NotifyObservers(static_cast<nsIChromeRegistry*>(this),
                           NS_CHROME_FLUSH_SKINS_TOPIC, nullptr);
 }
 
 // XXXbsmedberg: move this to windowmediator
 nsresult nsChromeRegistry::RefreshWindow(nsPIDOMWindowOuter* aWindow)
 {
   // Deal with our subframes first.
-  nsCOMPtr<nsIDOMWindowCollection> frames = aWindow->GetFrames();
-  uint32_t length;
-  frames->GetLength(&length);
-  uint32_t j;
-  for (j = 0; j < length; j++) {
-    nsCOMPtr<mozIDOMWindowProxy> childWin;
-    frames->Item(j, getter_AddRefs(childWin));
-    nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(childWin);
+  nsDOMWindowList* frames = aWindow->GetFrames();
+  uint32_t length = frames->GetLength();
+  for (uint32_t j = 0; j < length; j++) {
+    nsCOMPtr<nsPIDOMWindowOuter> piWindow = frames->IndexedGetter(j);
     RefreshWindow(piWindow);
   }
 
   nsresult rv;
   // Get the document.
   nsCOMPtr<nsIDocument> document = aWindow->GetDoc();
   if (!document)
     return NS_OK;
--- a/config/system-headers.mozbuild
+++ b/config/system-headers.mozbuild
@@ -1330,13 +1330,18 @@ if CONFIG['MOZ_SYSTEM_ICU']:
         'unicode/unorm.h',
         'unicode/unum.h',
         'unicode/upluralrules.h',
         'unicode/ureldatefmt.h',
         'unicode/ustring.h',
         'unicode/utypes.h',
     ]
 
+if CONFIG['ENABLE_BIGINT']:
+    system_headers += [
+        'gmp.h'
+    ]
+
 if CONFIG['MOZ_WAYLAND']:
     system_headers += [
         'wayland-client.h',
         'wayland-egl.h',
     ]
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -128,16 +128,17 @@ function Inspector(toolbox) {
   this._handleRejectionIfNotDestroyed = this._handleRejectionIfNotDestroyed.bind(this);
   this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
   this._onContextMenu = this._onContextMenu.bind(this);
   this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this);
   this._updateSearchResultsLabel = this._updateSearchResultsLabel.bind(this);
   this._updateDebuggerPausedWarning = this._updateDebuggerPausedWarning.bind(this);
 
   this.onDetached = this.onDetached.bind(this);
+  this.onHostChanged = this.onHostChanged.bind(this);
   this.onMarkupLoaded = this.onMarkupLoaded.bind(this);
   this.onNewSelection = this.onNewSelection.bind(this);
   this.onNewRoot = this.onNewRoot.bind(this);
   this.onPanelWindowResize = this.onPanelWindowResize.bind(this);
   this.onShowBoxModelHighlighterForNode =
     this.onShowBoxModelHighlighterForNode.bind(this);
   this.onSidebarHidden = this.onSidebarHidden.bind(this);
   this.onSidebarResized = this.onSidebarResized.bind(this);
@@ -233,17 +234,17 @@ Inspector.prototype = {
       console.error(e);
     }
   },
 
   _deferredOpen: async function(defaultSelection) {
     this.breadcrumbs = new HTMLBreadcrumbs(this);
 
     this.walker.on("new-root", this.onNewRoot);
-
+    this.toolbox.on("host-changed", this.onHostChanged);
     this.selection.on("new-node-front", this.onNewSelection);
     this.selection.on("detached-front", this.onDetached);
 
     if (this.target.isLocalTab) {
       this.target.on("thread-paused", this._updateDebuggerPausedWarning);
       this.target.on("thread-resumed", this._updateDebuggerPausedWarning);
       this.toolbox.on("select", this._updateDebuggerPausedWarning);
       this._updateDebuggerPausedWarning();
@@ -641,102 +642,112 @@ Inspector.prototype = {
     this.is3PaneModeEnabled = !this.is3PaneModeEnabled;
     Services.prefs.setBoolPref(THREE_PANE_ENABLED_PREF, this.is3PaneModeEnabled);
 
     await this.setupToolbar();
     await this.addRuleView({ skipQueue: true });
   },
 
   /**
+   * Sets the inspector sidebar split box state. Shows the splitter inside the sidebar
+   * split box, specifies the end panel control and resizes the split box width depending
+   * on the width of the toolbox.
+   */
+  setSidebarSplitBoxState() {
+    const toolboxWidth =
+      this.panelDoc.getElementById("inspector-splitter-box").clientWidth;
+
+    // Get the inspector sidebar's (right panel in horizontal mode or bottom panel in
+    // vertical mode) width.
+    const sidebarWidth = this.splitBox.state.width;
+    // This variable represents the width of the right panel in horizontal mode or
+    // bottom-right panel in vertical mode width in 3 pane mode.
+    let sidebarSplitboxWidth;
+
+    if (this.useLandscapeMode()) {
+      // Whether or not doubling the inspector sidebar's (right panel in horizontal mode
+      // or bottom panel in vertical mode) width will be bigger than half of the
+      // toolbox's width.
+      const canDoubleSidebarWidth = (sidebarWidth * 2) < (toolboxWidth / 2);
+
+      // Resize the main split box's end panel that contains the middle and right panel.
+      // Attempts to resize the main split box's end panel to be double the size of the
+      // existing sidebar's width when switching to 3 pane mode. However, if the middle
+      // and right panel's width together is greater than half of the toolbox's width,
+      // split all 3 panels to be equally sized by resizing the end panel to be 2/3 of
+      // the current toolbox's width.
+      this.splitBox.setState({
+        width: canDoubleSidebarWidth ? sidebarWidth * 2 : toolboxWidth * 2 / 3,
+      });
+
+      // In landscape/horizontal mode, set the right panel back to its original
+      // inspector sidebar width if we can double the sidebar width. Otherwise, set
+      // the width of the right panel to be 1/3 of the toolbox's width since all 3
+      // panels will be equally sized.
+      sidebarSplitboxWidth = canDoubleSidebarWidth ? sidebarWidth : toolboxWidth / 3;
+    } else {
+      // In portrait/vertical mode, set the bottom-right panel to be 1/2 of the
+      // toolbox's width.
+      sidebarSplitboxWidth = toolboxWidth / 2;
+    }
+
+    // Show the splitter inside the sidebar split box. Sets the width of the inspector
+    // sidebar and specify that the end (right in horizontal or bottom-right in
+    // vertical) panel of the sidebar split box should be controlled when resizing.
+    this.sidebarSplitBox.setState({
+      endPanelControl: true,
+      splitterSize: 1,
+      width: sidebarSplitboxWidth,
+    });
+  },
+
+  /**
    * Adds the rule view to the middle (in landscape/horizontal mode) or bottom-left panel
    * (in portrait/vertical mode) or inspector sidebar depending on whether or not it is 3
    * pane mode. The default tab specifies whether or not the rule view should be selected.
    * The defaultTab defaults to the rule view when reverting to the 2 pane mode and the
    * rule view is being merged back into the inspector sidebar from middle/bottom-left
    * panel. Otherwise, we specify the default tab when handling the sidebar setup.
    *
    * @params {String} defaultTab
    *         Thie id of the default tab for the sidebar.
    */
   async addRuleView({ defaultTab = "ruleview", skipQueue = false } = {}) {
     const ruleViewSidebar = this.sidebarSplitBox.startPanelContainer;
-    const toolboxWidth =
-      this.panelDoc.getElementById("inspector-splitter-box").clientWidth;
 
     if (this.is3PaneModeEnabled) {
       // Convert to 3 pane mode by removing the rule view from the inspector sidebar
       // and adding the rule view to the middle (in landscape/horizontal mode) or
       // bottom-left (in portrait/vertical mode) panel.
-
       ruleViewSidebar.style.display = "block";
 
-      // Get the inspector sidebar's (right panel in horizontal mode or bottom panel in
-      // vertical mode) width.
-      const sidebarWidth = this.splitBox.state.width;
-      // This variable represents the width of the right panel in horizontal mode or
-      // bottom-right panel in vertical mode width in 3 pane mode.
-      let sidebarSplitboxWidth;
-
-      if (this.useLandscapeMode()) {
-        // Whether or not doubling the inspector sidebar's (right panel in horizontal mode
-        // or bottom panel in vertical mode) width will be bigger than half of the
-        // toolbox's width.
-        const canDoubleSidebarWidth = (sidebarWidth * 2) < (toolboxWidth / 2);
-
-        // Resize the main split box's end panel that contains the middle and right panel.
-        // Attempts to resize the main split box's end panel to be double the size of the
-        // existing sidebar's width when switching to 3 pane mode. However, if the middle
-        // and right panel's width together is greater than half of the toolbox's width,
-        // split all 3 panels to be equally sized by resizing the end panel to be 2/3 of
-        // the current toolbox's width.
-        this.splitBox.setState({
-          width: canDoubleSidebarWidth ? sidebarWidth * 2 : toolboxWidth * 2 / 3,
-        });
-
-        // In landscape/horizontal mode, set the right panel back to its original
-        // inspector sidebar width if we can double the sidebar width. Otherwise, set
-        // the width of the right panel to be 1/3 of the toolbox's width since all 3
-        // panels will be equally sized.
-        sidebarSplitboxWidth = canDoubleSidebarWidth ? sidebarWidth : toolboxWidth / 3;
-      } else {
-        // In portrait/vertical mode, set the bottom-right panel to be 1/2 of the
-        // toolbox's width.
-        sidebarSplitboxWidth = toolboxWidth / 2;
-      }
-
-      // Show the splitter inside the sidebar split box. Sets the width of the inspector
-      // sidebar and specify that the end (right in horizontal or bottom-right in
-      // vertical) panel of the sidebar split box should be controlled when resizing.
-      this.sidebarSplitBox.setState({
-        endPanelControl: true,
-        splitterSize: 1,
-        width: sidebarSplitboxWidth,
-      });
+      this.setSidebarSplitBoxState();
 
       // Force the rule view panel creation by calling getPanel
       this.getPanel("ruleview");
 
       await this.sidebar.removeTab("ruleview");
 
       this.ruleViewSideBar.addExistingTab(
         "ruleview",
         INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"),
         true);
 
       this.ruleViewSideBar.show("ruleview");
     } else {
       // Removes the rule view from the 3 pane mode and adds the rule view to the main
       // inspector sidebar.
-
       ruleViewSidebar.style.display = "none";
 
       // Set the width of the split box (right panel in horziontal mode and bottom panel
       // in vertical mode) to be the width of the inspector sidebar.
+      const splitterBox = this.panelDoc.getElementById("inspector-splitter-box");
       this.splitBox.setState({
-        width: this.useLandscapeMode() ? this.sidebarSplitBox.state.width : toolboxWidth,
+        width: this.useLandscapeMode() ?
+          this.sidebarSplitBox.state.width : splitterBox.clientWidth,
       });
 
       // Hide the splitter to prevent any drag events in the sidebar split box and
       // specify that the end (right panel in horziontal mode or bottom panel in vertical
       // mode) panel should be uncontrolled when resizing.
       this.sidebarSplitBox.setState({
         endPanelControl: false,
         splitterSize: 0,
@@ -1191,16 +1202,28 @@ Inspector.prototype = {
            selection.isElementNode() &&
            !selection.isPseudoElementNode() &&
            !selection.isAnonymousNode() &&
            !invalidTagNames.includes(
             selection.nodeFront.nodeName.toLowerCase());
   },
 
   /**
+   * Handler for the "host-changed" event from the toolbox. Resets the inspector
+   * sidebar sizes when the toolbox host type changes.
+   */
+  onHostChanged: function() {
+    if (!this.is3PaneModeEnabled) {
+      return;
+    }
+
+    this.setSidebarSplitBoxState();
+  },
+
+  /**
    * When a new node is selected.
    */
   onNewSelection: function(value, reason) {
     if (reason === "selection-destroy") {
       return;
     }
 
     // Wait for all the known tools to finish updating and then let the
--- a/devtools/client/inspector/markup/test/browser_markup_events-windowed-host.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events-windowed-host.js
@@ -11,16 +11,18 @@
 const TEST_URL = URL_ROOT + "doc_markup_events-overflow.html";
 
 registerCleanupFunction(() => {
   // Restore the default Toolbox host position after the test.
   Services.prefs.clearUserPref("devtools.toolbox.host");
 });
 
 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);
   let { inspector, toolbox } = await openInspectorForURL(TEST_URL);
   await runTests(inspector);
 
   await toolbox.switchHost("window");
   await runTests(inspector);
 
   await toolbox.switchHost("bottom");
   await runTests(inspector);
--- a/devtools/server/actors/breakpoint.js
+++ b/devtools/server/actors/breakpoint.js
@@ -144,16 +144,17 @@ let BreakpointActor = ActorClassWithSpec
       originalSourceActor,
       originalLine,
       originalColumn
     } = this.threadActor.unsafeSynchronize(
       this.threadActor.sources.getOriginalLocation(generatedLocation));
     let url = originalSourceActor.url;
 
     if (this.threadActor.sources.isBlackBoxed(url)
+        || this.threadActor.skipBreakpoints
         || frame.onStep) {
       return undefined;
     }
 
     // If we're trying to pop this frame, and we see a breakpoint at
     // the spot at which popping started, ignore it.  See bug 970469.
     const locationAtFinish = frame.onPop && frame.onPop.originalLocation;
     if (locationAtFinish &&
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -1506,19 +1506,26 @@ const ThreadActor = ActorClassWithSpec(t
   onDebuggerStatement: function(frame) {
     // Don't pause if we are currently stepping (in or over) or the frame is
     // black-boxed.
     const generatedLocation = this.sources.getFrameLocation(frame);
     const { originalSourceActor } = this.unsafeSynchronize(
       this.sources.getOriginalLocation(generatedLocation));
     const url = originalSourceActor ? originalSourceActor.url : null;
 
-    return this.sources.isBlackBoxed(url) || frame.onStep
-      ? undefined
-      : this._pauseAndRespond(frame, { type: "debuggerStatement" });
+    if (this.skipBreakpoints || this.sources.isBlackBoxed(url) || frame.onStep) {
+      return undefined;
+    }
+
+    return this._pauseAndRespond(frame, { type: "debuggerStatement" });
+  },
+
+  onSkipBreakpoints: function({ skip }) {
+    this.skipBreakpoints = skip;
+    return { skip };
   },
 
   /**
    * A function that the engine calls when an exception has been thrown and has
    * propagated to the specified frame.
    *
    * @param youngestFrame Debugger.Frame
    *        The youngest remaining stack frame.
@@ -1547,17 +1554,17 @@ const ThreadActor = ActorClassWithSpec(t
 
     const generatedLocation = this.sources.getFrameLocation(youngestFrame);
     const { originalSourceActor } = this.unsafeSynchronize(
       this.sources.getOriginalLocation(generatedLocation));
     const url = originalSourceActor ? originalSourceActor.url : null;
 
     // We ignore sources without a url because we do not
     // want to pause at console evaluations or watch expressions.
-    if (!url || this.sources.isBlackBoxed(url)) {
+    if (!url || this.skipBreakpoints || this.sources.isBlackBoxed(url)) {
       return undefined;
     }
 
     try {
       let packet = this._paused(youngestFrame);
       if (!packet) {
         return undefined;
       }
@@ -1750,17 +1757,18 @@ Object.assign(ThreadActor.prototype.requ
   "resume": ThreadActor.prototype.onResume,
   "clientEvaluate": ThreadActor.prototype.onClientEvaluate,
   "frames": ThreadActor.prototype.onFrames,
   "interrupt": ThreadActor.prototype.onInterrupt,
   "eventListeners": ThreadActor.prototype.onEventListeners,
   "releaseMany": ThreadActor.prototype.onReleaseMany,
   "sources": ThreadActor.prototype.onSources,
   "threadGrips": ThreadActor.prototype.onThreadGrips,
-  "prototypesAndProperties": ThreadActor.prototype.onPrototypesAndProperties
+  "prototypesAndProperties": ThreadActor.prototype.onPrototypesAndProperties,
+  "skipBreakpoints": ThreadActor.prototype.onSkipBreakpoints
 });
 
 exports.ThreadActor = ThreadActor;
 
 /**
  * Creates a PauseActor.
  *
  * PauseActors exist for the lifetime of a given debuggee pause.  Used to
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -214,16 +214,26 @@ function findSource(sources, url) {
   return null;
 }
 
 function waitForPause(threadClient) {
   dump("Waiting for pause.\n");
   return waitForEvent(threadClient, "paused");
 }
 
+function waitForProperty(dbg, property) {
+  return new Promise(resolve => {
+    Object.defineProperty(dbg, property, {
+      set(newValue) {
+        resolve(newValue);
+      }
+    });
+  });
+}
+
 function setBreakpoint(sourceClient, location) {
   dump("Setting breakpoint.\n");
   return sourceClient.setBreakpoint(location);
 }
 
 function getPrototypeAndProperties(objClient) {
   dump("getting prototype and properties.\n");
 
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_stepping-with-skip-breakpoints.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint-disable no-shadow, max-nested-callbacks */
+
+"use strict";
+
+/**
+ * Check basic step-over functionality with pause points
+ * for the first statement and end of the last statement.
+ */
+
+var gDebuggee;
+var gClient;
+var gCallback;
+
+function run_test() {
+  do_test_pending();
+  run_test_with_server(DebuggerServer, function() {
+    run_test_with_server(WorkerDebuggerServer, do_test_finished);
+  });
+}
+
+function run_test_with_server(server, callback) {
+  gCallback = callback;
+  initTestDebuggerServer(server);
+  gDebuggee = addTestGlobal("test-stepping", server);
+  gClient = new DebuggerClient(server.connectPipe());
+  gClient.connect(test_simple_stepping);
+}
+
+async function test_simple_stepping() {
+  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
+                                                                       "test-stepping");
+  ok(!attachResponse.error, "Should not get an error attaching");
+
+  dumpn("Evaluating test code and waiting for first debugger statement");
+  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+  equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
+  equal(gDebuggee.a, undefined);
+  equal(gDebuggee.b, undefined);
+
+  const source = await getSource(threadClient, "test_stepping-01-test-code.js");
+
+  // Add pause points for the first and end of the last statement.
+  // Note: we intentionally ignore the second statement.
+  source.setPausePoints([{
+    location: {line: 3, column: 8},
+    types: {breakpoint: true, stepOver: true}
+  },
+  {
+    location: {line: 4, column: 14},
+    types: {breakpoint: true, stepOver: true}
+  }]);
+
+  dumpn("Step Over to line 3");
+  const step1 = await stepOver(gClient, threadClient);
+  equal(step1.type, "paused");
+  equal(step1.why.type, "resumeLimit");
+  equal(step1.frame.where.line, 3);
+  equal(step1.frame.where.column, 8);
+
+  equal(gDebuggee.a, undefined);
+  equal(gDebuggee.b, undefined);
+
+  dumpn("Step Over to line 4");
+  const step2 = await stepOver(gClient, threadClient);
+  equal(step2.type, "paused");
+  equal(step2.why.type, "resumeLimit");
+  equal(step2.frame.where.line, 4);
+  equal(step2.frame.where.column, 8);
+
+  equal(gDebuggee.a, 1);
+  equal(gDebuggee.b, undefined);
+
+  dumpn("Step Over to the end of line 4");
+  const step3 = await stepOver(gClient, threadClient);
+  equal(step3.type, "paused");
+  equal(step3.why.type, "resumeLimit");
+  equal(step3.frame.where.line, 4);
+  equal(step3.frame.where.column, 14);
+  equal(gDebuggee.a, 1);
+  equal(gDebuggee.b, 2);
+
+  finishClient(gClient, gCallback);
+}
+
+function evaluateTestCode() {
+  /* eslint-disable */
+  Cu.evalInSandbox(
+    `                                   // 1
+    debugger;                           // 2
+    var a = 1;                          // 3
+    var b = 2;`,                        // 4
+    gDebuggee,
+    "1.8",
+    "test_stepping-01-test-code.js",
+    1
+  );
+  /* eslint-disable */
+}
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -184,16 +184,17 @@ reason = bug 1104838
 [test_stepping-02.js]
 [test_stepping-03.js]
 [test_stepping-04.js]
 [test_stepping-05.js]
 [test_stepping-06.js]
 [test_stepping-07.js]
 [test_stepping-08.js]
 [test_stepping-with-pause-points.js]
+[test_stepping-with-skip-breakpoints.js]
 [test_framebindings-01.js]
 [test_framebindings-02.js]
 [test_framebindings-03.js]
 [test_framebindings-04.js]
 [test_framebindings-05.js]
 [test_framebindings-06.js]
 [test_framebindings-07.js]
 [test_pause_exceptions-01.js]
--- a/devtools/shared/client/thread-client.js
+++ b/devtools/shared/client/thread-client.js
@@ -391,16 +391,27 @@ ThreadClient.prototype = {
    */
   getFrames: DebuggerClient.requester({
     type: "frames",
     start: arg(0),
     count: arg(1)
   }),
 
   /**
+   * Toggle pausing via breakpoints in the server.
+   *
+   * @param skip boolean
+   *        Whether the server should skip pausing via breakpoints
+   */
+  skipBreakpoints: DebuggerClient.requester({
+    type: "skipBreakpoints",
+    skip: arg(0),
+  }),
+
+  /**
    * An array of cached frames. Clients can observe the framesadded and
    * framescleared event to keep up to date on changes to this cache,
    * and can fill it using the fillFrames method.
    */
   get cachedFrames() {
     return this._frameCache;
   },
 
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -32,17 +32,16 @@
 #include "mozilla/dom/SVGTitleElement.h"
 #include "nsIFormControl.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIWebNavigation.h"
 #include "nsIPresShell.h"
 #include "nsIStringBundle.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
-#include "nsIDOMWindowCollection.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIWindowWatcher.h"
 #include "nsIPrompt.h"
 #include "nsITabParent.h"
 #include "nsITabChild.h"
 #include "nsRect.h"
 #include "nsIWebBrowserChromeFocus.h"
 #include "nsIContent.h"
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -175,17 +175,17 @@ WindowNamedPropertiesHandler::ownPropNam
   }
 
   // Grab the DOM window.
   nsGlobalWindowInner* win = xpc::WindowOrNull(JS_GetGlobalForObject(aCx, aProxy));
   nsTArray<nsString> names;
   // The names live on the outer window, which might be null
   nsGlobalWindowOuter* outer = win->GetOuterWindowInternal();
   if (outer) {
-    nsDOMWindowList* childWindows = outer->GetWindowList();
+    nsDOMWindowList* childWindows = outer->GetFrames();
     if (childWindows) {
       uint32_t length = childWindows->GetLength();
       for (uint32_t i = 0; i < length; ++i) {
         nsCOMPtr<nsIDocShellTreeItem> item =
           childWindows->GetDocShellTreeItemAt(i);
         // This is a bit silly, since we could presumably just do
         // item->GetWindow().  But it's not obvious whether this does the same
         // thing as GetChildWindow() with the item's name (due to the complexity
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -519,16 +519,45 @@ class SameOriginCheckerImpl final : publ
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
 };
 
 } // namespace
 
+class nsContentUtils::nsContentUtilsReporter final : public nsIMemoryReporter
+{
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
+
+  ~nsContentUtilsReporter() = default;
+
+public:
+  NS_DECL_ISUPPORTS
+
+  NS_IMETHOD
+  CollectReports(nsIHandleReportCallback* aHandleReport,
+                 nsISupports* aData, bool aAnonymize) override
+  {
+    int64_t amt = 0;
+    for (int32_t i = 0; i < PropertiesFile_COUNT; ++i) {
+      if (sStringBundles[i]) {
+        amt += sStringBundles[i]->SizeOfIncludingThisIfUnshared(MallocSizeOf);
+      }
+    }
+
+    MOZ_COLLECT_REPORT("explicit/dom/content-utils-string-bundles", KIND_HEAP, UNITS_BYTES,
+                       amt, "string-bundles in ContentUtils");
+
+    return NS_OK;
+  }
+};
+
+NS_IMPL_ISUPPORTS(nsContentUtils::nsContentUtilsReporter, nsIMemoryReporter)
+
 /**
  * This class is used to determine whether or not the user is currently
  * interacting with the browser. It listens to observer events to toggle the
  * value of the sUserActive static.
  *
  * This class is an internal implementation detail.
  * nsContentUtils::GetUserIsInteracting() should be used to access current
  * user interaction status.
@@ -619,16 +648,17 @@ nsContentUtils::Init()
       EventListenerManagerHashClearEntry,
       EventListenerManagerHashInitEntry
     };
 
     sEventListenerManagersHash =
       new PLDHashTable(&hash_table_ops, sizeof(EventListenerManagerMapEntry));
 
     RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
+    RegisterStrongMemoryReporter(new nsContentUtilsReporter());
   }
 
   sBlockedScriptRunners = new AutoTArray<nsCOMPtr<nsIRunnable>, 8>;
 
   Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
                                "dom.allow_XUL_XBL_for_file");
 
   Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3378,16 +3378,17 @@ private:
   static nsIConsoleService* sConsoleService;
 
   static nsDataHashtable<nsRefPtrHashKey<nsAtom>, EventNameMapping>* sAtomEventTable;
   static nsDataHashtable<nsStringHashKey, EventNameMapping>* sStringEventTable;
   static nsTArray<RefPtr<nsAtom>>* sUserDefinedEvents;
 
   static nsIStringBundleService* sStringBundleService;
   static nsIStringBundle* sStringBundles[PropertiesFile_COUNT];
+  class nsContentUtilsReporter;
 
   static nsIContentPolicy* sContentPolicyService;
   static bool sTriedToGetContentPolicy;
 
   static RefPtr<mozilla::intl::LineBreaker> sLineBreaker;
   static RefPtr<mozilla::intl::WordBreaker> sWordBreaker;
 
   static nsIBidiKeyboard* sBidiKeyboard;
--- a/dom/base/nsDOMWindowList.cpp
+++ b/dom/base/nsDOMWindowList.cpp
@@ -21,30 +21,20 @@ nsDOMWindowList::nsDOMWindowList(nsIDocS
 {
   SetDocShell(aDocShell);
 }
 
 nsDOMWindowList::~nsDOMWindowList()
 {
 }
 
-NS_IMPL_ADDREF(nsDOMWindowList)
-NS_IMPL_RELEASE(nsDOMWindowList)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMWindowList)
-   NS_INTERFACE_MAP_ENTRY(nsIDOMWindowCollection)
-   NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMETHODIMP
+void
 nsDOMWindowList::SetDocShell(nsIDocShell* aDocShell)
 {
   mDocShellNode = aDocShell; // Weak Reference
-
-  return NS_OK;
 }
 
 void
 nsDOMWindowList::EnsureFresh()
 {
   nsCOMPtr<nsIWebNavigation> shellAsNav = do_QueryInterface(mDocShellNode);
 
   if (shellAsNav) {
@@ -66,58 +56,38 @@ nsDOMWindowList::GetLength()
 
   int32_t length;
   nsresult rv = mDocShellNode->GetChildCount(&length);
   NS_ENSURE_SUCCESS(rv, 0);
 
   return uint32_t(length);
 }
 
-NS_IMETHODIMP
-nsDOMWindowList::GetLength(uint32_t* aLength)
-{
-  *aLength = GetLength();
-  return NS_OK;
-}
-
 already_AddRefed<nsPIDOMWindowOuter>
 nsDOMWindowList::IndexedGetter(uint32_t aIndex)
 {
   nsCOMPtr<nsIDocShellTreeItem> item = GetDocShellTreeItemAt(aIndex);
   if (!item) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> window = item->GetWindow();
   MOZ_ASSERT(window);
 
   return window.forget();
 }
 
-NS_IMETHODIMP
-nsDOMWindowList::Item(uint32_t aIndex, mozIDOMWindowProxy** aReturn)
+already_AddRefed<nsPIDOMWindowOuter>
+nsDOMWindowList::NamedItem(const nsAString& aName)
 {
-  nsCOMPtr<nsPIDOMWindowOuter> window = IndexedGetter(aIndex);
-  window.forget(aReturn);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMWindowList::NamedItem(const nsAString& aName, mozIDOMWindowProxy** aReturn)
-{
-  nsCOMPtr<nsIDocShellTreeItem> item;
-
-  *aReturn = nullptr;
-
   EnsureFresh();
 
-  if (mDocShellNode) {
-    mDocShellNode->FindChildWithName(aName, false, false, nullptr,
-                                     nullptr, getter_AddRefs(item));
-
-    nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(item));
-    if (globalObject) {
-      CallQueryInterface(globalObject.get(), aReturn);
-    }
+  if (!mDocShellNode) {
+    return nullptr;
   }
 
-  return NS_OK;
+  nsCOMPtr<nsIDocShellTreeItem> item;
+  mDocShellNode->FindChildWithName(aName, false, false, nullptr,
+                                   nullptr, getter_AddRefs(item));
+
+  nsCOMPtr<nsPIDOMWindowOuter> childWindow(do_GetInterface(item));
+  return childWindow.forget();
 }
--- a/dom/base/nsDOMWindowList.h
+++ b/dom/base/nsDOMWindowList.h
@@ -2,48 +2,47 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsDOMWindowList_h___
 #define nsDOMWindowList_h___
 
 #include "nsCOMPtr.h"
-#include "nsIDOMWindowCollection.h"
 #include <stdint.h>
 #include "nsIDocShell.h"
 
 class nsIDocShell;
 class nsIDOMWindow;
 
-class nsDOMWindowList : public nsIDOMWindowCollection
+class nsDOMWindowList final
 {
 public:
   explicit nsDOMWindowList(nsIDocShell* aDocShell);
 
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMWINDOWCOLLECTION
+  NS_INLINE_DECL_REFCOUNTING(nsDOMWindowList)
 
   uint32_t GetLength();
   already_AddRefed<nsPIDOMWindowOuter> IndexedGetter(uint32_t aIndex);
+  already_AddRefed<nsPIDOMWindowOuter> NamedItem(const nsAString& aName);
 
   //local methods
-  NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
+  void SetDocShell(nsIDocShell* aDocShell);
   already_AddRefed<nsIDocShellTreeItem> GetDocShellTreeItemAt(uint32_t aIndex)
   {
     EnsureFresh();
     nsCOMPtr<nsIDocShellTreeItem> item;
     if (mDocShellNode) {
       mDocShellNode->GetChildAt(aIndex, getter_AddRefs(item));
     }
     return item.forget();
   }
 
 protected:
-  virtual ~nsDOMWindowList();
+  ~nsDOMWindowList();
 
   // Note: this function may flush and cause mDocShellNode to become null.
   void EnsureFresh();
 
   nsIDocShell* mDocShellNode; //Weak Reference
 };
 
 #endif // nsDOMWindowList_h___
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -36,17 +36,16 @@
 #include "mozilla/dom/WindowOrientationObserver.h"
 #endif
 #include "nsDOMOfflineResourceList.h"
 #include "nsError.h"
 #include "nsIIdleService.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
 #include "nsArrayUtils.h"
-#include "nsIDOMWindowCollection.h"
 #include "nsDOMWindowList.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocumentLoader.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptContext.h"
@@ -2809,17 +2808,17 @@ nsGlobalWindowInner::GetScrollbars(Error
 }
 
 bool
 nsGlobalWindowInner::GetClosed(ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetClosedOuter, (), aError, false);
 }
 
-already_AddRefed<nsIDOMWindowCollection>
+nsDOMWindowList*
 nsGlobalWindowInner::GetFrames()
 {
   FORWARD_TO_OUTER(GetFrames, (), nullptr);
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindowInner::IndexedGetter(uint32_t aIndex)
 {
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -645,17 +645,17 @@ public:
   void SetStatus(const nsAString& aStatus, mozilla::ErrorResult& aError);
   void Close(mozilla::ErrorResult& aError);
   nsresult Close() override;
   bool GetClosed(mozilla::ErrorResult& aError);
   void Stop(mozilla::ErrorResult& aError);
   void Focus(mozilla::ErrorResult& aError);
   nsresult Focus() override;
   void Blur(mozilla::ErrorResult& aError);
-  already_AddRefed<nsIDOMWindowCollection> GetFrames() override;
+  nsDOMWindowList* GetFrames() final;
   already_AddRefed<nsPIDOMWindowOuter> GetFrames(mozilla::ErrorResult& aError);
   uint32_t Length();
   already_AddRefed<nsPIDOMWindowOuter> GetTop(mozilla::ErrorResult& aError);
 protected:
   explicit nsGlobalWindowInner(nsGlobalWindowOuter *aOuterWindow);
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 public:
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -34,17 +34,16 @@
 #include "mozilla/dom/WindowOrientationObserver.h"
 #endif
 #include "nsDOMOfflineResourceList.h"
 #include "nsError.h"
 #include "nsIIdleService.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
 #include "nsArrayUtils.h"
-#include "nsIDOMWindowCollection.h"
 #include "nsDOMWindowList.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptTimeoutHandler.h"
@@ -2909,36 +2908,29 @@ nsGlobalWindowOuter::GetClosedOuter()
 
 bool
 nsGlobalWindowOuter::Closed()
 {
   return GetClosedOuter();
 }
 
 nsDOMWindowList*
-nsGlobalWindowOuter::GetWindowList()
+nsGlobalWindowOuter::GetFrames()
 {
   if (!mFrames && mDocShell) {
     mFrames = new nsDOMWindowList(mDocShell);
   }
 
   return mFrames;
 }
 
-already_AddRefed<nsIDOMWindowCollection>
-nsGlobalWindowOuter::GetFrames()
-{
-  nsCOMPtr<nsIDOMWindowCollection> frames = GetWindowList();
-  return frames.forget();
-}
-
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindowOuter::IndexedGetterOuter(uint32_t aIndex)
 {
-  nsDOMWindowList* windows = GetWindowList();
+  nsDOMWindowList* windows = GetFrames();
   NS_ENSURE_TRUE(windows, nullptr);
 
   return windows->IndexedGetter(aIndex);
 }
 
 nsIControllers*
 nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError)
 {
@@ -3746,17 +3738,17 @@ double
 nsGlobalWindowOuter::GetScrollYOuter()
 {
   return GetScrollXY(false).y;
 }
 
 uint32_t
 nsGlobalWindowOuter::Length()
 {
-  nsDOMWindowList* windows = GetWindowList();
+  nsDOMWindowList* windows = GetFrames();
 
   return windows ? windows->GetLength() : 0;
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindowOuter::GetTopOuter()
 {
   nsCOMPtr<nsPIDOMWindowOuter> top = GetScriptableTop();
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -577,17 +577,17 @@ public:
   nsresult Close() override;
   bool GetClosedOuter();
   bool Closed() override;
   void StopOuter(mozilla::ErrorResult& aError);
   void FocusOuter(mozilla::ErrorResult& aError);
   nsresult Focus() override;
   void BlurOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetFramesOuter();
-  already_AddRefed<nsIDOMWindowCollection> GetFrames() override;
+  nsDOMWindowList* GetFrames() final;
   uint32_t Length();
   already_AddRefed<nsPIDOMWindowOuter> GetTopOuter();
 
   nsresult GetPrompter(nsIPrompt** aPrompt) override;
 protected:
   explicit nsGlobalWindowOuter();
   nsPIDOMWindowOuter* GetOpenerWindowOuter();
   // Initializes the mWasOffline member variable
@@ -998,19 +998,16 @@ protected:
   void NotifyWindowIDDestroyed(const char* aTopic);
 
   void ClearStatus();
 
   virtual void UpdateParentTarget() override;
 
   void InitializeShowFocusRings();
 
-public:
-  // Outer windows only.
-  nsDOMWindowList* GetWindowList();
 protected:
   // Helper for getComputedStyle and getDefaultComputedStyle
   already_AddRefed<nsICSSDeclaration>
     GetComputedStyleHelperOuter(mozilla::dom::Element& aElt,
                                 const nsAString& aPseudoElt,
                                 bool aDefaultStylesOnly);
 
   // Outer windows only.
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -17,16 +17,17 @@
 #include "js/TypeDecls.h"
 #include "nsRefPtrHashtable.h"
 
 // Only fired for inner windows.
 #define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed"
 #define DOM_WINDOW_FROZEN_TOPIC "dom-window-frozen"
 #define DOM_WINDOW_THAWED_TOPIC "dom-window-thawed"
 
+class nsDOMWindowList;
 class nsGlobalWindowInner;
 class nsGlobalWindowOuter;
 class nsIArray;
 class nsIContent;
 class nsICSSDeclaration;
 class nsIDocShell;
 class nsIDocShellLoadInfo;
 class nsIDocument;
@@ -583,17 +584,17 @@ public:
     return mMarkedCCGeneration;
   }
 
   mozilla::dom::Navigator* Navigator();
   virtual mozilla::dom::Location* GetLocation() = 0;
 
   virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
 
-  virtual already_AddRefed<nsIDOMWindowCollection> GetFrames() = 0;
+  virtual nsDOMWindowList* GetFrames() = 0;
 
   virtual nsresult GetInnerWidth(int32_t* aWidth) = 0;
   virtual nsresult GetInnerHeight(int32_t* aHeight) = 0;
 
   virtual already_AddRefed<nsICSSDeclaration>
   GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
                    mozilla::ErrorResult& aError) = 0;
 
@@ -1085,17 +1086,17 @@ public:
   virtual mozilla::dom::Navigator* GetNavigator() = 0;
   virtual mozilla::dom::Location* GetLocation() = 0;
 
   virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
   virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
   virtual already_AddRefed<mozilla::dom::Selection> GetSelection() = 0;
   virtual already_AddRefed<nsPIDOMWindowOuter> GetOpener() = 0;
 
-  virtual already_AddRefed<nsIDOMWindowCollection> GetFrames() = 0;
+  virtual nsDOMWindowList* GetFrames() = 0;
 
   // aLoadInfo will be passed on through to the windowwatcher.
   // aForceNoOpener will act just like a "noopener" feature in aOptions except
   //                will not affect any other window features.
   virtual nsresult Open(const nsAString& aUrl, const nsAString& aName,
                         const nsAString& aOptions,
                         nsIDocShellLoadInfo* aLoadInfo,
                         bool aForceNoOpener,
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsWindowMemoryReporter.h"
 #include "nsWindowSizes.h"
 #include "nsGlobalWindow.h"
 #include "nsIDocument.h"
-#include "nsIDOMWindowCollection.h"
+#include "nsDOMWindowList.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "nsNetCID.h"
 #include "nsPrintfCString.h"
 #include "XPCJSMemoryReporter.h"
@@ -62,32 +62,28 @@ AddNonJSSizeOfWindowAndItsDescendents(ns
   // Measure the inner window, if there is one.
   nsGlobalWindowInner* inner = aWindow->GetCurrentInnerWindowInternal();
   if (inner) {
     inner->AddSizeOfIncludingThis(windowSizes);
   }
 
   windowSizes.addToTabSizes(aSizes);
 
-  nsCOMPtr<nsIDOMWindowCollection> frames = aWindow->GetFrames();
+  nsDOMWindowList* frames = aWindow->GetFrames();
 
-  uint32_t length;
-  nsresult rv = frames->GetLength(&length);
-  NS_ENSURE_SUCCESS(rv, rv);
+  uint32_t length = frames->GetLength();
 
   // Measure this window's descendents.
   for (uint32_t i = 0; i < length; i++) {
-      nsCOMPtr<mozIDOMWindowProxy> child;
-      rv = frames->Item(i, getter_AddRefs(child));
-      NS_ENSURE_SUCCESS(rv, rv);
+      nsCOMPtr<nsPIDOMWindowOuter> child = frames->IndexedGetter(i);
       NS_ENSURE_STATE(child);
 
       nsGlobalWindowOuter* childWin = nsGlobalWindowOuter::Cast(child);
 
-      rv = AddNonJSSizeOfWindowAndItsDescendents(childWin, aSizes);
+      nsresult rv = AddNonJSSizeOfWindowAndItsDescendents(childWin, aSizes);
       NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 static nsresult
 NonJSSizeOfTab(nsPIDOMWindowOuter* aWindow, size_t* aDomSize, size_t* aStyleSize, size_t* aOtherSize)
 {
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -7432,17 +7432,17 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-compressed-texture-pvrtc.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-compressed-texture-s3tc-srgb.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-compressed-texture-s3tc.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-compressed-texture-size-limit.html]
-skip-if = (os == 'win' && os_version == '6.1' && debug && !e10s) || (os == 'android' || os == 'linux')
+skip-if = (os == 'win' && os_version == '6.1') || (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-debug-renderer-info.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-debug-shaders.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__extensions__webgl-shared-resources.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance__glsl__bugs__angle-ambiguous-function-call.html]
 skip-if = (os == 'android' || os == 'linux')
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -1142,18 +1142,18 @@ skip-if = (os == 'win' && os_version == 
 skip-if = (os == 'win' && os_version == '6.1')
 [generated/test_2_conformance__glsl__misc__shader-uniform-packing-restrictions.html]
 # Failures on win7/debug on oct 20th, 2017, bug 1410306
 skip-if = (os == 'win' && os_version == '6.1' && debug)
 [generated/test_2_conformance__textures__misc__tex-image-and-sub-image-2d-with-array-buffer-view.html]
 # Failure on win7 but got passed on win7 vm
 skip-if = (os == 'win' && os_version == '6.1')
 [generated/test_2_conformance__extensions__webgl-compressed-texture-size-limit.html]
-# Frequent but intermittent timeout on win7 debug no e10s.
-skip-if = (os == 'win' && os_version == '6.1' && debug && !e10s)
+# Frequent but intermittent timeout on win7. Bug 1404234
+skip-if = (os == 'win' && os_version == '6.1')
 [generated/test_2_conformance2__textures__misc__tex-input-validation.html]
 skip-if = (os == 'win')
 [generated/test_2_conformance2__buffers__get-buffer-sub-data.html]
 skip-if = (os == 'win')
 [generated/test_2_conformance2__rendering__draw-with-integer-texture-base-level.html]
 fail-if = (os == 'win')
 [generated/test_2_conformance2__rendering__framebuffer-texture-changing-base-level.html]
 fail-if = (os == 'win')
--- a/dom/interfaces/base/domstubs.idl
+++ b/dom/interfaces/base/domstubs.idl
@@ -25,15 +25,14 @@ namespace mozilla {
 namespace dom {
 class DOMException;
 }
 }
 %}
 
 // Base
 interface nsIDOMWindow;
-interface nsIDOMWindowCollection;
 
 // Events
 interface nsIDOMEventListener;
 
 // HTML
 interface nsIDOMHTMLHeadElement;
--- a/dom/interfaces/base/moz.build
+++ b/dom/interfaces/base/moz.build
@@ -13,17 +13,16 @@ XPIDL_SOURCES += [
     'nsIBrowserDOMWindow.idl',
     'nsIContentPermissionPrompt.idl',
     'nsIContentPrefService2.idl',
     'nsIContentProcess.idl',
     'nsIContentURIGrouper.idl',
     'nsIDOMChromeWindow.idl',
     'nsIDOMGlobalPropertyInitializer.idl',
     'nsIDOMWindow.idl',
-    'nsIDOMWindowCollection.idl',
     'nsIDOMWindowUtils.idl',
     'nsIFocusManager.idl',
     'nsIIdleObserver.idl',
     'nsIQueryContentEventResult.idl',
     'nsIRemoteBrowser.idl',
     'nsIServiceWorkerManager.idl',
     'nsIStructuredCloneContainer.idl',
     'nsITabChild.idl',
deleted file mode 100644
--- a/dom/interfaces/base/nsIDOMWindowCollection.idl
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-
-interface mozIDOMWindowProxy;
-
-/**
- * The nsIDOMWindowCollection interface is an interface for a
- * collection of DOM window objects.
- */
-
-[uuid(8d64f457-fb8c-49ea-a359-cef30eed9774)]
-interface nsIDOMWindowCollection : nsISupports
-{
-  /**
-   * Accessor for the number of windows in this collection.
-   */
-  readonly attribute unsigned long    length;
-
-  /**
-   * Method for accessing an item in this collection by index.
-   */
-  mozIDOMWindowProxy        item(in unsigned long index);
-
-  /**
-   * Method for accessing an item in this collection by window name.
-   */
-  mozIDOMWindowProxy        namedItem(in DOMString name);
-};
--- a/gfx/2d/DataSurfaceHelpers.cpp
+++ b/gfx/2d/DataSurfaceHelpers.cpp
@@ -152,37 +152,44 @@ UniquePtr<uint8_t[]>
 SurfaceToPackedBGRA(DataSourceSurface *aSurface)
 {
   SurfaceFormat format = aSurface->GetFormat();
   if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
     return nullptr;
   }
 
   IntSize size = aSurface->GetSize();
-
-  UniquePtr<uint8_t[]> imageBuffer(
-    new (std::nothrow) uint8_t[size.width * size.height * sizeof(uint32_t)]);
+  if (size.width < 0 || size.width >= INT32_MAX / 4) {
+    return nullptr;
+  }
+  int32_t stride = size.width * 4;
+  CheckedInt<size_t> bufferSize =
+    CheckedInt<size_t>(stride) * CheckedInt<size_t>(size.height);
+  if (!bufferSize.isValid()) {
+    return nullptr;
+  }
+  UniquePtr<uint8_t[]> imageBuffer(new (std::nothrow) uint8_t[bufferSize.value()]);
   if (!imageBuffer) {
     return nullptr;
   }
 
   DataSourceSurface::MappedSurface map;
   if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     return nullptr;
   }
 
   CopySurfaceDataToPackedArray(map.mData, imageBuffer.get(), size,
-                               map.mStride, 4 * sizeof(uint8_t));
+                               map.mStride, 4);
 
   aSurface->Unmap();
 
   if (format == SurfaceFormat::B8G8R8X8) {
     // Convert BGRX to BGRA by setting a to 255.
-    SwizzleData(imageBuffer.get(), size.width * sizeof(uint32_t), SurfaceFormat::X8R8G8B8_UINT32,
-                imageBuffer.get(), size.width * sizeof(uint32_t), SurfaceFormat::A8R8G8B8_UINT32,
+    SwizzleData(imageBuffer.get(), stride, SurfaceFormat::X8R8G8B8_UINT32,
+                imageBuffer.get(), stride, SurfaceFormat::A8R8G8B8_UINT32,
                 size);
   }
 
   return imageBuffer;
 }
 
 uint8_t*
 SurfaceToPackedBGR(DataSourceSurface *aSurface)
@@ -191,30 +198,38 @@ SurfaceToPackedBGR(DataSourceSurface *aS
   MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported");
 
   if (format != SurfaceFormat::B8G8R8X8) {
     // To support B8G8R8A8 we'd need to un-pre-multiply alpha
     return nullptr;
   }
 
   IntSize size = aSurface->GetSize();
-
-  uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * 3 * sizeof(uint8_t)];
+  if (size.width < 0 || size.width >= INT32_MAX / 3) {
+    return nullptr;
+  }
+  int32_t stride = size.width * 3;
+  CheckedInt<size_t> bufferSize =
+    CheckedInt<size_t>(stride) * CheckedInt<size_t>(size.height);
+  if (!bufferSize.isValid()) {
+    return nullptr;
+  }
+  uint8_t* imageBuffer = new (std::nothrow) uint8_t[bufferSize.value()];
   if (!imageBuffer) {
     return nullptr;
   }
 
   DataSourceSurface::MappedSurface map;
   if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     delete [] imageBuffer;
     return nullptr;
   }
 
   SwizzleData(map.mData, map.mStride, SurfaceFormat::B8G8R8X8,
-              imageBuffer, size.width * 3, SurfaceFormat::B8G8R8,
+              imageBuffer, stride, SurfaceFormat::B8G8R8,
               size);
 
   aSurface->Unmap();
 
   return imageBuffer;
 }
 
 void
--- a/gfx/2d/Swizzle.cpp
+++ b/gfx/2d/Swizzle.cpp
@@ -254,38 +254,52 @@ PremultiplyFallback(const uint8_t* aSrc,
 
 // If rows are tightly packed, and the size of the total area will fit within
 // the precision range of a single row, then process all the data as if it was
 // a single row.
 static inline IntSize
 CollapseSize(const IntSize& aSize, int32_t aSrcStride, int32_t aDstStride)
 {
   if (aSrcStride == aDstStride &&
-      aSrcStride == 4 * aSize.width) {
+      (aSrcStride & 3) == 0 &&
+      aSrcStride / 4 == aSize.width) {
     CheckedInt32 area = CheckedInt32(aSize.width) * CheckedInt32(aSize.height);
     if (area.isValid()) {
       return IntSize(area.value(), 1);
     }
   }
   return aSize;
 }
 
+static inline int32_t
+GetStrideGap(int32_t aWidth, SurfaceFormat aFormat, int32_t aStride)
+{
+  CheckedInt32 used = CheckedInt32(aWidth) * BytesPerPixel(aFormat);
+  if (!used.isValid() || used.value() < 0) {
+    return -1;
+  }
+  return aStride - used.value();
+}
+
 bool
 PremultiplyData(const uint8_t* aSrc, int32_t aSrcStride, SurfaceFormat aSrcFormat,
                 uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat,
                 const IntSize& aSize)
 {
   if (aSize.IsEmpty()) {
     return true;
   }
   IntSize size = CollapseSize(aSize, aSrcStride, aDstStride);
   // Find gap from end of row to the start of the next row.
-  int32_t srcGap = aSrcStride - BytesPerPixel(aSrcFormat) * aSize.width;
-  int32_t dstGap = aDstStride - BytesPerPixel(aDstFormat) * aSize.width;
+  int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride);
+  int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride);
   MOZ_ASSERT(srcGap >= 0 && dstGap >= 0);
+  if (srcGap < 0 || dstGap < 0) {
+    return false;
+  }
 
 #define FORMAT_CASE_CALL(...) __VA_ARGS__(aSrc, srcGap, aDst, dstGap, size)
 
 #ifdef USE_SSE2
   switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
   PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8)
   PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
   PREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
@@ -399,19 +413,22 @@ UnpremultiplyData(const uint8_t* aSrc, i
                   uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat,
                   const IntSize& aSize)
 {
   if (aSize.IsEmpty()) {
     return true;
   }
   IntSize size = CollapseSize(aSize, aSrcStride, aDstStride);
   // Find gap from end of row to the start of the next row.
-  int32_t srcGap = aSrcStride - BytesPerPixel(aSrcFormat) * aSize.width;
-  int32_t dstGap = aDstStride - BytesPerPixel(aDstFormat) * aSize.width;
+  int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride);
+  int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride);
   MOZ_ASSERT(srcGap >= 0 && dstGap >= 0);
+  if (srcGap < 0 || dstGap < 0) {
+    return false;
+  }
 
 #define FORMAT_CASE_CALL(...) __VA_ARGS__(aSrc, srcGap, aDst, dstGap, size)
 
 #ifdef USE_SSE2
   switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
   UNPREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8)
   UNPREMULTIPLY_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
   UNPREMULTIPLY_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8)
@@ -697,19 +714,22 @@ SwizzleData(const uint8_t* aSrc, int32_t
             uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat,
             const IntSize& aSize)
 {
   if (aSize.IsEmpty()) {
     return true;
   }
   IntSize size = CollapseSize(aSize, aSrcStride, aDstStride);
   // Find gap from end of row to the start of the next row.
-  int32_t srcGap = aSrcStride - BytesPerPixel(aSrcFormat) * aSize.width;
-  int32_t dstGap = aDstStride - BytesPerPixel(aDstFormat) * aSize.width;
+  int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride);
+  int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride);
   MOZ_ASSERT(srcGap >= 0 && dstGap >= 0);
+  if (srcGap < 0 || dstGap < 0) {
+    return false;
+  }
 
 #define FORMAT_CASE_CALL(...) __VA_ARGS__(aSrc, srcGap, aDst, dstGap, size)
 
 #ifdef USE_SSE2
   switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
   SWIZZLE_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
   SWIZZLE_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
   SWIZZLE_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
--- a/intl/strres/nsIStringBundle.idl
+++ b/intl/strres/nsIStringBundle.idl
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsISimpleEnumerator.idl"
 
 %{C++
+#include "mozilla/MemoryReporting.h"
 
 // Define Contractid and CID
 // {D85A17C1-AA7C-11d2-9B8C-00805F8A16D9}
 #define NS_STRINGBUNDLESERVICE_CID \
 { 0xd85a17c1, 0xaa7c, 0x11d2, \
   { 0x9b, 0x8c, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
 
 #define NS_STRINGBUNDLE_CONTRACTID "@mozilla.org/intl/stringbundle;1"
@@ -52,21 +53,26 @@ interface nsIStringBundle : nsISupports
   // the names are most often 8-bit string literals (normally ASCII, though
   // u8"foo" literals will also work).
   [noscript, binaryname(FormatStringFromName)]
   AString formatStringFromNameCpp(in string aName,
                                   [array, size_is(length)] in wstring params,
                                   in unsigned long length);
 
   /*
-  Implements nsISimpleEnumerator, replaces nsIEnumerator 
+  Implements nsISimpleEnumerator, replaces nsIEnumerator
   */
   nsISimpleEnumerator getSimpleEnumeration();
   // Preloads string bundle data asynchronously
   void asyncPreload();
+
+%{C++
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+  virtual size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+%}
 };
 
 [scriptable, uuid(D85A17C0-AA7C-11d2-9B8C-00805F8A16D9)]
 interface nsIStringBundleService : nsISupports
 {
   nsIStringBundle createBundle(in string aURLSpec);
   nsIStringBundle createExtensibleBundle(in string aRegistryKey);
 
@@ -78,16 +84,20 @@ interface nsIStringBundleService : nsISu
    *            can be separated by newline ('\n') characters.
    * @return the formatted message
    */
   AString formatStatusMessage(in nsresult aStatus, in wstring aStatusArg);
 
   /**
    * flushes the string bundle cache - useful when the locale changes or
    * when we need to get some extra memory back
-   * 
+   *
    * at some point, we might want to make this flush all the bundles,
    * because any bundles that are floating around when the locale changes
    * will suddenly contain bad data
    *
    */
   void flushBundles();
+
+  %{C++
+    virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+  %}
 };
--- a/intl/strres/nsIStringBundleOverride.idl
+++ b/intl/strres/nsIStringBundleOverride.idl
@@ -2,24 +2,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsISimpleEnumerator;
 
+%{C++
+#include "mozilla/MemoryReporting.h"
+%}
+
 // to be implemented by an embeddor that wants to override some strings
 [scriptable, uuid(965eb278-5678-456b-82a7-20a0c86a803c)]
 interface nsIStringBundleOverride : nsISupports
 {
   /**
    * get the override value for a particular key in a particular
    * string bundle
    */
   AString getStringFromName(in AUTF8String url,
                             in ACString key);
 
   /**
    * get all override keys for a given string bundle
    */
   nsISimpleEnumerator enumerateKeysInBundle(in AUTF8String url);
+
+%{C++
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+%}
 };
--- a/intl/strres/nsStringBundle.cpp
+++ b/intl/strres/nsStringBundle.cpp
@@ -59,16 +59,39 @@ NS_IMETHODIMP
 nsStringBundle::AsyncPreload()
 {
   return NS_IdleDispatchToCurrentThread(
     NewIdleRunnableMethod("nsStringBundle::LoadProperties",
                           this,
                           &nsStringBundle::LoadProperties));
 }
 
+size_t
+nsStringBundle::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = 0;
+  if (mProps) {
+    n += mProps->SizeOfIncludingThis(aMallocSizeOf);
+  }
+  if (mOverrideStrings) {
+    n += mOverrideStrings->SizeOfIncludingThis(aMallocSizeOf);
+  }
+  return aMallocSizeOf(this) + n;
+}
+
+size_t
+nsStringBundle::SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const
+{
+  if (mRefCnt == 1) {
+    return SizeOfIncludingThis(aMallocSizeOf);
+  } else {
+    return 0;
+  }
+}
+
 nsresult
 nsStringBundle::LoadProperties()
 {
   // this is different than mLoaded, because we only want to attempt
   // to load once
   // we only want to load once, but if we've tried once and failed,
   // continue to throw an error!
   if (mAttemptedLoad) {
@@ -378,16 +401,41 @@ nsExtensibleStringBundle::AsyncPreload()
   }
   return rv;
 }
 
 nsExtensibleStringBundle::~nsExtensibleStringBundle()
 {
 }
 
+size_t
+nsExtensibleStringBundle::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = 0;
+  const uint32_t sz = mBundles.Count();
+  for (uint32_t i = 0; i < sz; ++i) {
+    nsIStringBundle* bundle = mBundles[i];
+    if (bundle) {
+      n += bundle->SizeOfIncludingThis(aMallocSizeOf);
+    }
+  }
+  n += mBundles.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  return aMallocSizeOf(this) + n;
+}
+
+size_t
+nsExtensibleStringBundle::SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const
+{
+  if (mRefCnt == 1) {
+    return SizeOfIncludingThis(aMallocSizeOf);
+  } else {
+    return 0;
+  }
+}
+
 nsresult
 nsExtensibleStringBundle::GetStringFromID(int32_t aID, nsAString& aResult)
 {
   nsAutoCString idStr;
   idStr.AppendInt(aID, 10);
   return GetStringFromName(idStr.get(), aResult);
 }
 
@@ -485,20 +533,22 @@ nsStringBundleService::nsStringBundleSer
 {
   mErrorService = do_GetService(kErrorServiceCID);
   NS_ASSERTION(mErrorService, "Couldn't get error service");
 }
 
 NS_IMPL_ISUPPORTS(nsStringBundleService,
                   nsIStringBundleService,
                   nsIObserver,
-                  nsISupportsWeakReference)
+                  nsISupportsWeakReference,
+                  nsIMemoryReporter)
 
 nsStringBundleService::~nsStringBundleService()
 {
+  UnregisterWeakMemoryReporter(this);
   flushBundleCache();
 }
 
 nsresult
 nsStringBundleService::Init()
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
@@ -509,19 +559,32 @@ nsStringBundleService::Init()
     os->AddObserver(this, "intl:app-locales-changed", true);
   }
 
   // instantiate the override service, if there is any.
   // at some point we probably want to make this a category, and
   // support multiple overrides
   mOverrideStrings = do_GetService(NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID);
 
+  RegisterWeakMemoryReporter(this);
+
   return NS_OK;
 }
 
+size_t
+nsStringBundleService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = mBundleMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  for (auto iter = mBundleMap.ConstIter(); !iter.Done(); iter.Next()) {
+    n += iter.Data()->mBundle->SizeOfIncludingThis(aMallocSizeOf);
+    n += iter.Data()->mHashKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  }
+  return aMallocSizeOf(this) + n;
+}
+
 NS_IMETHODIMP
 nsStringBundleService::Observe(nsISupports* aSubject,
                                const char* aTopic,
                                const char16_t* aSomeData)
 {
   if (strcmp("memory-pressure", aTopic) == 0 ||
       strcmp("profile-do-change", aTopic) == 0 ||
       strcmp("chrome-flush-caches", aTopic) == 0 ||
@@ -565,17 +628,16 @@ nsStringBundleService::getStringBundle(c
 
   if (cacheEntry) {
     // cache hit!
     // remove it from the list, it will later be reinserted
     // at the head of the list
     cacheEntry->remove();
 
   } else {
-
     // hasn't been cached, so insert it into the hash table
     RefPtr<nsStringBundle> bundle = new nsStringBundle(aURLSpec, mOverrideStrings);
     cacheEntry = insertIntoCache(bundle.forget(), key);
   }
 
   // at this point the cacheEntry should exist in the hashtable,
   // but is not in the LRU cache.
   // put the cache entry at the front of the list
--- a/intl/strres/nsStringBundle.h
+++ b/intl/strres/nsStringBundle.h
@@ -22,16 +22,19 @@ public:
     nsStringBundle(const char* aURLSpec, nsIStringBundleOverride*);
     nsresult LoadProperties();
 
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSISTRINGBUNDLE
 
     nsCOMPtr<nsIPersistentProperties> mProps;
 
+    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+    size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
 protected:
     virtual ~nsStringBundle();
 
     nsresult GetCombinedEnumeration(nsIStringBundleOverride* aOverrideString,
                                     nsISimpleEnumerator** aResult);
 private:
     nsCString              mPropertiesURL;
     nsCOMPtr<nsIStringBundleOverride> mOverrideStrings;
@@ -57,16 +60,18 @@ class nsExtensibleStringBundle final : p
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTRINGBUNDLE
 
   nsresult Init(const char * aCategory, nsIStringBundleService *);
 
 public:
   nsExtensibleStringBundle();
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+  size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
 private:
   virtual ~nsExtensibleStringBundle();
 
   nsCOMArray<nsIStringBundle> mBundles;
   bool mLoaded;
 };
 
--- a/intl/strres/nsStringBundleService.h
+++ b/intl/strres/nsStringBundleService.h
@@ -10,34 +10,52 @@
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIStringBundle.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsIErrorService.h"
 #include "nsIStringBundleOverride.h"
+#include "nsIMemoryReporter.h"
 
 #include "mozilla/LinkedList.h"
 
 struct bundleCacheEntry_t;
 
 class nsStringBundleService : public nsIStringBundleService,
                               public nsIObserver,
-                              public nsSupportsWeakReference
+                              public nsSupportsWeakReference,
+                              public nsIMemoryReporter
 {
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
+
 public:
   nsStringBundleService();
 
   nsresult Init();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTRINGBUNDLESERVICE
   NS_DECL_NSIOBSERVER
 
+  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
+                            nsISupports* aData, bool anonymize) override
+  {
+    size_t amt = SizeOfIncludingThis(MallocSizeOf);
+
+    MOZ_COLLECT_REPORT(
+      "explicit/string-bundle-service", KIND_HEAP, UNITS_BYTES,
+      amt,
+      "Memory used for StringBundleService bundles");
+    return NS_OK;
+  };
+
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
 private:
   virtual ~nsStringBundleService();
 
   void getStringBundle(const char *aUrl, nsIStringBundle** aResult);
   nsresult FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
                             uint32_t argCount, char16_t** argArray,
                             nsAString& result);
 
--- a/intl/strres/nsStringBundleTextOverride.cpp
+++ b/intl/strres/nsStringBundleTextOverride.cpp
@@ -207,16 +207,22 @@ nsStringBundleTextOverride::GetStringFro
     nsAutoCString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key);
 
     // persistent properties uses ":" as a delimiter, so escape that character
     combinedURL.ReplaceSubstring(":", "%3A");
 
     return mValues->GetStringProperty(combinedURL, aResult);
 }
 
+size_t
+nsStringBundleTextOverride::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  return aMallocSizeOf(this) + (mValues ? mValues->SizeOfIncludingThis(aMallocSizeOf) : 0);
+}
+
 NS_IMETHODIMP
 nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL,
                                                   nsISimpleEnumerator** aResult)
 {
     // enumerate all strings, and let the enumerator know
     nsCOMPtr<nsISimpleEnumerator> enumerator;
     mValues->Enumerate(getter_AddRefs(enumerator));
 
--- a/intl/strres/nsStringBundleTextOverride.h
+++ b/intl/strres/nsStringBundleTextOverride.h
@@ -27,15 +27,17 @@ class nsStringBundleTextOverride : publi
   public:
     nsStringBundleTextOverride() { }
 
     nsresult Init();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSISTRINGBUNDLEOVERRIDE
 
+    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
   private:
     nsCOMPtr<nsIPersistentProperties> mValues;
 
     virtual ~nsStringBundleTextOverride() {}
 };
 
 #endif
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -97,23 +97,39 @@ def disable_export_js(value):
     if value and not len(value):
         suggestion = '--disable-export-js'
     else:
         suggestion = '--enable-export-js'
 
     die('Setting %s is deprecated, use %s instead.',
         value.format('DISABLE_EXPORT_JS'), suggestion)
 
+# Experimental BigInt support
+# =======================================================
+js_option('--enable-bigint',
+          default=False,
+          help='Enable BigInt')
+
+@depends('--enable-bigint')
+def enable_bigint(value):
+    if value:
+        return True
+
+set_config('ENABLE_BIGINT', enable_bigint)
+set_define('ENABLE_BIGINT', enable_bigint)
 
 # JIT support
 # =======================================================
-@depends(target)
-def ion_default(target):
+@depends(target, '--enable-bigint')
+def ion_default(target, enable_bigint):
+    if enable_bigint:
+        return False
     if target.cpu in ('x86', 'x86_64', 'arm', 'aarch64', 'mips32', 'mips64'):
         return True
+    return False
 
 js_option('--enable-ion',
           default=ion_default,
           help='Enable use of the IonMonkey JIT')
 
 set_config('ENABLE_ION', depends_if('--enable-ion')(lambda x: True))
 
 # JIT code simulator for cross compiles
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -1019,16 +1019,19 @@ enum class ESClass {
     Date,
     Set,
     Map,
     Promise,
     MapIterator,
     SetIterator,
     Arguments,
     Error,
+#ifdef ENABLE_BIGINT
+    BigInt,
+#endif
 
     /** None of the above. */
     Other
 };
 
 /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
 bool
 Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -117,17 +117,17 @@ ToBoolean(HandleValue v)
         return false;
     if (v.isDouble()) {
         double d = v.toDouble();
         return !mozilla::IsNaN(d) && d != 0;
     }
     if (v.isSymbol())
         return true;
 
-    /* The slow path handles strings and objects. */
+    /* The slow path handles strings, BigInts and objects. */
     return js::ToBooleanSlow(v);
 }
 
 /* ES6 draft 20141224, 7.1.3. */
 MOZ_ALWAYS_INLINE bool
 ToNumber(JSContext* cx, HandleValue v, double* out)
 {
     detail::AssertArgumentsAreSane(cx, v);
--- a/js/public/GCPolicyAPI.h
+++ b/js/public/GCPolicyAPI.h
@@ -45,16 +45,17 @@
 
 #include "js/TraceKind.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 
 // Expand the given macro D for each public GC pointer.
 #define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
     D(JS::Symbol*) \
+    IF_BIGINT(D(JS::BigInt*),) \
     D(JSAtom*) \
     D(JSFunction*) \
     D(JSObject*) \
     D(JSScript*) \
     D(JSString*)
 
 // Expand the given macro D for each public tagged GC pointer type.
 #define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
@@ -122,16 +123,19 @@ struct GCPointerPolicy
             return js::gc::IsAboutToBeFinalizedUnbarriered(vp);
         return false;
     }
     static bool isValid(T v) {
         return js::gc::IsCellPointerValidOrNull(v);
     }
 };
 template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
+#ifdef ENABLE_BIGINT
+template <> struct GCPolicy<JS::BigInt*> : public GCPointerPolicy<JS::BigInt*> {};
+#endif
 template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
 template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
 template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};
 template <> struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {};
 template <> struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {};
 
 template <typename T>
 struct NonGCPointerPolicy
--- a/js/public/Initialization.h
+++ b/js/public/Initialization.h
@@ -48,16 +48,36 @@ typedef void (*JS_ICUFreeFn)(const void*
  * *must* be called before JS_Init.  Don't use it unless you know what you're
  * doing!
  */
 extern JS_PUBLIC_API(bool)
 JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn,
                          JS_ICUReallocFn reallocFn,
                          JS_ICUFreeFn freeFn);
 
+#ifdef ENABLE_BIGINT
+namespace JS {
+
+// These types are documented as allocate_function, reallocate_function,
+// and free_function in the Info node `(gmp)Custom Allocation`.
+using GMPAllocFn = void* (*)(size_t allocSize);
+using GMPReallocFn = void* (*)(void* p, size_t oldSize, size_t newSize);
+using GMPFreeFn = void (*)(void* p, size_t size);
+
+// This function can be used to track memory used by GMP. If it is
+// called, it *must* be called before JS_Init so that same functions are
+// used for all allocations.
+extern JS_PUBLIC_API(void)
+SetGMPMemoryFunctions(GMPAllocFn allocFn,
+                      GMPReallocFn reallocFn,
+                      GMPFreeFn freeFn);
+
+}; // namespace JS
+#endif
+
 /**
  * Initialize SpiderMonkey, returning true only if initialization succeeded.
  * Once this method has succeeded, it is safe to call JS_NewContext and other
  * JSAPI methods.
  *
  * This method must be called before any other JSAPI method is used on any
  * thread.  Once it has been used, it is safe to call any JSAPI method, and it
  * remains safe to do so until JS_ShutDown is correctly called.
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -624,16 +624,17 @@ struct UnusedGCThingSizes
     macro(Other, GCHeapUnused, object) \
     macro(Other, GCHeapUnused, script) \
     macro(Other, GCHeapUnused, lazyScript) \
     macro(Other, GCHeapUnused, shape) \
     macro(Other, GCHeapUnused, baseShape) \
     macro(Other, GCHeapUnused, objectGroup) \
     macro(Other, GCHeapUnused, string) \
     macro(Other, GCHeapUnused, symbol) \
+    IF_BIGINT(macro(Other, GCHeapUnused, bigInt),) \
     macro(Other, GCHeapUnused, jitcode) \
     macro(Other, GCHeapUnused, scope) \
     macro(Other, GCHeapUnused, regExpShared)
 
     UnusedGCThingSizes()
       : FOR_EACH_SIZE(ZERO_SIZE)
         dummy()
     {}
@@ -643,16 +644,19 @@ struct UnusedGCThingSizes
         dummy()
     {}
 
     void addToKind(JS::TraceKind kind, intptr_t n) {
         switch (kind) {
           case JS::TraceKind::Object:       object += n;       break;
           case JS::TraceKind::String:       string += n;       break;
           case JS::TraceKind::Symbol:       symbol += n;       break;
+#ifdef ENABLE_BIGINT
+          case JS::TraceKind::BigInt:       bigInt += n;       break;
+#endif
           case JS::TraceKind::Script:       script += n;       break;
           case JS::TraceKind::Shape:        shape += n;        break;
           case JS::TraceKind::BaseShape:    baseShape += n;    break;
           case JS::TraceKind::JitCode:      jitcode += n;      break;
           case JS::TraceKind::LazyScript:   lazyScript += n;   break;
           case JS::TraceKind::ObjectGroup:  objectGroup += n;  break;
           case JS::TraceKind::Scope:        scope += n;        break;
           case JS::TraceKind::RegExpShared: regExpShared += n; break;
@@ -684,16 +688,18 @@ struct UnusedGCThingSizes
 
 #undef FOR_EACH_SIZE
 };
 
 struct ZoneStats
 {
 #define FOR_EACH_SIZE(macro) \
     macro(Other,   GCHeapUsed,  symbolsGCHeap) \
+    IF_BIGINT(macro(Other,   GCHeapUsed,  bigIntsGCHeap),) \
+    IF_BIGINT(macro(Other,   MallocHeap,  bigIntsMallocHeap),) \
     macro(Other,   GCHeapAdmin, gcHeapArenaAdmin) \
     macro(Other,   GCHeapUsed,  lazyScriptsGCHeap) \
     macro(Other,   MallocHeap,  lazyScriptsMallocHeap) \
     macro(Other,   GCHeapUsed,  jitCodesGCHeap) \
     macro(Other,   GCHeapUsed,  objectGroupsGCHeap) \
     macro(Other,   MallocHeap,  objectGroupsMallocHeap) \
     macro(Other,   GCHeapUsed,  scopesGCHeap) \
     macro(Other,   MallocHeap,  scopesMallocHeap) \
--- a/js/public/ProtoKey.h
+++ b/js/public/ProtoKey.h
@@ -90,16 +90,17 @@
     real(Uint8Array,            InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint8)) \
     real(Int16Array,            InitViaClassSpec,       TYPED_ARRAY_CLASP(Int16)) \
     real(Uint16Array,           InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint16)) \
     real(Int32Array,            InitViaClassSpec,       TYPED_ARRAY_CLASP(Int32)) \
     real(Uint32Array,           InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint32)) \
     real(Float32Array,          InitViaClassSpec,       TYPED_ARRAY_CLASP(Float32)) \
     real(Float64Array,          InitViaClassSpec,       TYPED_ARRAY_CLASP(Float64)) \
     real(Uint8ClampedArray,     InitViaClassSpec,       TYPED_ARRAY_CLASP(Uint8Clamped)) \
+IF_BIGINT(real,imaginary)(BigInt, InitViaClassSpec, OCLASP(BigInt)) \
     real(Proxy,                 InitProxyClass,         &js::ProxyClass) \
     real(WeakMap,               InitWeakMapClass,       OCLASP(WeakMap)) \
     real(Map,                   InitViaClassSpec,       OCLASP(Map)) \
     real(Set,                   InitViaClassSpec,       OCLASP(Set)) \
     real(DataView,              InitViaClassSpec,       OCLASP(DataView)) \
     real(Symbol,                InitSymbolClass,        OCLASP(Symbol)) \
 IF_SAB(real,imaginary)(SharedArrayBuffer,       InitViaClassSpec, OCLASP(SharedArrayBuffer)) \
 IF_INTL(real,imaginary) (Intl,                  InitIntlClass,          CLASP(Intl)) \
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -56,17 +56,20 @@ enum class TraceKind
     // The kind associated with a nullptr.
     Null = 0x06,
 
     // The following kinds do not have an exposed C++ idiom.
     BaseShape = 0x0F,
     JitCode = 0x1F,
     LazyScript = 0x2F,
     Scope = 0x3F,
-    RegExpShared = 0x4F
+    RegExpShared = 0x4F,
+#ifdef ENABLE_BIGINT
+    BigInt = 0x5F
+#endif
 };
 const static uintptr_t OutOfLineTraceKindMask = 0x07;
 
 #define ASSERT_TRACE_KIND(tk) \
     static_assert((uintptr_t(tk) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask, \
         "mask bits are set")
 ASSERT_TRACE_KIND(JS::TraceKind::BaseShape);
 ASSERT_TRACE_KIND(JS::TraceKind::JitCode);
@@ -92,16 +95,17 @@ struct MapTypeToTraceKind {
     D(LazyScript,    js::LazyScript,    true) \
     D(Scope,         js::Scope,         true) \
     D(Object,        JSObject,          true) \
     D(ObjectGroup,   js::ObjectGroup,   true) \
     D(Script,        JSScript,          true) \
     D(Shape,         js::Shape,         true) \
     D(String,        JSString,          false) \
     D(Symbol,        JS::Symbol,        false) \
+    IF_BIGINT(D(BigInt, JS::BigInt, false),) \
     D(RegExpShared,  js::RegExpShared,  true)
 
 // Map from all public types to their trace kind.
 #define JS_EXPAND_DEF(name, type, _) \
     template <> struct MapTypeToTraceKind<type> { \
         static const JS::TraceKind kind = JS::TraceKind::name; \
     };
 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -146,16 +146,19 @@ class JS_PUBLIC_API(CallbackTracer) : pu
     // Override these methods to receive notification when an edge is visited
     // with the type contained in the callback. The default implementation
     // dispatches to the fully-generic onChild implementation, so for cases that
     // do not care about boxing overhead and do not need the actual edges,
     // just override the generic onChild.
     virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
     virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
     virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
+#ifdef ENABLE_BIGINT
+    virtual void onBigIntEdge(JS::BigInt** bip) { onChild(JS::GCCellPtr(*bip)); }
+#endif
     virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
     virtual void onShapeEdge(js::Shape** shapep) {
         onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
     }
     virtual void onObjectGroupEdge(js::ObjectGroup** groupp) {
         onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup));
     }
     virtual void onBaseShapeEdge(js::BaseShape** basep) {
@@ -238,16 +241,19 @@ class JS_PUBLIC_API(CallbackTracer) : pu
     // In C++, overriding a method hides all methods in the base class with
     // that name, not just methods with that signature. Thus, the typed edge
     // methods have to have distinct names to allow us to override them
     // individually, which is freqently useful if, for example, we only want to
     // process only one type of edge.
     void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
     void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
     void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
+#ifdef ENABLE_BIGINT
+    void dispatchToOnEdge(JS::BigInt** bip) { onBigIntEdge(bip); }
+#endif
     void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
     void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
     void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }
     void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); }
     void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); }
     void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
     void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); }
     void dispatchToOnEdge(js::RegExpShared** sharedp) { onRegExpSharedEdge(sharedp); }
--- a/js/public/TypeDecls.h
+++ b/js/public/TypeDecls.h
@@ -36,53 +36,74 @@ struct JSFreeOp;
 
 struct jsid;
 
 namespace JS {
 
 typedef unsigned char Latin1Char;
 
 class Symbol;
+#ifdef ENABLE_BIGINT
+class BigInt;
+#endif
 union Value;
 class Realm;
 struct Runtime;
 struct Zone;
 
 template <typename T> class Handle;
 template <typename T> class MutableHandle;
 template <typename T> class Rooted;
 template <typename T> class PersistentRooted;
 
 typedef Handle<JSFunction*> HandleFunction;
 typedef Handle<jsid>        HandleId;
 typedef Handle<JSObject*>   HandleObject;
 typedef Handle<JSScript*>   HandleScript;
 typedef Handle<JSString*>   HandleString;
 typedef Handle<JS::Symbol*> HandleSymbol;
+#ifdef ENABLE_BIGINT
+typedef Handle<JS::BigInt*> HandleBigInt;
+#endif
 typedef Handle<Value>       HandleValue;
 
 typedef MutableHandle<JSFunction*> MutableHandleFunction;
 typedef MutableHandle<jsid>        MutableHandleId;
 typedef MutableHandle<JSObject*>   MutableHandleObject;
 typedef MutableHandle<JSScript*>   MutableHandleScript;
 typedef MutableHandle<JSString*>   MutableHandleString;
 typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
+#ifdef ENABLE_BIGINT
+typedef MutableHandle<JS::BigInt*> MutableHandleBigInt;
+#endif
 typedef MutableHandle<Value>       MutableHandleValue;
 
 typedef Rooted<JSObject*>       RootedObject;
 typedef Rooted<JSFunction*>     RootedFunction;
 typedef Rooted<JSScript*>       RootedScript;
 typedef Rooted<JSString*>       RootedString;
 typedef Rooted<JS::Symbol*>     RootedSymbol;
+#ifdef ENABLE_BIGINT
+typedef Rooted<JS::BigInt*>     RootedBigInt;
+#endif
 typedef Rooted<jsid>            RootedId;
 typedef Rooted<JS::Value>       RootedValue;
 
 typedef PersistentRooted<JSFunction*> PersistentRootedFunction;
 typedef PersistentRooted<jsid>        PersistentRootedId;
 typedef PersistentRooted<JSObject*>   PersistentRootedObject;
 typedef PersistentRooted<JSScript*>   PersistentRootedScript;
 typedef PersistentRooted<JSString*>   PersistentRootedString;
 typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
+#ifdef ENABLE_BIGINT
+typedef PersistentRooted<JS::BigInt*> PersistentRootedBigInt;
+#endif
 typedef PersistentRooted<Value>       PersistentRootedValue;
 
 } // namespace JS
 
+#ifdef ENABLE_BIGINT
+#define IF_BIGINT(x, y) x
+#else
+#define IF_BIGINT(x, y) y
+#endif
+
 #endif /* js_TypeDecls_h */
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -1051,16 +1051,34 @@ class JS_PUBLIC_API(Concrete<JS::Symbol>
     }
 
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
     const char16_t* typeName() const override { return concreteTypeName; }
     static const char16_t concreteTypeName[];
 };
 
+#ifdef ENABLE_BIGINT
+template<>
+class JS_PUBLIC_API(Concrete<JS::BigInt>) : TracerConcrete<JS::BigInt> {
+  protected:
+    explicit Concrete(JS::BigInt* ptr) : TracerConcrete(ptr) {}
+
+  public:
+    static void construct(void* storage, JS::BigInt* ptr) {
+        new (storage) Concrete(ptr);
+    }
+
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
+};
+#endif
+
 template<>
 class JS_PUBLIC_API(Concrete<JSScript>) : TracerConcreteWithCompartment<JSScript> {
   protected:
     explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
 
   public:
     static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); }
 
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -54,16 +54,19 @@ enum JSValueType : uint8_t
     JSVAL_TYPE_INT32               = 0x01,
     JSVAL_TYPE_BOOLEAN             = 0x02,
     JSVAL_TYPE_UNDEFINED           = 0x03,
     JSVAL_TYPE_NULL                = 0x04,
     JSVAL_TYPE_MAGIC               = 0x05,
     JSVAL_TYPE_STRING              = 0x06,
     JSVAL_TYPE_SYMBOL              = 0x07,
     JSVAL_TYPE_PRIVATE_GCTHING     = 0x08,
+#ifdef ENABLE_BIGINT
+    JSVAL_TYPE_BIGINT              = 0x09,
+#endif
     JSVAL_TYPE_OBJECT              = 0x0c,
 
     /* These never appear in a jsval; they are only provided as an out-of-band value. */
     JSVAL_TYPE_UNKNOWN             = 0x20,
     JSVAL_TYPE_MISSING             = 0x21
 };
 
 static_assert(sizeof(JSValueType) == 1,
@@ -77,16 +80,19 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
     JSVAL_TAG_INT32                = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_NULL                 = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_STRING               = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
     JSVAL_TAG_SYMBOL               = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
     JSVAL_TAG_PRIVATE_GCTHING      = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
+#ifdef ENABLE_BIGINT
+    JSVAL_TAG_BIGINT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
+#endif
     JSVAL_TAG_OBJECT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
 } JS_ENUM_FOOTER(JSValueTag);
 
 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
               "compiler typed enum support is apparently buggy");
 
 #elif defined(JS_PUNBOX64)
 
@@ -96,16 +102,19 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
     JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_STRING               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
     JSVAL_TAG_SYMBOL               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
     JSVAL_TAG_PRIVATE_GCTHING      = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
+#ifdef ENABLE_BIGINT
+    JSVAL_TAG_BIGINT               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
+#endif
     JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
 } JS_ENUM_FOOTER(JSValueTag);
 
 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
               "compiler typed enum support is apparently buggy");
 
 enum JSValueShiftedTag : uint64_t
 {
@@ -113,16 +122,19 @@ enum JSValueShiftedTag : uint64_t
     JSVAL_SHIFTED_TAG_INT32           = (((uint64_t)JSVAL_TAG_INT32)           << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_UNDEFINED       = (((uint64_t)JSVAL_TAG_UNDEFINED)       << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_NULL            = (((uint64_t)JSVAL_TAG_NULL)            << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_BOOLEAN         = (((uint64_t)JSVAL_TAG_BOOLEAN)         << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_MAGIC           = (((uint64_t)JSVAL_TAG_MAGIC)           << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_STRING          = (((uint64_t)JSVAL_TAG_STRING)          << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_SYMBOL          = (((uint64_t)JSVAL_TAG_SYMBOL)          << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
+#ifdef ENABLE_BIGINT
+    JSVAL_SHIFTED_TAG_BIGINT          = (((uint64_t)JSVAL_TAG_BIGINT)          << JSVAL_TAG_SHIFT),
+#endif
     JSVAL_SHIFTED_TAG_OBJECT          = (((uint64_t)JSVAL_TAG_OBJECT)          << JSVAL_TAG_SHIFT)
 };
 
 static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
               "compiler typed enum support is apparently buggy");
 
 #endif
 
@@ -256,17 +268,17 @@ CanonicalizeNaN(double d)
 }
 
 /**
  * JS::Value is the interface for a single JavaScript Engine value.  A few
  * general notes on JS::Value:
  *
  * - JS::Value has setX() and isX() members for X in
  *
- *     { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
+ *     { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null, Object, Magic }
  *
  *   JS::Value also contains toX() for each of the non-singleton types.
  *
  * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for
  *   the magic value or a uint32_t value. By providing JSWhyMagic values when
  *   creating and checking for magic values, it is possible to assert, at
  *   runtime, that only magic values with the expected reason flow through a
  *   particular value. For example, if cx->exception has a magic value, the
@@ -338,16 +350,19 @@ union MOZ_NON_PARAM alignas(8) Value
         JSValueTag tag_;
 #  endif // MOZ_BIG_ENDIAN
         union {
             int32_t i32_;
             uint32_t u32_;
             uint32_t  boo_;     // Don't use |bool| -- it must be four bytes.
             JSString* str_;
             JS::Symbol* sym_;
+#ifdef ENABLE_BIGINT
+            JS::BigInt* bi_;
+#endif
             JSObject* obj_;
             js::gc::Cell* cell_;
             void* ptr_;
             JSWhyMagic why_;
         } payload_;
 #  if MOZ_LITTLE_ENDIAN
         JSValueTag tag_;
 #  endif // MOZ_LITTLE_ENDIAN
@@ -449,16 +464,23 @@ union MOZ_NON_PARAM alignas(8) Value
         asBits_ = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
     }
 
     void setSymbol(JS::Symbol* sym) {
         MOZ_ASSERT(js::gc::IsCellPointerValid(sym));
         asBits_ = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
     }
 
+#ifdef ENABLE_BIGINT
+    void setBigInt(JS::BigInt* bi) {
+        MOZ_ASSERT(js::gc::IsCellPointerValid(bi));
+        asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi));
+    }
+#endif
+
     void setObject(JSObject& obj) {
         MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
 
         // This should not be possible and is undefined behavior, but some
         // ObjectValue(nullptr) are sneaking in. Try to catch them here, if
         // indeed they are going through this code. I tested gcc, and it at
         // least will *not* elide the null check even though it would be
         // permitted according to the spec. The temporary is necessary to
@@ -615,16 +637,22 @@ union MOZ_NON_PARAM alignas(8) Value
     bool isString() const {
         return toTag() == JSVAL_TAG_STRING;
     }
 
     bool isSymbol() const {
         return toTag() == JSVAL_TAG_SYMBOL;
     }
 
+#ifdef ENABLE_BIGINT
+    bool isBigInt() const {
+        return toTag() == JSVAL_TAG_BIGINT;
+    }
+#endif
+
     bool isObject() const {
 #if defined(JS_NUNBOX32)
         return toTag() == JSVAL_TAG_OBJECT;
 #elif defined(JS_PUNBOX64)
         MOZ_ASSERT((asBits_ >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
         return asBits_ >= JSVAL_SHIFTED_TAG_OBJECT;
 #endif
     }
@@ -676,16 +704,20 @@ union MOZ_NON_PARAM alignas(8) Value
         static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
                       "Value type tags must correspond with JS::TraceKinds.");
         static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
                       "Value type tags must correspond with JS::TraceKinds.");
         static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
                       "Value type tags must correspond with JS::TraceKinds.");
         if (MOZ_UNLIKELY(isPrivateGCThing()))
             return JS::GCThingTraceKind(toGCThing());
+#ifdef ENABLE_BIGINT
+        if (MOZ_UNLIKELY(isBigInt()))
+            return JS::TraceKind::BigInt;
+#endif
         return JS::TraceKind(toTag() & 0x03);
     }
 
     JSWhyMagic whyMagic() const {
         MOZ_ASSERT(isMagic());
         return s_.payload_.why_;
     }
 
@@ -740,16 +772,27 @@ union MOZ_NON_PARAM alignas(8) Value
         MOZ_ASSERT(isSymbol());
 #if defined(JS_NUNBOX32)
         return s_.payload_.sym_;
 #elif defined(JS_PUNBOX64)
         return reinterpret_cast<JS::Symbol*>(asBits_ ^ JSVAL_SHIFTED_TAG_SYMBOL);
 #endif
     }
 
+#ifdef ENABLE_BIGINT
+    JS::BigInt* toBigInt() const {
+        MOZ_ASSERT(isBigInt());
+#if defined(JS_NUNBOX32)
+        return s_.payload_.bi_;
+#elif defined(JS_PUNBOX64)
+        return reinterpret_cast<JS::BigInt*>(asBits_ ^ JSVAL_SHIFTED_TAG_BIGINT);
+#endif
+    }
+#endif
+
     JSObject& toObject() const {
         MOZ_ASSERT(isObject());
 #if defined(JS_NUNBOX32)
         return *s_.payload_.obj_;
 #elif defined(JS_PUNBOX64)
         uint64_t ptrBits = asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT;
         MOZ_ASSERT(ptrBits);
         MOZ_ASSERT((ptrBits & 0x7) == 0);
@@ -857,16 +900,20 @@ union MOZ_NON_PARAM alignas(8) Value
      * cells.
      */
 
     void setPrivateGCThing(js::gc::Cell* cell) {
         MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
                    "Private GC thing Values must not be strings. Make a StringValue instead.");
         MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
                    "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
+#ifdef ENABLE_BIGINT
+        MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt,
+                   "Private GC thing Values must not be BigInts. Make a BigIntValue instead.");
+#endif
         MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
                    "Private GC thing Values must not be objects. Make an ObjectValue instead.");
 
         MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
 #if defined(JS_PUNBOX64)
         // VisualStudio cannot contain parenthesized C++ style cast and shift
         // inside decltype in template parameter:
         //   AssertionConditionType<decltype((uintptr_t(x) >> 1))>
@@ -982,16 +1029,26 @@ StringValue(JSString* str)
 static inline Value
 SymbolValue(JS::Symbol* sym)
 {
     Value v;
     v.setSymbol(sym);
     return v;
 }
 
+#ifdef ENABLE_BIGINT
+static inline Value
+BigIntValue(JS::BigInt* bi)
+{
+    Value v;
+    v.setBigInt(bi);
+    return v;
+}
+#endif
+
 static inline Value
 BooleanValue(bool boo)
 {
     Value v;
     v.setBoolean(boo);
     return v;
 }
 
@@ -1237,31 +1294,37 @@ class WrappedPtrOperations<JS::Value, Wr
     bool isTrue() const { return value().isTrue(); }
     bool isFalse() const { return value().isFalse(); }
     bool isNumber() const { return value().isNumber(); }
     bool isInt32() const { return value().isInt32(); }
     bool isInt32(int32_t i32) const { return value().isInt32(i32); }
     bool isDouble() const { return value().isDouble(); }
     bool isString() const { return value().isString(); }
     bool isSymbol() const { return value().isSymbol(); }
+#ifdef ENABLE_BIGINT
+    bool isBigInt() const { return value().isBigInt(); }
+#endif
     bool isObject() const { return value().isObject(); }
     bool isMagic() const { return value().isMagic(); }
     bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
     bool isGCThing() const { return value().isGCThing(); }
     bool isPrimitive() const { return value().isPrimitive(); }
 
     bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
     bool isObjectOrNull() const { return value().isObjectOrNull(); }
 
     bool toBoolean() const { return value().toBoolean(); }
     double toNumber() const { return value().toNumber(); }
     int32_t toInt32() const { return value().toInt32(); }
     double toDouble() const { return value().toDouble(); }
     JSString* toString() const { return value().toString(); }
     JS::Symbol* toSymbol() const { return value().toSymbol(); }
+#ifdef ENABLE_BIGINT
+    JS::BigInt* toBigInt() const { return value().toBigInt(); }
+#endif
     JSObject& toObject() const { return value().toObject(); }
     JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
     gc::Cell* toGCThing() const { return value().toGCThing(); }
     JS::TraceKind traceKind() const { return value().traceKind(); }
     void* toPrivate() const { return value().toPrivate(); }
     uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
 
     uint64_t asRawBits() const { return value().asRawBits(); }
@@ -1289,16 +1352,19 @@ class MutableWrappedPtrOperations<JS::Va
     void setDouble(double d) { value().setDouble(d); }
     void setNaN() { setDouble(JS::GenericNaN()); }
     void setBoolean(bool b) { value().setBoolean(b); }
     void setMagic(JSWhyMagic why) { value().setMagic(why); }
     bool setNumber(uint32_t ui) { return value().setNumber(ui); }
     bool setNumber(double d) { return value().setNumber(d); }
     void setString(JSString* str) { this->value().setString(str); }
     void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); }
+#ifdef ENABLE_BIGINT
+    void setBigInt(JS::BigInt* bi) { this->value().setBigInt(bi); }
+#endif
     void setObject(JSObject& obj) { this->value().setObject(obj); }
     void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); }
     void setPrivate(void* ptr) { this->value().setPrivate(ptr); }
     void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); }
     void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); }
 };
 
 /*
@@ -1317,16 +1383,19 @@ class HeapBase<JS::Value, Wrapper> : pub
     void setUndefined() { setBarriered(JS::UndefinedValue()); }
     void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
     void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
     void setNaN() { setDouble(JS::GenericNaN()); }
     void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
     void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
     void setString(JSString* str) { setBarriered(JS::StringValue(str)); }
     void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); }
+#ifdef ENABLE_BIGINT
+    void setBigInt(JS::BigInt* bi) { setBarriered(JS::BigIntValue(bi)); }
+#endif
     void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); }
     void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); }
 
     bool setNumber(uint32_t ui) {
         if (ui > JSVAL_INT_MAX) {
             setDouble((double)ui);
             return false;
         } else {
@@ -1373,16 +1442,23 @@ DispatchTyped(F f, const JS::Value& val,
         MOZ_ASSERT(gc::IsCellPointerValid(obj));
         return f(obj, mozilla::Forward<Args>(args)...);
     }
     if (val.isSymbol()) {
         JS::Symbol* sym = val.toSymbol();
         MOZ_ASSERT(gc::IsCellPointerValid(sym));
         return f(sym, mozilla::Forward<Args>(args)...);
     }
+#ifdef ENABLE_BIGINT
+    if (val.isBigInt()) {
+        JS::BigInt* bi = val.toBigInt();
+        MOZ_ASSERT(gc::IsCellPointerValid(bi));
+        return f(bi, mozilla::Forward<Args>(args)...);
+    }
+#endif
     if (MOZ_UNLIKELY(val.isPrivateGCThing())) {
         MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing()));
         return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
     }
     MOZ_ASSERT(!val.isGCThing());
     return F::defaultValue(val);
 }
 
--- a/js/rust/Cargo.toml
+++ b/js/rust/Cargo.toml
@@ -7,16 +7,19 @@ license = "MPL-2.0"
 
 [build-dependencies]
 env_logger = {version = "0.5", default-features = false} # disable `regex` to reduce code size
 bindgen = {version = "0.33.1", default-features = false} # disable `logging` to reduce code size
 cmake = "0.1"
 glob = "0.2.11"
 
 [[test]]
+name = "bigint"
+required-features = ["bigint"]
+[[test]]
 name = "callback"
 [[test]]
 name = "enumerate"
 [[test]]
 name = "evaluate"
 [[test]]
 name = "panic"
 [[test]]
@@ -34,16 +37,17 @@ name = "vec_conversion"
 
 [lib]
 doctest = false
 
 [features]
 debugmozjs = ['mozjs_sys/debugmozjs']
 promises = ['mozjs_sys/promises']
 nonzero = []
+bigint = ['mozjs_sys/bigint']
 
 [dependencies.mozjs_sys]
 path = "../src"
 
 [dependencies]
 lazy_static = "1.0"
 libc = "0.2"
 log = "0.4"
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -68,16 +68,20 @@ fn build_jsapi_bindings() {
 
     if cfg!(feature = "debugmozjs") {
         builder = builder
             .clang_arg("-DJS_GC_ZEAL")
             .clang_arg("-DDEBUG")
             .clang_arg("-DJS_DEBUG");
     }
 
+    if cfg!(feature = "bigint") {
+        builder = builder.clang_arg("-DENABLE_BIGINT");
+    }
+
     let include_dir = get_mozjs_include_dir();
     let include_dir = include_dir.to_str()
         .expect("Path to mozjs include dir should be utf-8");
     builder = builder.clang_arg("-I");
     builder = builder.clang_arg(include_dir);
 
     for ty in UNSAFE_IMPL_SYNC_TYPES {
         builder = builder.raw_line(format!("unsafe impl Sync for {} {{}}", ty));
@@ -94,16 +98,20 @@ fn build_jsapi_bindings() {
     for var in WHITELIST_VARS {
         builder = builder.whitelist_var(var);
     }
 
     for func in WHITELIST_FUNCTIONS {
         builder = builder.whitelist_function(func);
     }
 
+    if cfg!(feature = "bigint") {
+        builder = builder.whitelist_type("JS::BigInt");
+    }
+
     for ty in OPAQUE_TYPES {
         builder = builder.opaque_type(ty);
     }
 
     for ty in BLACKLIST_TYPES {
         builder = builder.blacklist_type(ty);
     }
 
--- a/js/rust/src/jsval.rs
+++ b/js/rust/src/jsval.rs
@@ -20,48 +20,54 @@ const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
 #[repr(u32)]
 #[allow(dead_code)]
 #[derive(Clone, Copy, Debug)]
 enum ValueTag {
     INT32     = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_INT32 as u32),
     UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32),
     STRING    = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32),
     SYMBOL    = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32),
+    #[cfg(feature = "bigint")]
+    BIGINT    = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32),
     BOOLEAN   = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32),
     MAGIC     = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32),
     NULL      = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32),
     OBJECT    = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_OBJECT as u32),
 }
 
 #[cfg(target_pointer_width = "32")]
 #[repr(u32)]
 #[allow(dead_code)]
 #[derive(Clone, Copy, Debug)]
 enum ValueTag {
     PRIVATE   = 0,
     INT32     = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_INT32 as u32),
     UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32),
     STRING    = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32),
     SYMBOL    = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32),
+    #[cfg(feature = "bigint")]
+    BIGINT    = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32),
     BOOLEAN   = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32),
     MAGIC     = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32),
     NULL      = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32),
     OBJECT    = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_OBJECT as u32),
 }
 
 #[cfg(target_pointer_width = "64")]
 #[repr(u64)]
 #[allow(dead_code)]
 #[derive(Clone, Copy, Debug)]
 enum ValueShiftedTag {
     MAX_DOUBLE = (((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64),
     INT32      = ((ValueTag::INT32 as u64)      << JSVAL_TAG_SHIFT),
     UNDEFINED  = ((ValueTag::UNDEFINED as u64)  << JSVAL_TAG_SHIFT),
     STRING     = ((ValueTag::STRING as u64)     << JSVAL_TAG_SHIFT),
     SYMBOL     = ((ValueTag::SYMBOL as u64)     << JSVAL_TAG_SHIFT),
+    #[cfg(feature = "bigint")]
+    BIGINT     = ((ValueTag::BIGINT as u64)     << JSVAL_TAG_SHIFT),
     BOOLEAN    = ((ValueTag::BOOLEAN as u64)    << JSVAL_TAG_SHIFT),
     MAGIC      = ((ValueTag::MAGIC as u64)      << JSVAL_TAG_SHIFT),
     NULL       = ((ValueTag::NULL as u64)       << JSVAL_TAG_SHIFT),
     OBJECT     = ((ValueTag::OBJECT as u64)     << JSVAL_TAG_SHIFT),
 }
 
 
 #[cfg(target_pointer_width = "64")]
@@ -182,16 +188,33 @@ pub fn PrivateValue(o: *const c_void) ->
 #[cfg(target_pointer_width = "32")]
 #[inline(always)]
 pub fn PrivateValue(o: *const c_void) -> JS::Value {
     let ptrBits = o as usize as u64;
     assert!((ptrBits & 1) == 0);
     BuildJSVal(ValueTag::PRIVATE, ptrBits)
 }
 
+#[inline(always)]
+#[cfg(feature = "bigint")]
+#[cfg(target_pointer_width = "64")]
+pub fn BigIntValue(b: &JS::BigInt) -> JS::Value {
+    let bits = b as *const JS::BigInt as usize as u64;
+    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
+    BuildJSVal(ValueTag::BIGINT, bits)
+}
+
+#[inline(always)]
+#[cfg(target_pointer_width = "32")]
+#[inline(always)]
+pub fn BigIntValue(s: &JS::BigInt) -> JS::Value {
+    let bits = s as *const JS::BigInt as usize as u64;
+    BuildJSVal(ValueTag::BIGINT, bits)
+}
+
 impl JS::Value {
     #[inline(always)]
     unsafe fn asBits(&self) -> u64 {
         self.asBits_
     }
 
     #[inline(always)]
     #[cfg(target_pointer_width = "64")]
@@ -359,16 +382,34 @@ impl JS::Value {
     #[cfg(target_pointer_width = "32")]
     pub fn is_symbol(&self) -> bool {
         unsafe {
             (self.asBits() >> 32) == ValueTag::SYMBOL as u64
         }
     }
 
     #[inline(always)]
+    #[cfg(feature = "bigint")]
+    #[cfg(target_pointer_width = "64")]
+    pub fn is_bigint(&self) -> bool {
+        unsafe {
+            (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64
+        }
+    }
+
+    #[inline(always)]
+    #[cfg(feature = "bigint")]
+    #[cfg(target_pointer_width = "32")]
+    pub fn is_bigint(&self) -> bool {
+        unsafe {
+            (self.asBits() >> 32) == ValueTag::BIGINT as u64
+        }
+    }
+
+    #[inline(always)]
     #[cfg(target_pointer_width = "64")]
     pub fn to_boolean(&self) -> bool {
         assert!(self.is_boolean());
         unsafe {
             (self.asBits() & JSVAL_PAYLOAD_MASK) != 0
         }
     }
 
--- a/js/rust/src/rust.rs
+++ b/js/rust/src/rust.rs
@@ -301,16 +301,22 @@ impl RootKind for *mut JSString {
     fn rootKind() -> JS::RootKind { JS::RootKind::String }
 }
 
 impl RootKind for *mut JS::Symbol {
     #[inline(always)]
     fn rootKind() -> JS::RootKind { JS::RootKind::Symbol }
 }
 
+#[cfg(feature = "bigint")]
+impl RootKind for *mut JS::BigInt {
+    #[inline(always)]
+    fn rootKind() -> JS::RootKind { JS::RootKind::BigInt }
+}
+
 impl RootKind for *mut JSScript {
     #[inline(always)]
     fn rootKind() -> JS::RootKind { JS::RootKind::Script }
 }
 
 impl RootKind for jsid {
     #[inline(always)]
     fn rootKind() -> JS::RootKind { JS::RootKind::Id }
new file mode 100644
--- /dev/null
+++ b/js/rust/tests/bigint.rs
@@ -0,0 +1,48 @@
+#[macro_use]
+extern crate js;
+
+use js::jsapi::root::JS::CompartmentOptions;
+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_bigint() {
+    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())
+        );
+
+        rooted!(in(cx) let mut rval = UndefinedValue());
+        assert!(rt.evaluate_script(global.handle(), "BigInt(0)",
+                                   "test", 1, rval.handle_mut()).is_ok());
+        assert!(rval.is_bigint());
+    }
+}
+
+#[test]
+fn is_not_bigint() {
+    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())
+        );
+
+        rooted!(in(cx) let mut rval = UndefinedValue());
+        assert!(rt.evaluate_script(global.handle(), "'not a BigInt'",
+                                   "test", 1, rval.handle_mut()).is_ok());
+        assert!(!rval.is_bigint());
+    }
+}
--- a/js/src/Cargo.toml
+++ b/js/src/Cargo.toml
@@ -3,16 +3,17 @@ name = "mozjs_sys"
 version = "0.0.0"
 authors = ["Mozilla"]
 links = "mozjs"
 build = "build.rs"
 
 [features]
 debugmozjs = []
 promises = []
+bigint = []
 
 [lib]
 name = "mozjs_sys"
 path = "lib.rs"
 
 [build-dependencies]
 num_cpus = "1.1.0"
 
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -42,16 +42,19 @@ class MOZ_STACK_CLASS SourceBufferHolder
 
 class HandleValueArray;
 
 class ObjectOpResult;
 class PropertyResult;
 
 enum class SymbolCode: uint32_t;
 
+#ifdef ENABLE_BIGINT
+class BigInt;
+#endif
 } // namespace JS
 
 // Do the importing.
 namespace js {
 
 using JS::Value;
 using JS::BooleanValue;
 using JS::DoubleValue;
@@ -107,43 +110,55 @@ using JS::TransitiveCompileOptions;
 
 using JS::Rooted;
 using JS::RootedFunction;
 using JS::RootedId;
 using JS::RootedObject;
 using JS::RootedScript;
 using JS::RootedString;
 using JS::RootedSymbol;
+#ifdef ENABLE_BIGINT
+using JS::RootedBigInt;
+#endif
 using JS::RootedValue;
 
 using JS::PersistentRooted;
 using JS::PersistentRootedFunction;
 using JS::PersistentRootedId;
 using JS::PersistentRootedObject;
 using JS::PersistentRootedScript;
 using JS::PersistentRootedString;
 using JS::PersistentRootedSymbol;
+#ifdef ENABLE_BIGINT
+using JS::PersistentRootedBigInt;
+#endif
 using JS::PersistentRootedValue;
 
 using JS::Handle;
 using JS::HandleFunction;
 using JS::HandleId;
 using JS::HandleObject;
 using JS::HandleScript;
 using JS::HandleString;
 using JS::HandleSymbol;
+#ifdef ENABLE_BIGINT
+using JS::HandleBigInt;
+#endif
 using JS::HandleValue;
 
 using JS::MutableHandle;
 using JS::MutableHandleFunction;
 using JS::MutableHandleId;
 using JS::MutableHandleObject;
 using JS::MutableHandleScript;
 using JS::MutableHandleString;
 using JS::MutableHandleSymbol;
+#ifdef ENABLE_BIGINT
+using JS::MutableHandleBigInt;
+#endif
 using JS::MutableHandleValue;
 
 using JS::NullHandleValue;
 using JS::UndefinedHandleValue;
 using JS::TrueHandleValue;
 using JS::FalseHandleValue;
 
 using JS::HandleValueArray;
@@ -152,11 +167,14 @@ using JS::ObjectOpResult;
 using JS::PropertyResult;
 
 using JS::Realm;
 using JS::Zone;
 
 using JS::Symbol;
 using JS::SymbolCode;
 
+#ifdef ENABLE_BIGINT
+using JS::BigInt;
+#endif
 } /* namespace js */
 
 #endif /* NamespaceImports_h */
--- a/js/src/build.rs
+++ b/js/src/build.rs
@@ -11,37 +11,35 @@ fn main() {
     let out_dir = env::var("OUT_DIR").expect("Should have env var OUT_DIR");
     let target = env::var("TARGET").expect("Should have env var TARGET");
 
     let js_src = env::var("CARGO_MANIFEST_DIR").expect("Should have env var CARGO_MANIFEST_DIR");
 
     env::set_var("MAKEFLAGS", format!("-j{}", num_cpus::get()));
     env::set_current_dir(&js_src).unwrap();
 
-    let variant = if cfg!(feature = "debugmozjs") {
-        "plaindebug"
-    } else {
-        "plain"
-    };
+    let variant = format!("{}{}",
+                          if cfg!(feature = "bigint") { "bigint" } else { "plain" },
+                          if cfg!(feature = "debugmozjs") { "debug" } else { "" });
 
     let python = env::var("PYTHON").unwrap_or("python2.7".into());
     let mut cmd = Command::new(&python);
     cmd.args(&["./devtools/automation/autospider.py",
                // Only build SpiderMonkey, don't run all the tests.
                "--build-only",
                // Disable Mozilla's jemalloc; Rust has its own jemalloc that we
                // can swap in instead and everything using a single malloc is
                // good.
                "--no-jemalloc",
                // Don't try to clobber the output directory. Without
                // this option, the build will fail because the directory
                // already exists but wasn't created by autospider.
                "--dep",
                "--objdir", &out_dir,
-               variant])
+               &variant])
         .env("SOURCE", &js_src)
         .env("PWD", &js_src)
         .stdout(Stdio::inherit())
         .stderr(Stdio::inherit());
     println!("Running command: {:?}", cmd);
     let result = cmd
         .status()
         .expect("Should spawn autospider OK");
@@ -49,16 +47,20 @@ fn main() {
 
     println!("cargo:rustc-link-search=native={}/js/src/build", out_dir);
     println!("cargo:rustc-link-search=native={}/js/src", out_dir);
     println!("cargo:rustc-link-lib=static=js_static");
 
     println!("cargo:rustc-link-search=native={}/dist/bin", out_dir);
     println!("cargo:rustc-link-lib=nspr4");
 
+    if cfg!(feature = "bigint") {
+        println!("cargo:rustc-link-lib=gmp");
+    }
+
     if target.contains("windows") {
         println!("cargo:rustc-link-lib=winmm");
         if target.contains("gnu") {
             println!("cargo:rustc-link-lib=stdc++");
         }
     } else {
         println!("cargo:rustc-link-lib=stdc++");
     }
--- a/js/src/build/moz.build
+++ b/js/src/build/moz.build
@@ -29,16 +29,21 @@ else:
 FORCE_STATIC_LIB = True
 STATIC_LIBRARY_NAME = 'js_static'
 
 if CONFIG['ENABLE_INTL_API']:
     USE_LIBS += [
         'icu',
     ]
 
+if CONFIG['ENABLE_BIGINT']:
+    OS_LIBS += [
+        'gmp',
+    ]
+
 USE_LIBS += [
     'nspr',
     'zlib',
 ]
 
 if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'):
     OS_LIBS += [
         'm',
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -1267,16 +1267,22 @@ ArrayJoinDenseKernel(JSContext* cx, Sepa
              * Object stringifying could modify the initialized length or make
              * the array sparse. Delegate it to a separate loop to keep this
              * one tight.
              *
              * Symbol stringifying is a TypeError, so into the slow path
              * with those as well.
              */
             break;
+        } else if (IF_BIGINT(elem.isBigInt(), false)) {
+            // ToString(bigint) doesn't access bigint.toString or
+            // anything like that, so it can't mutate the array we're
+            // walking through, so it *could* be handled here. We don't
+            // do so yet for reasons of initial-implementation economy.
+            break;
         } else {
             MOZ_ASSERT(elem.isMagic(JS_ELEMENTS_HOLE) || elem.isNullOrUndefined());
         }
 
         // Steps 7.a, 7.e.
         if (++(*numProcessed) != length && !sepOp(cx, sb))
             return false;
     }
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/BigInt.cpp
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "builtin/BigInt.h"
+
+#include "jsapi.h"
+
+#include "builtin/TypedObject.h"
+#include "gc/Tracer.h"
+#include "js/TracingAPI.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/BigIntType.h"
+#include "vm/SelfHosting.h"
+#include "vm/TaggedProto.h"
+
+#include "vm/JSObject-inl.h"
+
+using namespace js;
+
+static MOZ_ALWAYS_INLINE bool
+IsBigInt(HandleValue v)
+{
+    return v.isBigInt() || (v.isObject() && v.toObject().is<BigIntObject>());
+}
+
+static JSObject*
+CreateBigIntPrototype(JSContext* cx, JSProtoKey key)
+{
+    return GlobalObject::createBlankPrototype<PlainObject>(cx, cx->global());
+}
+
+// BigInt proposal section 5.1.3
+static bool
+BigIntConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    // Step 1.
+    if (args.isConstructing()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR, "BigInt");
+        return false;
+    }
+
+    // Step 2.
+    RootedValue v(cx, args.get(0));
+    if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
+        return false;
+
+    // Steps 3-4.
+    BigInt* bi = v.isNumber()
+                 ? NumberToBigInt(cx, v.toNumber())
+                 : ToBigInt(cx, v);
+    if (!bi)
+        return false;
+
+    args.rval().setBigInt(bi);
+    return true;
+}
+
+JSObject*
+BigIntObject::create(JSContext* cx, HandleBigInt bigInt)
+{
+    RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
+    if (!obj)
+        return nullptr;
+    BigIntObject& bn = obj->as<BigIntObject>();
+    bn.setFixedSlot(PRIMITIVE_VALUE_SLOT, BigIntValue(bigInt));
+    return &bn;
+}
+
+BigInt*
+BigIntObject::unbox() const
+{
+    return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBigInt();
+}
+
+bool
+js::intrinsic_ToBigInt(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+
+    BigInt* result = ToBigInt(cx, args[0]);
+    if (!result)
+        return false;
+
+    args.rval().setBigInt(result);
+    return true;
+}
+
+// BigInt proposal section 5.3.4
+bool
+BigIntObject::valueOf_impl(JSContext* cx, const CallArgs& args)
+{
+    // Step 1.
+    HandleValue thisv = args.thisv();
+    MOZ_ASSERT(IsBigInt(thisv));
+    RootedBigInt bi(cx, thisv.isBigInt()
+                        ? thisv.toBigInt()
+                        : thisv.toObject().as<BigIntObject>().unbox());
+
+    args.rval().setBigInt(bi);
+    return true;
+}
+
+bool
+BigIntObject::valueOf(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsBigInt, valueOf_impl>(cx, args);
+}
+
+// BigInt proposal section 5.3.3
+bool
+BigIntObject::toString_impl(JSContext* cx, const CallArgs& args)
+{
+    // Step 1.
+    HandleValue thisv = args.thisv();
+    MOZ_ASSERT(IsBigInt(thisv));
+    RootedBigInt bi(cx, thisv.isBigInt()
+                        ? thisv.toBigInt()
+                        : thisv.toObject().as<BigIntObject>().unbox());
+
+    // Steps 2-3.
+    uint8_t radix = 10;
+
+    // Steps 4-5.
+    if (args.hasDefined(0)) {
+        double d;
+        if (!ToInteger(cx, args[0], &d))
+            return false;
+        if (d < 2 || d > 36) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_RADIX);
+            return false;
+        }
+        radix = d;
+    }
+
+    // Steps 6-7.
+    JSLinearString* str = BigInt::toString(cx, bi, radix);
+    if (!str)
+        return false;
+    args.rval().setString(str);
+    return true;
+}
+
+bool
+BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
+}
+
+// BigInt proposal section 5.3.2. "This function is
+// implementation-dependent, and it is permissible, but not encouraged,
+// for it to return the same thing as toString."
+bool
+BigIntObject::toLocaleString_impl(JSContext* cx, const CallArgs& args)
+{
+    HandleValue thisv = args.thisv();
+    MOZ_ASSERT(IsBigInt(thisv));
+    RootedBigInt bi(cx, thisv.isBigInt()
+                        ? thisv.toBigInt()
+                        : thisv.toObject().as<BigIntObject>().unbox());
+
+    RootedString str(cx, BigInt::toString(cx, bi, 10));
+    if (!str)
+        return false;
+    args.rval().setString(str);
+    return true;
+}
+
+bool
+BigIntObject::toLocaleString(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsBigInt, toLocaleString_impl>(cx, args);
+}
+
+const ClassSpec BigIntObject::classSpec_ = {
+    GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
+    CreateBigIntPrototype,
+    nullptr,
+    nullptr,
+    BigIntObject::methods,
+    BigIntObject::properties
+};
+
+const Class BigIntObject::class_ = {
+    "BigInt",
+    JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
+    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
+    JS_NULL_CLASS_OPS,
+    &BigIntObject::classSpec_
+};
+
+const JSPropertySpec BigIntObject::properties[] = {
+    // BigInt proposal section 5.3.5
+    JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY),
+    JS_PS_END
+};
+
+const JSFunctionSpec BigIntObject::methods[] = {
+    JS_FN("valueOf", valueOf, 0, 0),
+    JS_FN("toString", toString, 0, 0),
+    JS_FN("toLocaleString", toLocaleString, 0, 0),
+    JS_FS_END
+};
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/BigInt.h
@@ -0,0 +1,53 @@
+/* -*- 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/. */
+
+#ifndef builtin_BigInt_h
+#define builtin_BigInt_h
+
+#include "js/Class.h"
+#include "js/RootingAPI.h"
+#include "vm/BigIntType.h"
+#include "vm/NativeObject.h"
+
+namespace js {
+
+class GlobalObject;
+
+class BigIntObject : public NativeObject
+{
+    static const unsigned PRIMITIVE_VALUE_SLOT = 0;
+    static const unsigned RESERVED_SLOTS = 1;
+
+  public:
+    static const ClassSpec classSpec_;
+    static const Class class_;
+
+    static JSObject* create(JSContext* cx, JS::Handle<JS::BigInt*> bi);
+
+    // Methods defined on BigInt.prototype.
+    static bool valueOf_impl(JSContext* cx, const CallArgs& args);
+    static bool valueOf(JSContext* cx, unsigned argc, JS::Value* vp);
+    static bool toString_impl(JSContext* cx, const CallArgs& args);
+    static bool toString(JSContext* cx, unsigned argc, JS::Value* vp);
+    static bool toLocaleString_impl(JSContext* cx, const CallArgs& args);
+    static bool toLocaleString(JSContext* cx, unsigned argc, JS::Value* vp);
+
+    JS::BigInt* unbox() const;
+
+  private:
+    static const JSPropertySpec properties[];
+    static const JSFunctionSpec methods[];
+};
+
+extern JSObject*
+InitBigIntClass(JSContext* cx, Handle<GlobalObject*> global);
+
+extern bool
+intrinsic_ToBigInt(JSContext* cx, unsigned argc, JS::Value* vp);
+
+} // namespace js
+
+#endif
--- a/js/src/builtin/Boolean.cpp
+++ b/js/src/builtin/Boolean.cpp
@@ -10,16 +10,19 @@
 
 #include "builtin/Boolean-inl.h"
 
 #include "jsapi.h"
 #include "jstypes.h"
 
 #include "jit/InlinableNatives.h"
 #include "util/StringBuffer.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/GlobalObject.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/ProxyObject.h"
 
 #include "vm/BooleanObject-inl.h"
 
@@ -159,12 +162,16 @@ js::BooleanToString(JSContext* cx, bool 
     return b ? cx->names().true_ : cx->names().false_;
 }
 
 JS_PUBLIC_API(bool)
 js::ToBooleanSlow(HandleValue v)
 {
     if (v.isString())
         return v.toString()->length() != 0;
+#ifdef ENABLE_BIGINT
+    if (v.isBigInt())
+        return v.toBigInt()->toBoolean();
+#endif
 
     MOZ_ASSERT(v.isObject());
     return !EmulatesUndefined(&v.toObject());
 }
--- a/js/src/builtin/JSON.cpp
+++ b/js/src/builtin/JSON.cpp
@@ -10,16 +10,19 @@
 #include "mozilla/Range.h"
 #include "mozilla/ScopeExit.h"
 
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "builtin/Array.h"
+#ifdef ENABLE_BIGINT
+#include "builtin/BigInt.h"
+#endif
 #include "builtin/String.h"
 #include "util/StringBuffer.h"
 #include "vm/Interpreter.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSONParser.h"
 
@@ -286,16 +289,21 @@ PreprocessValue(JSContext* cx, HandleObj
             JSString* str = ToStringSlow<CanGC>(cx, vp);
             if (!str)
                 return false;
             vp.setString(str);
         } else if (cls == ESClass::Boolean) {
             if (!Unbox(cx, obj, vp))
                 return false;
         }
+#ifdef ENABLE_BIGINT
+        else if (cls == ESClass::BigInt) {
+            vp.setBigInt(obj->as<BigIntObject>().unbox());
+        }
+#endif
     }
 
     return true;
 }
 
 /*
  * Determines whether a value which has passed by ES5 150.2.3 Str steps 1-4's
  * gauntlet will result in Str returning |undefined|.  This function is used to
@@ -582,16 +590,24 @@ Str(JSContext* cx, const Value& v, Strin
                            "reachable non-finite numbers");
                 return scx->sb.append("null");
             }
         }
 
         return NumberValueToStringBuffer(cx, v, scx->sb);
     }
 
+#ifdef ENABLE_BIGINT
+    /* Step 10 in the BigInt proposal. */
+    if (v.isBigInt()) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BIGINT_NOT_SERIALIZABLE);
+        return false;
+    }
+#endif
+
     /* Step 10. */
     MOZ_ASSERT(v.isObject());
     RootedObject obj(cx, &v.toObject());
 
     MOZ_ASSERT(!scx->maybeSafely || obj->is<PlainObject>() || obj->is<ArrayObject>(),
                "input to JS::ToJSONMaybeSafely must not include reachable "
                "objects that are neither arrays nor plain objects");
 
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -52,17 +52,18 @@ HashableValue::setValue(JSContext* cx, H
         } else {
             value = v;
         }
     } else {
         value = v;
     }
 
     MOZ_ASSERT(value.isUndefined() || value.isNull() || value.isBoolean() || value.isNumber() ||
-               value.isString() || value.isSymbol() || value.isObject());
+               value.isString() || value.isSymbol() || value.isObject() ||
+               IF_BIGINT(value.isBigInt(), false));
     return true;
 }
 
 static HashNumber
 HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs)
 {
     // HashableValue::setValue normalizes values so that the SameValue relation
     // on HashableValues is the same as the == relationship on
@@ -72,16 +73,20 @@ HashValue(const Value& v, const mozilla:
     // from the string contents rather than any pointer; to avoid revealing
     // addresses, pointer-based hash codes are computed using the
     // HashCodeScrambler.
 
     if (v.isString())
         return v.toString()->asAtom().hash();
     if (v.isSymbol())
         return v.toSymbol()->hash();
+#ifdef ENABLE_BIGINT
+    if (v.isBigInt())
+        return v.toBigInt()->hash();
+#endif
     if (v.isObject())
         return hcs.scramble(v.asRawBits());
 
     MOZ_ASSERT(!v.isGCThing(), "do not reveal pointers via hash codes");
     return mozilla::HashGeneric(v.asRawBits());
 }
 
 HashNumber
@@ -91,22 +96,34 @@ HashableValue::hash(const mozilla::HashC
 }
 
 bool
 HashableValue::operator==(const HashableValue& other) const
 {
     // Two HashableValues are equal if they have equal bits.
     bool b = (value.asRawBits() == other.value.asRawBits());
 
+#ifdef ENABLE_BIGINT
+    // BigInt values are considered equal if they represent the same
+    // integer. This test should use a comparison function that doesn't
+    // require a JSContext once one is defined in the BigInt class.
+    if (!b && (value.isBigInt() && other.value.isBigInt())) {
+        JSContext* cx = TlsContext.get();
+        RootedValue valueRoot(cx, value);
+        RootedValue otherRoot(cx, other.value);
+        SameValue(cx, valueRoot, otherRoot, &b);
+    }
+#endif
+
 #ifdef DEBUG
     bool same;
     JSContext* cx = TlsContext.get();
     RootedValue valueRoot(cx, value);
     RootedValue otherRoot(cx, other.value);
-    MOZ_ASSERT(SameValue(nullptr, valueRoot, otherRoot, &same));
+    MOZ_ASSERT(SameValue(cx, valueRoot, otherRoot, &same));
     MOZ_ASSERT(same == b);
 #endif
     return b;
 }
 
 HashableValue
 HashableValue::trace(JSTracer* trc) const
 {
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -3,16 +3,19 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/Object.h"
 
 #include "mozilla/MaybeOneOf.h"
 
+#ifdef ENABLE_BIGINT
+#include "builtin/BigInt.h"
+#endif
 #include "builtin/Eval.h"
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/String.h"
 #include "frontend/BytecodeCompiler.h"
 #include "jit/InlinableNatives.h"
 #include "js/UniquePtr.h"
 #include "util/StringBuffer.h"
 #include "vm/AsyncFunction.h"
@@ -466,16 +469,21 @@ GetBuiltinTagSlow(JSContext* cx, HandleO
         builtinTag.set(cx->names().objectNumber);
         return true;
       case ESClass::Date:
         builtinTag.set(cx->names().objectDate);
         return true;
       case ESClass::RegExp:
         builtinTag.set(cx->names().objectRegExp);
         return true;
+#ifdef ENABLE_BIGINT
+      case ESClass::BigInt:
+        builtinTag.set(cx->names().objectBigInt);
+        return true;
+#endif
       default:
         if (obj->isCallable()) {
             // Non-standard: Prevent <object> from showing up as Function.
             RootedObject unwrapped(cx, CheckedUnwrap(obj));
             if (!unwrapped || !unwrapped->getClass()->isDOMClass()) {
                 builtinTag.set(cx->names().objectFunction);
                 return true;
             }
@@ -525,16 +533,21 @@ GetBuiltinTagFast(JSObject* obj, const C
     if (obj->is<ErrorObject>())
         return cx->names().objectError;
 
     if (obj->isCallable() && !obj->getClass()->isDOMClass()) {
         // Non-standard: Prevent <object> from showing up as Function.
         return cx->names().objectFunction;
     }
 
+#ifdef ENABLE_BIGINT
+    if (obj->is<BigIntObject>())
+        return cx->names().objectBigInt;
+#endif
+
     return nullptr;
 }
 
 // ES6 19.1.3.6
 bool
 js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
new file mode 100644
--- /dev/null
+++ b/js/src/devtools/automation/variants/bigint
@@ -0,0 +1,7 @@
+{
+    "configure-args": "--enable-bigint",
+    "optimize": true,
+    "env": {
+        "JSTESTS_EXTRA_ARGS": "--jitflags=all"
+    }
+}
new file mode 100644
--- /dev/null
+++ b/js/src/devtools/automation/variants/bigintdebug
@@ -0,0 +1,7 @@
+{
+    "configure-args": "--enable-bigint",
+    "debug": true,
+    "env": {
+        "JSTESTS_EXTRA_ARGS": "--jitflags=debug"
+    }
+}
--- a/js/src/devtools/automation/variants/msan
+++ b/js/src/devtools/automation/variants/msan
@@ -4,10 +4,11 @@
     "debug": false,
     "compiler": "clang",
     "env": {
         "JITTEST_EXTRA_ARGS": "--jitflags=interp --ignore-timeouts={DIR}/cgc-jittest-timeouts.txt",
         "JSTESTS_EXTRA_ARGS": "--jitflags=interp --exclude-file={DIR}/cgc-jstests-slow.txt",
         "MSAN_OPTIONS": "external_symbolizer_path={TOOLTOOL_CHECKOUT}/clang/bin/llvm-symbolizer:log_path={OUTDIR}/sanitize_log"
     },
     "ignore-test-failures": "true",
-    "max-errors": 2
+    "max-errors": 6,
+    "use_minidump": false
 }
--- a/js/src/gc/AllocKind.h
+++ b/js/src/gc/AllocKind.h
@@ -59,16 +59,17 @@ namespace gc {
     D(SHAPE,               Shape,        js::Shape,         js::Shape,         true,   false) \
     D(ACCESSOR_SHAPE,      Shape,        js::AccessorShape, js::AccessorShape, true,   false) \
     D(BASE_SHAPE,          BaseShape,    js::BaseShape,     js::BaseShape,     true,   false) \
     D(OBJECT_GROUP,        ObjectGroup,  js::ObjectGroup,   js::ObjectGroup,   true,   false) \
     D(EXTERNAL_STRING,     String,       JSExternalString,  JSExternalString,  true,   false) \
     D(FAT_INLINE_ATOM,     String,       js::FatInlineAtom, js::FatInlineAtom, true,   false) \
     D(ATOM,                String,       js::NormalAtom,    js::NormalAtom,    true,   false) \
     D(SYMBOL,              Symbol,       JS::Symbol,        JS::Symbol,        true,   false) \
+    IF_BIGINT(D(BIGINT,    BigInt,       JS::BigInt,        JS::BigInt,        true,   false),) \
     D(JITCODE,             JitCode,      js::jit::JitCode,  js::jit::JitCode,  false,  false) \
     D(SCOPE,               Scope,        js::Scope,         js::Scope,         true,   false) \
     D(REGEXP_SHARED,       RegExpShared, js::RegExpShared,  js::RegExpShared,  true,   false)
 
 #define FOR_EACH_NURSERY_STRING_ALLOCKIND(D) \
     D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString, true,   true) \
     D(STRING,              String,        JSString,          JSString,          true,   true)
 
--- a/js/src/gc/AtomMarking.cpp
+++ b/js/src/gc/AtomMarking.cpp
@@ -185,17 +185,20 @@ AtomMarkingRuntime::markAtomValue(JSCont
         if (value.toString()->isAtom())
             markAtom(cx, &value.toString()->asAtom());
         return;
     }
     if (value.isSymbol()) {
         markAtom(cx, value.toSymbol());
         return;
     }
-    MOZ_ASSERT_IF(value.isGCThing(), value.isObject() || value.isPrivateGCThing());
+    MOZ_ASSERT_IF(value.isGCThing(),
+                  value.isObject() ||
+                  value.isPrivateGCThing() ||
+                  IF_BIGINT(value.isBigInt(), false));
 }
 
 void
 AtomMarkingRuntime::adoptMarkedAtoms(Zone* target, Zone* source)
 {
     MOZ_ASSERT(CurrentThreadCanAccessZone(source));
     MOZ_ASSERT(CurrentThreadCanAccessZone(target));
     target->markedAtoms().bitwiseOrWith(source->markedAtoms());
@@ -267,17 +270,20 @@ AtomMarkingRuntime::valueIsMarked(Zone* 
         if (value.toString()->isAtom())
             return atomIsMarked(zone, &value.toString()->asAtom());
         return true;
     }
 
     if (value.isSymbol())
         return atomIsMarked(zone, value.toSymbol());
 
-    MOZ_ASSERT_IF(value.isGCThing(), value.isObject() || value.isPrivateGCThing());
+    MOZ_ASSERT_IF(value.isGCThing(),
+                  value.isObject() ||
+                  value.isPrivateGCThing() ||
+                  IF_BIGINT(value.isBigInt(), false));
     return true;
 }
 
 #endif // DEBUG
 
 } // namespace gc
 
 #ifdef DEBUG
--- a/js/src/gc/DeletePolicy.h
+++ b/js/src/gc/DeletePolicy.h
@@ -3,16 +3,19 @@
  * 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 gc_DeletePolicy_h
 #define gc_DeletePolicy_h
 
 #include "js/TracingAPI.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 
 namespace js {
 namespace gc {
 
 struct ClearEdgesTracer : public JS::CallbackTracer
 {
     ClearEdgesTracer();
 
@@ -21,16 +24,19 @@ struct ClearEdgesTracer : public JS::Cal
 #endif
 
     template <typename T>
     inline void clearEdge(T** thingp);
 
     void onObjectEdge(JSObject** objp) override;
     void onStringEdge(JSString** strp) override;
     void onSymbolEdge(JS::Symbol** symp) override;
+#ifdef ENABLE_BIGINT
+    void onBigIntEdge(JS::BigInt** bip) override;
+#endif
     void onScriptEdge(JSScript** scriptp) override;
     void onShapeEdge(js::Shape** shapep) override;
     void onObjectGroupEdge(js::ObjectGroup** groupp) override;
     void onBaseShapeEdge(js::BaseShape** basep) override;
     void onJitCodeEdge(js::jit::JitCode** codep) override;
     void onLazyScriptEdge(js::LazyScript** lazyp) override;
     void onScopeEdge(js::Scope** scopep) override;
     void onRegExpSharedEdge(js::RegExpShared** sharedp) override;
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -219,16 +219,19 @@
 #include "gc/Policy.h"
 #include "gc/WeakMap.h"
 #include "jit/BaselineJIT.h"
 #include "jit/IonCode.h"
 #include "jit/JitcodeMap.h"
 #include "js/SliceBudget.h"
 #include "proxy/DeadObjectProxy.h"
 #include "util/Windows.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/Debugger.h"
 #include "vm/GeckoProfiler.h"
 #include "vm/JSAtom.h"
 #include "vm/JSCompartment.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Printer.h"
@@ -490,17 +493,20 @@ static const FinalizePhase BackgroundFin
     },
     {
         gcstats::PhaseKind::SWEEP_STRING, {
             AllocKind::FAT_INLINE_STRING,
             AllocKind::STRING,
             AllocKind::EXTERNAL_STRING,
             AllocKind::FAT_INLINE_ATOM,
             AllocKind::ATOM,
-            AllocKind::SYMBOL
+            AllocKind::SYMBOL,
+#ifdef ENABLE_BIGINT
+            AllocKind::BIGINT
+#endif
         }
     },
     {
         gcstats::PhaseKind::SWEEP_SHAPE, {
             AllocKind::SHAPE,
             AllocKind::ACCESSOR_SHAPE,
             AllocKind::BASE_SHAPE,
             AllocKind::OBJECT_GROUP
@@ -8431,16 +8437,20 @@ JS::GCCellPtr::GCCellPtr(const Value& v)
   : ptr(0)
 {
     if (v.isString())
         ptr = checkedCast(v.toString(), JS::TraceKind::String);
     else if (v.isObject())
         ptr = checkedCast(&v.toObject(), JS::TraceKind::Object);
     else if (v.isSymbol())
         ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol);
+#ifdef ENABLE_BIGINT
+    else if (v.isBigInt())
+        ptr = checkedCast(v.toBigInt(), JS::TraceKind::BigInt);
+#endif
     else if (v.isPrivateGCThing())
         ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind());
     else
         ptr = checkedCast(nullptr, JS::TraceKind::Null);
 }
 
 JS::TraceKind
 JS::GCCellPtr::outOfLineKind() const
@@ -9133,16 +9143,19 @@ js::gc::ClearEdgesTracer::clearEdge(S** 
     InternalBarrierMethods<S*>::preBarrier(*thingp);
     InternalBarrierMethods<S*>::postBarrier(thingp, *thingp, nullptr);
     *thingp = nullptr;
 }
 
 void js::gc::ClearEdgesTracer::onObjectEdge(JSObject** objp) { clearEdge(objp); }
 void js::gc::ClearEdgesTracer::onStringEdge(JSString** strp) { clearEdge(strp); }
 void js::gc::ClearEdgesTracer::onSymbolEdge(JS::Symbol** symp) { clearEdge(symp); }
+#ifdef ENABLE_BIGINT
+void js::gc::ClearEdgesTracer::onBigIntEdge(JS::BigInt** bip) { clearEdge(bip); }
+#endif
 void js::gc::ClearEdgesTracer::onScriptEdge(JSScript** scriptp) { clearEdge(scriptp); }
 void js::gc::ClearEdgesTracer::onShapeEdge(js::Shape** shapep) { clearEdge(shapep); }
 void js::gc::ClearEdgesTracer::onObjectGroupEdge(js::ObjectGroup** groupp) { clearEdge(groupp); }
 void js::gc::ClearEdgesTracer::onBaseShapeEdge(js::BaseShape** basep) { clearEdge(basep); }
 void js::gc::ClearEdgesTracer::onJitCodeEdge(js::jit::JitCode** codep) { clearEdge(codep); }
 void js::gc::ClearEdgesTracer::onLazyScriptEdge(js::LazyScript** lazyp) { clearEdge(lazyp); }
 void js::gc::ClearEdgesTracer::onScopeEdge(js::Scope** scopep) { clearEdge(scopep); }
 void js::gc::ClearEdgesTracer::onRegExpSharedEdge(js::RegExpShared** sharedp) { clearEdge(sharedp); }
--- a/js/src/gc/Marking-inl.h
+++ b/js/src/gc/Marking-inl.h
@@ -6,16 +6,20 @@
 
 #ifndef gc_Marking_inl_h
 #define gc_Marking_inl_h
 
 #include "gc/Marking.h"
 
 #include "gc/RelocationOverlay.h"
 
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
+
 namespace js {
 namespace gc {
 
 template <typename T>
 struct MightBeForwarded
 {
     static_assert(mozilla::IsBaseOf<Cell, T>::value,
                   "T must derive from Cell");
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -16,16 +16,19 @@
 
 #include "builtin/ModuleObject.h"
 #include "gc/GCInternals.h"
 #include "gc/Policy.h"
 #include "jit/IonCode.h"
 #include "js/SliceBudget.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/ArrayObject.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/Debugger.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/RegExpObject.h"
 #include "vm/RegExpShared.h"
 #include "vm/Scope.h"
 #include "vm/Shape.h"
 #include "vm/SymbolType.h"
 #include "vm/TypedArrayObject.h"
@@ -889,16 +892,19 @@ js::GCMarker::markAndTraceChildren(T* th
     if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
         return;
     if (mark(thing))
         thing->traceChildren(this);
 }
 namespace js {
 template <> void GCMarker::traverse(BaseShape* thing) { markAndTraceChildren(thing); }
 template <> void GCMarker::traverse(JS::Symbol* thing) { markAndTraceChildren(thing); }
+#ifdef ENABLE_BIGINT
+template <> void GCMarker::traverse(JS::BigInt* thing) { markAndTraceChildren(thing); }
+#endif
 template <> void GCMarker::traverse(RegExpShared* thing) { markAndTraceChildren(thing); }
 } // namespace js
 
 // Strings, LazyScripts, Shapes, and Scopes are extremely common, but have
 // simple patterns of recursion. We traverse trees of these edges immediately,
 // with aggressive, manual inlining, implemented by eagerlyTraceChildren.
 template <typename T>
 void
@@ -1545,16 +1551,24 @@ js::GCMarker::lazilyMarkChildren(ObjectG
 
     if (TypeDescr* descr = group->maybeTypeDescr())
         traverseEdge(group, static_cast<JSObject*>(descr));
 
     if (JSFunction* fun = group->maybeInterpretedFunction())
         traverseEdge(group, static_cast<JSObject*>(fun));
 }
 
+#ifdef ENABLE_BIGINT
+void
+JS::BigInt::traceChildren(JSTracer* trc)
+{
+    return;
+}
+#endif
+
 struct TraverseObjectFunctor
 {
     template <typename T>
     void operator()(T* thing, GCMarker* gcmarker, JSObject* src) {
         gcmarker->traverseEdge(src, *thing);
     }
 };
 
@@ -1689,17 +1703,18 @@ ObjectDenseElementsMayBeMarkable(NativeO
         return true;
 
     // This typeset doesn't escape this function so avoid sweeping here.
     HeapTypeSet* typeSet = group->maybeGetPropertyDontCheckGeneration(JSID_VOID);
     if (!typeSet)
         return true;
 
     static const uint32_t flagMask =
-        TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT;
+        TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT |
+        IF_BIGINT(TYPE_FLAG_BIGINT, 0);
     bool mayBeMarkable = typeSet->hasAnyFlag(flagMask) || typeSet->getObjectCount() != 0;
 
 #ifdef DEBUG
     if (!mayBeMarkable) {
         const Value* elements = nobj->getDenseElementsAllowCopyOnWrite();
         for (unsigned i = 0; i < nobj->getDenseInitializedLength(); i++)
             MOZ_ASSERT(!elements[i].isGCThing());
     }
@@ -1803,17 +1818,23 @@ GCMarker::processMarkStackTop(SliceBudge
             if (mark(obj2)) {
                 // Save the rest of this value array for later and start scanning obj2's children.
                 pushValueArray(obj, vp, end);
                 obj = obj2;
                 goto scan_obj;
             }
         } else if (v.isSymbol()) {
             traverseEdge(obj, v.toSymbol());
-        } else if (v.isPrivateGCThing()) {
+        }
+#ifdef ENABLE_BIGINT
+        else if (v.isBigInt()) {
+            traverseEdge(obj, v.toBigInt());
+        }
+#endif
+        else if (v.isPrivateGCThing()) {
             // v.toGCCellPtr cannot be inlined, so construct one manually.
             Cell* cell = v.toGCThing();
             traverseEdge(obj, JS::GCCellPtr(cell, cell->getTraceKind()));
         }
     }
     return;
 
   scan_obj:
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -104,27 +104,34 @@ template <typename S, typename T>
 struct RewrapTaggedPointer{};
 #define DECLARE_REWRAP(S, T, method, prefix) \
     template <> struct RewrapTaggedPointer<S, T> { \
         static S wrap(T* thing) { return method ( prefix thing ); } \
     }
 DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, );
 DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, );
 DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, );
+#ifdef ENABLE_BIGINT
+DECLARE_REWRAP(JS::Value, JS::BigInt, JS::BigIntValue, );
+#endif
 DECLARE_REWRAP(jsid, JSString, NON_INTEGER_ATOM_TO_JSID, (JSAtom*));
 DECLARE_REWRAP(jsid, JS::Symbol, SYMBOL_TO_JSID, );
 DECLARE_REWRAP(js::TaggedProto, JSObject, js::TaggedProto, );
 #undef DECLARE_REWRAP
 
 template <typename T>
 struct IsPrivateGCThingInValue
   : public mozilla::EnableIf<mozilla::IsBaseOf<Cell, T>::value &&
                              !mozilla::IsBaseOf<JSObject, T>::value &&
                              !mozilla::IsBaseOf<JSString, T>::value &&
-                             !mozilla::IsBaseOf<JS::Symbol, T>::value, T>
+                             !mozilla::IsBaseOf<JS::Symbol, T>::value
+#ifdef ENABLE_BIGINT
+                             && !mozilla::IsBaseOf<JS::BigInt, T>::value
+#endif
+                             , T>
 {
     static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
                   "T must not be Cell or TenuredCell");
 };
 
 template <typename T>
 struct RewrapTaggedPointer<Value, T>
 {
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -11,16 +11,19 @@
 #include "jsutil.h"
 #include "NamespaceImports.h"
 
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #include "gc/PublicIterators.h"
 #include "gc/Zone.h"
 #include "util/Text.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/Shape.h"
 #include "vm/SymbolType.h"
 
 #include "gc/GC-inl.h"
 #include "vm/JSCompartment-inl.h"
 #include "vm/ObjectGroup-inl.h"
@@ -391,16 +394,22 @@ JS_GetTraceThingInfo(char* buf, size_t b
                ? "substring"
                : "string";
         break;
 
       case JS::TraceKind::Symbol:
         name = "symbol";
         break;
 
+#ifdef ENABLE_BIGINT
+      case JS::TraceKind::BigInt:
+        name = "BigInt";
+        break;
+#endif
+
       default:
         name = "INVALID";
         break;
     }
 
     n = strlen(name);
     if (n > bufsize - 1)
         n = bufsize - 1;
--- a/js/src/gdb/lib-for-tests/prologue.py
+++ b/js/src/gdb/lib-for-tests/prologue.py
@@ -64,16 +64,23 @@ def assert_subprinter_registered(printer
     pat = r'^( +)%(printer)s *\n(\1 +.*\n)*\1 +%(subprinter)s *\n' % names
     output = gdb.execute('info pretty-printer', to_string=True)
     if not re.search(pat, output, re.MULTILINE):
         raise AssertionError("assert_subprinter_registered failed to find pretty-printer:\n"
                              "  %s:%s\n"
                              "'info pretty-printer' says:\n"
                              "%s" % (printer, subprinter, output))
 
+enable_bigint = False
+try:
+    if gdb.lookup_type('JS::BigInt'):
+        enable_bigint = True
+except:
+    pass
+
 # Request full stack traces for Python errors.
 gdb.execute('set python print-stack full')
 
 # Tell GDB not to ask the user about the things we tell it to do.
 gdb.execute('set confirm off', False)
 
 # Some print settings that make testing easier.
 gdb.execute('set print static-members off')
--- a/js/src/gdb/mozilla/jsval.py
+++ b/js/src/gdb/mozilla/jsval.py
@@ -141,16 +141,25 @@ class JSValueTypeCache(object):
         self.UNDEFINED = get('JSVAL_TYPE_UNDEFINED')
         self.BOOLEAN = get('JSVAL_TYPE_BOOLEAN')
         self.MAGIC = get('JSVAL_TYPE_MAGIC')
         self.STRING = get('JSVAL_TYPE_STRING')
         self.SYMBOL = get('JSVAL_TYPE_SYMBOL')
         self.NULL = get('JSVAL_TYPE_NULL')
         self.OBJECT = get('JSVAL_TYPE_OBJECT')
 
+        self.enable_bigint = False
+        try:
+            # Looking up the tag will throw an exception if BigInt is not
+            # enabled.
+            self.BIGINT = get('JSVAL_TYPE_BIGINT')
+            self.enable_bigint = True
+        except:
+            pass
+
         # Let self.magic_names be an array whose i'th element is the name of
         # the i'th magic value.
         d = gdb.types.make_enum_dict(gdb.lookup_type('JSWhyMagic'))
         self.magic_names = list(range(max(d.values()) + 1))
         for (k,v) in d.items(): self.magic_names[v] = k
 
         # Choose an unboxing scheme for this architecture.
         self.boxer = Punbox if cache.void_ptr_t.sizeof == 8 else Nunbox
@@ -193,11 +202,13 @@ class JSValue(object):
             return '$JS::DoubleValue(%s)' % self.value['asDouble_']
 
         if tag == self.jtc.STRING:
             value = self.box.as_address().cast(self.cache.JSString_ptr_t)
         elif tag == self.jtc.OBJECT:
             value = self.box.as_address().cast(self.cache.JSObject_ptr_t)
         elif tag == self.jtc.SYMBOL:
             value = self.box.as_address().cast(self.cache.JSSymbol_ptr_t)
+        elif self.jtc.enable_bigint and tag == self.jtc.BIGINT:
+            return '$JS::BigIntValue()'
         else:
             value = 'unrecognized!'
         return '$JS::Value(%s)' % (value,)
--- a/js/src/gdb/tests/test-jsval.cpp
+++ b/js/src/gdb/tests/test-jsval.cpp
@@ -1,11 +1,15 @@
 #include "gdb-tests.h"
 #include "jsapi.h"
 
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
+
 FRAGMENT(jsval, simple) {
   using namespace JS;
 
   RootedValue fortytwo(cx, Int32Value(42));
   RootedValue fortytwoD(cx, DoubleValue(42));
   RootedValue negone(cx, Int32Value(-1));
   RootedValue undefined(cx, UndefinedValue());
   RootedValue null(cx, NullValue());
@@ -13,16 +17,19 @@ FRAGMENT(jsval, simple) {
   RootedValue js_false(cx, BooleanValue(false));
   RootedValue elements_hole(cx, js::MagicValue(JS_ELEMENTS_HOLE));
 
   RootedValue empty_string(cx);
   empty_string.setString(JS_NewStringCopyZ(cx, ""));
   RootedString hello(cx, JS_NewStringCopyZ(cx, "Hello!"));
   RootedValue friendly_string(cx, StringValue(hello));
   RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello)));
+#ifdef ENABLE_BIGINT
+  RootedValue bi(cx, BigIntValue(BigInt::create(cx)));
+#endif
 
   RootedValue global(cx);
   global.setObject(*CurrentGlobalOrNull(cx));
 
   // Some interesting value that floating-point won't munge.
   RootedValue onehundredthirtysevenonehundredtwentyeighths(cx, DoubleValue(137.0 / 128.0));
 
   breakpoint();
@@ -33,10 +40,13 @@ FRAGMENT(jsval, simple) {
   use(undefined);
   use(js_true);
   use(js_false);
   use(null);
   use(elements_hole);
   use(empty_string);
   use(friendly_string);
   use(symbol);
+#ifdef ENABLE_BIGINT
+  use(bi);
+#endif
   use(global);
 }
--- a/js/src/gdb/tests/test-jsval.py
+++ b/js/src/gdb/tests/test-jsval.py
@@ -10,10 +10,12 @@ assert_pretty('negone', '$JS::Int32Value
 assert_pretty('undefined', '$JS::UndefinedValue()')
 assert_pretty('null', '$JS::NullValue()')
 assert_pretty('js_true', '$JS::BooleanValue(true)')
 assert_pretty('js_false', '$JS::BooleanValue(false)')
 assert_pretty('elements_hole', '$JS::MagicValue(JS_ELEMENTS_HOLE)')
 assert_pretty('empty_string', '$JS::Value("")')
 assert_pretty('friendly_string', '$JS::Value("Hello!")')
 assert_pretty('symbol', '$JS::Value(Symbol.for("Hello!"))')
+if enable_bigint:
+    assert_pretty('bi', '$JS::BigIntValue()')
 assert_pretty('global', '$JS::Value((JSObject *)  [object global] delegate)')
 assert_pretty('onehundredthirtysevenonehundredtwentyeighths', '$JS::DoubleValue(1.0703125)')
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1975,29 +1975,30 @@ BaselineCacheIRCompiler::emitGuardAndGet
     if (!addFailurePath(&failure))
         return false;
 
     // Load our PropertyIteratorObject* and its NativeIterator.
     masm.loadPtr(iterAddr, output);
     masm.loadObjPrivate(output, JSObject::ITER_CLASS_NFIXED_SLOTS, niScratch);
 
     // Ensure the |active| and |unreusable| bits are not set.
-    masm.branchTest32(Assembler::NonZero, Address(niScratch, offsetof(NativeIterator, flags)),
-                      Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE), failure->label());
-
-    // Pre-write barrier for store to 'obj'.
-    Address iterObjAddr(niScratch, offsetof(NativeIterator, obj));
+    masm.branchTest32(Assembler::NonZero,
+                      Address(niScratch, NativeIterator::offsetOfFlags()),
+                      Imm32(NativeIterator::Flags::All), failure->label());
+
+    // Pre-write barrier for store to 'objectBeingIterated_'.
+    Address iterObjAddr(niScratch, NativeIterator::offsetOfObjectBeingIterated());
     EmitPreBarrier(masm, iterObjAddr, MIRType::Object);
 
     // Mark iterator as active.
-    Address iterFlagsAddr(niScratch, offsetof(NativeIterator, flags));
+    Address iterFlagsAddr(niScratch, NativeIterator::offsetOfFlags());
     masm.storePtr(obj, iterObjAddr);
-    masm.or32(Imm32(JSITER_ACTIVE), iterFlagsAddr);
-
-    // Post-write barrier for stores to 'obj'.
+    masm.or32(Imm32(NativeIterator::Flags::Active), iterFlagsAddr);
+
+    // Post-write barrier for stores to 'objectBeingIterated_'.
     emitPostBarrierSlot(output, TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), scratch1);
 
     // Chain onto the active iterator stack. Note that Baseline CacheIR stub
     // code is shared across compartments within a Zone, so we can't bake in
     // compartment->enumerators here.
     masm.loadPtr(enumeratorsAddr, scratch1);
     masm.loadPtr(Address(scratch1, 0), scratch1);
     emitRegisterEnumerator(scratch1, niScratch, scratch2);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1787,16 +1787,17 @@ CreateDependentString::generate(MacroAss
         masm.and32(Imm32(JSString::TYPE_FLAGS_MASK), temp2);
         masm.branch32(Assembler::NotEqual, temp2, Imm32(JSString::DEPENDENT_FLAGS), &noBase);
         masm.loadDependentStringBase(base, temp1);
         masm.storeDependentStringBase(temp1, string);
         masm.bind(&noBase);
 
         // Post-barrier the base store, whether it was the direct or indirect
         // base (both will end up in temp1 here).
+        masm.branchPtrInNurseryChunk(Assembler::Equal, string, temp2, &done);
         masm.branchPtrInNurseryChunk(Assembler::NotEqual, temp1, temp2, &done);
 
         LiveRegisterSet regsToSave(RegisterSet::Volatile());
         regsToSave.takeUnchecked(temp1);
         regsToSave.takeUnchecked(temp2);
         regsToSave.addUnchecked(string);
 
         masm.PushRegsInMask(regsToSave);
@@ -9924,17 +9925,18 @@ CodeGenerator::visitIteratorEnd(LIterato
     const Register temp2 = ToRegister(lir->temp2());
     const Register temp3 = ToRegister(lir->temp3());
 
     OutOfLineCode* ool = oolCallVM(CloseIteratorFromIonInfo, lir, ArgList(obj), StoreNothing());
 
     LoadNativeIterator(masm, obj, temp1, ool->entry());
 
     // Clear active bit.
-    masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));
+    masm.and32(Imm32(~NativeIterator::Flags::Active),
+               Address(temp1, NativeIterator::offsetOfFlags()));
 
     // Reset property cursor.
     masm.loadPtr(Address(temp1, NativeIterator::offsetOfGuardsEnd()), temp2);
     masm.storePtr(temp2, Address(temp1, NativeIterator::offsetOfPropertyCursor()));
 
     // Unlink from the iterator list.
     const Register next = temp2;
     const Register prev = temp3;
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -2304,29 +2304,30 @@ IonCacheIRCompiler::emitGuardAndGetItera
     if (!addFailurePath(&failure))
         return false;
 
     // Load our PropertyIteratorObject* and its NativeIterator.
     masm.movePtr(ImmGCPtr(iterobj), output);
     masm.loadObjPrivate(output, JSObject::ITER_CLASS_NFIXED_SLOTS, niScratch);
 
     // Ensure the |active| and |unreusable| bits are not set.
-    masm.branchTest32(Assembler::NonZero, Address(niScratch, offsetof(NativeIterator, flags)),
-                      Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE), failure->label());
-
-    // Pre-write barrier for store to 'obj'.
-    Address iterObjAddr(niScratch, offsetof(NativeIterator, obj));
+    masm.branchTest32(Assembler::NonZero,
+                      Address(niScratch, NativeIterator::offsetOfFlags()),
+                      Imm32(NativeIterator::Flags::All), failure->label());
+
+    // Pre-write barrier for store to 'objectBeingIterated_'.
+    Address iterObjAddr(niScratch, NativeIterator::offsetOfObjectBeingIterated());
     EmitPreBarrier(masm, iterObjAddr, MIRType::Object);
 
     // Mark iterator as active.
-    Address iterFlagsAddr(niScratch, offsetof(NativeIterator, flags));
+    Address iterFlagsAddr(niScratch, NativeIterator::offsetOfFlags());
     masm.storePtr(obj, iterObjAddr);
-    masm.or32(Imm32(JSITER_ACTIVE), iterFlagsAddr);
-
-    // Post-write barrier for stores to 'obj'.
+    masm.or32(Imm32(NativeIterator::Flags::Active), iterFlagsAddr);
+
+    // Post-write barrier for stores to 'objectBeingIterated_'.
     emitPostBarrierSlot(output, TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), scratch1);
 
     // Chain onto the active iterator stack.
     masm.loadPtr(AbsoluteAddress(enumerators), scratch1);
     emitRegisterEnumerator(scratch1, niScratch, scratch2);
 
     return true;
 }
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -2668,17 +2668,17 @@ CompareExchangeJS(MacroAssembler& masm, 
                   const T& mem, Register oldval, Register newval, Register valueTemp,
                   Register offsetTemp, Register maskTemp, Register temp, AnyRegister output)
 {
     if (arrayType == Scalar::Uint32) {
         masm.compareExchange(arrayType, sync, mem, oldval, newval, valueTemp, offsetTemp, maskTemp,
                              temp);
         masm.convertUInt32ToDouble(temp, output.fpu());
     } else {
-        masm.compareExchange(arrayType, sync, mem, oldval, newval, valueTemp, maskTemp, temp,
+        masm.compareExchange(arrayType, sync, mem, oldval, newval, valueTemp, offsetTemp, maskTemp,
                              output.gpr());
     }
 }
 
 void
 MacroAssembler::compareExchangeJS(Scalar::Type arrayType, const Synchronization& sync,
                                   const Address& mem, Register oldval, Register newval,
                                   Register valueTemp, Register offsetTemp, Register maskTemp,
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -642,8 +642,17 @@ MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMA
 
 // Response-related
 MSG_DEF(JSMSG_ERROR_CONSUMING_RESPONSE,                  0, JSEXN_TYPEERR,  "there was an error consuming the Response")
 MSG_DEF(JSMSG_BAD_RESPONSE_VALUE,                        0, JSEXN_TYPEERR,  "expected Response or Promise resolving to Response")
 MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE,                    0, JSEXN_TYPEERR,  "Response has unsupported MIME type")
 MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN,             0, JSEXN_TYPEERR,  "Response.type must be 'basic', 'cors' or 'default'")
 MSG_DEF(JSMSG_BAD_RESPONSE_STATUS,                       0, JSEXN_TYPEERR,  "Response does not have ok status")
 MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED,                 0, JSEXN_TYPEERR,  "Response already consumed")
+
+// BigInt
+MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
+MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
+MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
+MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
+MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")
+MSG_DEF(JSMSG_NOT_BIGINT, 0, JSEXN_TYPEERR, "not a BigInt")
+MSG_DEF(JSMSG_BIGINT_NOT_SERIALIZABLE, 0, JSEXN_TYPEERR, "BigInt value can't be serialized in JSON")
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -6,16 +6,19 @@
 
 #include "jsfriendapi.h"
 
 #include "mozilla/Atomics.h"
 #include "mozilla/PodOperations.h"
 
 #include <stdint.h>
 
+#ifdef ENABLE_BIGINT
+#include "builtin/BigInt.h"
+#endif
 #include "builtin/Promise.h"
 #include "builtin/TestingFunctions.h"
 #include "gc/GCInternals.h"
 #include "gc/PublicIterators.h"
 #include "gc/WeakMap.h"
 #include "js/Printf.h"
 #include "js/Proxy.h"
 #include "js/Wrapper.h"
@@ -308,16 +311,20 @@ js::GetBuiltinClass(JSContext* cx, Handl
     else if (obj->is<MapIteratorObject>())
         *cls = ESClass::MapIterator;
     else if (obj->is<SetIteratorObject>())
         *cls = ESClass::SetIterator;
     else if (obj->is<ArgumentsObject>())
         *cls = ESClass::Arguments;
     else if (obj->is<ErrorObject>())
         *cls = ESClass::Error;
+#ifdef ENABLE_BIGINT
+    else if (obj->is<BigIntObject>())
+        *cls = ESClass::BigInt;
+#endif
     else
         *cls = ESClass::Other;
 
     return true;
 }
 
 JS_FRIEND_API(const char*)
 js::ObjectClassName(JSContext* cx, HandleObject obj)
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1586,19 +1586,31 @@ js::ToNumberSlow(JSContext* cx, HandleVa
     if (v.isSymbol()) {
         if (!cx->helperThread()) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       JSMSG_SYMBOL_TO_NUMBER);
         }
         return false;
     }
 
-    MOZ_ASSERT(v.isUndefined());
-    *out = GenericNaN();
-    return true;
+    if (v.isUndefined()) {
+        *out = GenericNaN();
+        return true;
+    }
+
+    MOZ_ASSERT(v.isSymbol() || IF_BIGINT(v.isBigInt(), false));
+    if (!cx->helperThread()) {
+        unsigned errnum = JSMSG_SYMBOL_TO_NUMBER;
+#ifdef ENABLE_BIGINT
+        if (v.isBigInt())
+            errnum = JSMSG_BIGINT_TO_NUMBER;
+#endif
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errnum);
+    }
+    return false;
 }
 
 /*
  * Convert a value to an int8_t, according to the WebIDL rules for byte
  * conversion. Return converted value in *out on success, false on failure.
  */
 JS_PUBLIC_API(bool)
 js::ToInt8Slow(JSContext *cx, const HandleValue v, int8_t *out)
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -44,16 +44,19 @@ enum JSType {
     JSTYPE_UNDEFINED,           /* undefined */
     JSTYPE_OBJECT,              /* object */
     JSTYPE_FUNCTION,            /* function */
     JSTYPE_STRING,              /* string */
     JSTYPE_NUMBER,              /* number */
     JSTYPE_BOOLEAN,             /* boolean */
     JSTYPE_NULL,                /* null */
     JSTYPE_SYMBOL,              /* symbol */
+#ifdef ENABLE_BIGINT
+    JSTYPE_BIGINT,              /* BigInt */
+#endif
     JSTYPE_LIMIT
 };
 
 /* Dense index into cached prototypes and class atoms for standard objects. */
 enum JSProtoKey {
 #define PROTOKEY_AND_INITIALIZER(name,init,clasp) JSProto_##name,
     JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER)
 #undef PROTOKEY_AND_INITIALIZER
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -453,16 +453,22 @@ SOURCES += [
     'jsmath.cpp',
     'jsutil.cpp',
     'util/DoubleToString.cpp',
     'vm/Interpreter.cpp',
     'vm/JSAtom.cpp',
     'vm/ProfilingStack.cpp',
 ]
 
+if CONFIG['ENABLE_BIGINT']:
+    SOURCES += [
+        'builtin/BigInt.cpp',
+        'vm/BigIntType.cpp',
+    ]
+
 if CONFIG['JS_POSIX_NSPR']:
     UNIFIED_SOURCES += [
         'vm/PosixNSPR.cpp',
     ]
 
 if CONFIG['MOZ_INSTRUMENTS']:
     SOURCES += [
         'devtools/Instruments.cpp',
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -278,17 +278,17 @@ struct AutoCloseIterator
 };
 
 static JSObject*
 Reify(JSContext* cx, JSCompartment* origin, HandleObject objp)
 {
     Rooted<PropertyIteratorObject*> iterObj(cx, &objp->as<PropertyIteratorObject>());
     NativeIterator* ni = iterObj->getNativeIterator();
 
-    RootedObject obj(cx, ni->obj);
+    RootedObject obj(cx, ni->objectBeingIterated());
     {
         AutoCloseIterator close(cx, iterObj);
 
         /* Wrap the iteratee. */
         if (!origin->wrap(cx, &obj))
             return nullptr;
 
         /*
--- a/js/src/util/StringBuffer.cpp
+++ b/js/src/util/StringBuffer.cpp
@@ -159,11 +159,19 @@ js::ValueToStringBufferSlow(JSContext* c
     if (v.isBoolean())
         return BooleanToStringBuffer(v.toBoolean(), sb);
     if (v.isNull())
         return sb.append(cx->names().null);
     if (v.isSymbol()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_STRING);
         return false;
     }
+#ifdef ENABLE_BIGINT
+    if (v.isBigInt()) {
+        JSLinearString* str = BigInt::toString(cx, v.toBigInt(), 10);
+        if (!str)
+            return false;
+        return sb.append(str);
+    }
+#endif
     MOZ_ASSERT(v.isUndefined());
     return sb.append(cx->names().undefined);
 }
new file mode 100644
--- /dev/null
+++ b/js/src/vm/BigIntType.cpp
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/BigIntType.h"
+
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/HashFunctions.h"
+
+#include <gmp.h>
+#include <math.h>
+
+#include "jsapi.h"
+
+#include "builtin/BigInt.h"
+#include "gc/Allocator.h"
+#include "gc/Tracer.h"
+#include "js/Initialization.h"
+#include "js/Utility.h"
+#include "vm/JSContext.h"
+#include "vm/SelfHosting.h"
+
+using namespace js;
+
+// The following functions are wrappers for use with
+// mp_set_memory_functions. GMP passes extra arguments to the realloc
+// and free functions not needed by the JS allocation interface.
+// js_malloc has the signature expected for GMP's malloc function, so no
+// wrapper is required.
+
+static void*
+js_mp_realloc(void* ptr, size_t old_size, size_t new_size)
+{
+    return js_realloc(ptr, new_size);
+}
+
+static void
+js_mp_free(void* ptr, size_t size)
+{
+    return js_free(ptr);
+}
+
+static bool memoryFunctionsInitialized = false;
+
+JS_PUBLIC_API(void)
+JS::SetGMPMemoryFunctions(JS::GMPAllocFn allocFn,
+                          JS::GMPReallocFn reallocFn,
+                          JS::GMPFreeFn freeFn)
+{
+    MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Uninitialized);
+    memoryFunctionsInitialized = true;
+    mp_set_memory_functions(allocFn, reallocFn, freeFn);
+}
+
+void
+BigInt::init()
+{
+    // Don't override custom allocation functions if
+    // JS::SetGMPMemoryFunctions was called.
+    if (!memoryFunctionsInitialized) {
+        memoryFunctionsInitialized = true;
+        mp_set_memory_functions(js_malloc, js_mp_realloc, js_mp_free);
+    }
+}
+
+BigInt*
+BigInt::create(JSContext* cx)
+{
+    BigInt* x = Allocate<BigInt>(cx);
+    if (!x)
+        return nullptr;
+    mpz_init(x->num_); // to zero
+    return x;
+}
+
+BigInt*
+BigInt::createFromDouble(JSContext* cx, double d)
+{
+    BigInt* x = Allocate<BigInt>(cx);
+    if (!x)
+        return nullptr;
+    mpz_init_set_d(x->num_, d);
+    return x;
+}
+
+BigInt*
+BigInt::createFromBoolean(JSContext* cx, bool b)
+{
+    BigInt* x = Allocate<BigInt>(cx);
+    if (!x)
+        return nullptr;
+    mpz_init_set_ui(x->num_, b);
+    return x;
+}
+
+// BigInt proposal section 5.1.1
+static bool
+IsInteger(double d)
+{
+    // Step 1 is an assertion checked by the caller.
+    // Step 2.
+    if (!mozilla::IsFinite(d))
+        return false;
+
+    // Step 3.
+    double i = JS::ToInteger(d);
+
+    // Step 4.
+    if (i != d)
+        return false;
+
+    // Step 5.
+    return true;
+}
+
+// BigInt proposal section 5.1.2
+BigInt*
+js::NumberToBigInt(JSContext* cx, double d)
+{
+    // Step 1 is an assertion checked by the caller.
+    // Step 2.
+    if (!IsInteger(d)) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+                                  JSMSG_NUMBER_TO_BIGINT);
+        return nullptr;
+    }
+
+    // Step 3.
+    return BigInt::createFromDouble(cx, d);
+}
+
+BigInt*
+BigInt::copy(JSContext* cx, HandleBigInt x)
+{
+    BigInt* bi = Allocate<BigInt>(cx);
+    if (!bi)
+        return nullptr;
+    mpz_init_set(bi->num_, x->num_);
+    return bi;
+}
+
+// BigInt proposal section 7.3
+BigInt*
+js::ToBigInt(JSContext* cx, HandleValue val)
+{
+    RootedValue v(cx, val);
+
+    // Step 1.
+    if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
+        return nullptr;
+
+    // Step 2.
+    // String conversions are not yet supported.
+    if (v.isBigInt())
+        return v.toBigInt();
+
+    if (v.isBoolean())
+        return BigInt::createFromBoolean(cx, v.toBoolean());
+
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_BIGINT);
+    return nullptr;
+}
+
+JSLinearString*
+BigInt::toString(JSContext* cx, BigInt* x, uint8_t radix)
+{
+    MOZ_ASSERT(2 <= radix && radix <= 36);
+    // We need two extra chars for '\0' and potentially '-'.
+    size_t strSize = mpz_sizeinbase(x->num_, 10) + 2;
+    UniqueChars str(static_cast<char*>(js_malloc(strSize)));
+    if (!str) {
+        ReportOutOfMemory(cx);
+        return nullptr;
+    }
+    mpz_get_str(str.get(), radix, x->num_);
+
+    return NewStringCopyZ<CanGC>(cx, str.get());
+}
+
+void
+BigInt::finalize(js::FreeOp* fop)
+{
+    mpz_clear(num_);
+}
+
+JSAtom*
+js::BigIntToAtom(JSContext* cx, BigInt* bi)
+{
+    JSString* str = BigInt::toString(cx, bi, 10);
+    if (!str)
+        return nullptr;
+    return AtomizeString(cx, str);
+}
+
+bool
+BigInt::toBoolean()
+{
+    return mpz_sgn(num_) != 0;
+}
+
+js::HashNumber
+BigInt::hash()
+{
+    const mp_limb_t* limbs = mpz_limbs_read(num_);
+    size_t limbCount = mpz_size(num_);
+    uint32_t hash = mozilla::HashBytes(limbs, limbCount * sizeof(mp_limb_t));
+    hash = mozilla::AddToHash(hash, mpz_sgn(num_));
+    return hash;
+}
+
+size_t
+BigInt::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    // Use the total number of limbs allocated when calculating the size
+    // (_mp_alloc), not the number of limbs currently in use (_mp_size).
+    // See the Info node `(gmp)Integer Internals` for details.
+    mpz_srcptr n = static_cast<mpz_srcptr>(num_);
+    return sizeof(*n) + sizeof(mp_limb_t) * n->_mp_alloc;
+}
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<BigInt>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    BigInt& bi = get();
+    MOZ_ASSERT(bi.isTenured());
+    size_t size = js::gc::Arena::thingSize(bi.asTenured().getAllocKind());
+    size += bi.sizeOfExcludingThis(mallocSizeOf);
+    return size;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/vm/BigIntType.h
@@ -0,0 +1,78 @@
+/* -*- 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/. */
+
+#ifndef vm_BigIntType_h
+#define vm_BigIntType_h
+
+#include <gmp.h>
+
+#include "gc/Barrier.h"
+#include "gc/GC.h"
+#include "gc/Heap.h"
+#include "js/AllocPolicy.h"
+#include "js/GCHashTable.h"
+#include "js/RootingAPI.h"
+#include "js/TypeDecls.h"
+#include "vm/StringType.h"
+
+namespace JS {
+
+class BigInt final : public js::gc::TenuredCell
+{
+  private:
+    // The minimum allocation size is currently 16 bytes (see
+    // SortedArenaList in gc/ArenaList.h).
+    union {
+        mpz_t num_;
+        uint8_t unused_[js::gc::MinCellSize];
+    };
+
+  public:
+    // Allocate and initialize a BigInt value
+    static BigInt* create(JSContext* cx);
+
+    static BigInt* createFromDouble(JSContext* cx, double d);
+
+    static BigInt* createFromBoolean(JSContext* cx, bool b);
+
+    static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
+
+    void traceChildren(JSTracer* trc);
+
+    void finalize(js::FreeOp* fop);
+
+    js::HashNumber hash();
+
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+    bool toBoolean();
+
+    static void init();
+
+    static BigInt* copy(JSContext* cx, Handle<BigInt*> x);
+
+    static JSLinearString* toString(JSContext* cx, BigInt* x, uint8_t radix);
+};
+
+static_assert(sizeof(BigInt) >= js::gc::MinCellSize,
+              "sizeof(BigInt) must be greater than the minimum allocation size");
+
+} // namespace JS
+
+namespace js {
+
+extern JSAtom*
+BigIntToAtom(JSContext* cx, JS::BigInt* bi);
+
+extern JS::BigInt*
+NumberToBigInt(JSContext* cx, double d);
+
+extern JS::BigInt*
+ToBigInt(JSContext* cx, JS::Handle<JS::Value> v);
+
+} // namespace js
+
+#endif
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -258,16 +258,17 @@
     macro(noFilename, noFilename, "noFilename") \
     macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \
     macro(noStack, noStack, "noStack") \
     macro(notes, notes, "notes") \
     macro(NumberFormat, NumberFormat, "NumberFormat") \
     macro(numeric, numeric, "numeric") \
     macro(objectArguments, objectArguments, "[object Arguments]") \
     macro(objectArray, objectArray, "[object Array]") \
+    macro(objectBigInt, objectBigInt, "[object BigInt]") \
     macro(objectBoolean, objectBoolean, "[object Boolean]") \
     macro(objectDate, objectDate, "[object Date]") \
     macro(objectError, objectError, "[object Error]") \
     macro(objectFunction, objectFunction, "[object Function]") \
     macro(objectNull, objectNull, "[object Null]") \
     macro(objectNumber, objectNumber, "[object Number]") \
     macro(objectObject, objectObject, "[object Object]") \
     macro(objectRegExp, objectRegExp, "[object RegExp]") \
@@ -459,11 +460,12 @@
     macro(undefined, undefined, "undefined") \
     macro(object, object, "object") \
     macro(function, function, "function") \
     macro(string, string, "string") \
     macro(number, number, "number") \
     macro(boolean, boolean, "boolean") \
     macro(null, null, "null") \
     macro(symbol, symbol, "symbol") \
-    macro(defineDataPropertyIntrinsic, defineDataPropertyIntrinsic, "_DefineDataProperty") \
+    macro(bigint, bigint, "bigint") \
+    macro(defineDataPropertyIntrinsic, defineDataPropertyIntrinsic, "_DefineDataProperty")
 
 #endif /* vm_CommonPropertyNames_h */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -6,16 +6,19 @@
 
 #include "vm/GlobalObject.h"
 
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfriendapi.h"
 
 #include "builtin/AtomicsObject.h"
+#ifdef ENABLE_BIGINT
+#include "builtin/BigInt.h"
+#endif
 #include "builtin/DataViewObject.h"
 #include "builtin/Eval.h"
 #include "builtin/MapObject.h"
 #include "builtin/ModuleObject.h"
 #include "builtin/Object.h"
 #include "builtin/Promise.h"
 #include "builtin/RegExp.h"
 #include "builtin/SelfHostingDefines.h"
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -20,16 +20,19 @@
 #include "jit/ExecutableAllocator.h"
 #include "jit/Ion.h"
 #include "jit/JitCommon.h"
 #include "js/Utility.h"
 #if ENABLE_INTL_API
 #include "unicode/uclean.h"
 #include "unicode/utypes.h"
 #endif // ENABLE_INTL_API
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/DateTime.h"
 #include "vm/HelperThreads.h"
 #include "vm/Runtime.h"
 #include "vm/Time.h"
 #include "vm/TraceLogging.h"
 #include "vtune/VTuneWrapper.h"
 #include "wasm/WasmProcess.h"
 
@@ -72,17 +75,17 @@ JS::detail::InitWithFailureDiagnostic(bo
 #ifdef DEBUG
     MOZ_RELEASE_ASSERT(isDebugBuild);
 #else
     MOZ_RELEASE_ASSERT(!isDebugBuild);
 #endif
 
     MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
                "must call JS_Init once before any JSAPI operation except "
-               "JS_SetICUMemoryFunctions");
+               "JS_SetICUMemoryFunctions or JS::SetGMPMemoryFunctions");
     MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
                "how do we have live runtimes before JS_Init?");
 
     libraryInitState = InitState::Initializing;
 
     PRMJ_NowInit();
 
     // The first invocation of `ProcessCreation` creates a temporary thread
@@ -129,16 +132,20 @@ JS::detail::InitWithFailureDiagnostic(bo
     RETURN_IF_FAIL(js::CreateHelperThreadsState());
     RETURN_IF_FAIL(FutexThread::initialize());
     RETURN_IF_FAIL(js::gcstats::Statistics::initialize());
 
 #ifdef JS_SIMULATOR
     RETURN_IF_FAIL(js::jit::SimulatorProcess::initialize());
 #endif
 
+#ifdef ENABLE_BIGINT
+    JS::BigInt::init();
+#endif
+
     libraryInitState = InitState::Running;
     return nullptr;
 }
 
 #undef RETURN_IF_FAIL
 
 JS_PUBLIC_API(void)
 JS_ShutDown(void)
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -27,16 +27,19 @@
 #include "jit/AtomicOperations.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/Jit.h"
 #include "util/StringBuffer.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/BytecodeUtil.h"
 #include "vm/Debugger.h"
 #include "vm/GeneratorObject.h"
 #include "vm/Iteration.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSObject.h"
@@ -964,16 +967,20 @@ js::TypeOfValue(const Value& v)
     if (v.isNull())
         return JSTYPE_OBJECT;
     if (v.isUndefined())
         return JSTYPE_UNDEFINED;
     if (v.isObject())
         return TypeOfObject(&v.toObject());
     if (v.isBoolean())
         return JSTYPE_BOOLEAN;
+#ifdef ENABLE_BIGINT
+    if (v.isBigInt())
+        return JSTYPE_BIGINT;
+#endif
     MOZ_ASSERT(v.isSymbol());
     return JSTYPE_SYMBOL;
 }
 
 bool
 js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage)
 {
     if (IsConstructor(heritage))
@@ -4378,17 +4385,20 @@ js::GetProperty(JSContext* cx, HandleVal
     if (name == cx->names().length) {
         // Fast path for strings, arrays and arguments.
         if (GetLengthProperty(v, vp))
             return true;
     }
 
     // Optimize common cases like (2).toString() or "foo".valueOf() to not
     // create a wrapper object.
-    if (v.isPrimitive() && !v.isNullOrUndefined()) {
+    if (v.isPrimitive() &&
+        !v.isNullOrUndefined() &&
+        IF_BIGINT(!v.isBigInt(), true))
+    {
         NativeObject* proto;
         if (v.isNumber()) {
             proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
         } else if (v.isString()) {
             proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
         } else if (v.isBoolean()) {
             proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
         } else {
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -52,17 +52,17 @@ using mozilla::PodEqual;
 
 typedef Rooted<PropertyIteratorObject*> RootedPropertyIteratorObject;
 
 static const gc::AllocKind ITERATOR_FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
 
 void
 NativeIterator::trace(JSTracer* trc)
 {
-    TraceNullableEdge(trc, &obj, "obj");
+    TraceNullableEdge(trc, &objectBeingIterated_, "objectBeingIterated_");
 
     // The SuppressDeletedPropertyHelper loop can GC, so make sure that if the
     // GC removes any elements from the list, it won't remove this one.
     if (iterObj_)
         TraceManuallyBarrieredEdge(trc, &iterObj_, "iterObj");
 
     std::for_each(guardsBegin(), guardsEnd(),
                   [trc](HeapReceiverGuard& guard) {
@@ -541,18 +541,18 @@ js::GetPropertyKeys(JSContext* cx, Handl
 }
 
 static inline void
 RegisterEnumerator(ObjectRealm& realm, NativeIterator* ni)
 {
     /* Register non-escaping native enumerators (for-in) with the current context. */
     ni->link(realm.enumerators);
 
-    MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
-    ni->flags |= JSITER_ACTIVE;
+    MOZ_ASSERT(!ni->isActive());
+    ni->markActive();
 }
 
 static PropertyIteratorObject*
 NewPropertyIteratorObject(JSContext* cx)
 {
     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
                                                              TaggedProto(nullptr)));
     if (!group)
@@ -653,26 +653,26 @@ NativeIterator::allocateSentinel(JSConte
  *
  * This definition is a bit tricky: some parts of initializing are fallible, so
  * as we initialize, we must carefully keep this in GC-safe state (see
  * NativeIterator::trace).
  */
 NativeIterator::NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
                                Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
                                uint32_t numGuards, uint32_t guardKey, bool* hadError)
-  : obj(objBeingIterated),
+  : objectBeingIterated_(objBeingIterated),
     iterObj_(propIter),
     // NativeIterator initially acts (before full initialization) as if it
     // contains no guards...
     guardsEnd_(guardsBegin()),
     // ...and no properties.
     propertyCursor_(reinterpret_cast<GCPtrFlatString*>(guardsBegin() + numGuards)),
     propertiesEnd_(propertyCursor_),
-    guard_key(guardKey),
-    flags(0)
+    guardKey_(guardKey),
+    flags_(0)
 {
     MOZ_ASSERT(!*hadError);
 
     // NOTE: This must be done first thing: PropertyIteratorObject::finalize
     //       can only free |this| (and not leak it) if this has happened.
     propIter->setNativeIterator(this);
 
     for (size_t i = 0, len = props.length(); i < len; i++) {
@@ -724,17 +724,17 @@ NativeIterator::NativeIterator(JSContext
             key = mozilla::AddToHash(key, guard.hash());
 
             // The one caller of this method that passes |numGuards > 0|, does
             // so only if the entire chain consists of cacheable objects (that
             // necessarily have static prototypes).
             pobj = pobj->staticPrototype();
         } while (pobj);
 
-        guard_key = key;
+        guardKey_ = key;
         MOZ_ASSERT(i == numGuards);
     }
 
     MOZ_ASSERT(static_cast<void*>(guardsEnd_) == propertyCursor_);
     MOZ_ASSERT(!*hadError);
 }
 
 static inline PropertyIteratorObject*
@@ -761,31 +761,23 @@ js::NewEmptyPropertyIterator(JSContext* 
     AutoIdVector props(cx); // Empty
     return CreatePropertyIterator(cx, nullptr, props, 0, 0);
 }
 
 /* static */ bool
 IteratorHashPolicy::match(PropertyIteratorObject* obj, const Lookup& lookup)
 {
     NativeIterator* ni = obj->getNativeIterator();
-    if (ni->guard_key != lookup.key || ni->guardCount() != lookup.numGuards)
+    if (ni->guardKey() != lookup.key || ni->guardCount() != lookup.numGuards)
         return false;
 
     return PodEqual(reinterpret_cast<ReceiverGuard*>(ni->guardsBegin()), lookup.guards,
                     ni->guardCount());
 }
 
-static inline void
-UpdateNativeIterator(NativeIterator* ni, JSObject* obj)
-{
-    // Update the object for which the native iterator is associated, so
-    // SuppressDeletedPropertyHelper will recognize the iterator as a match.
-    ni->obj = obj;
-}
-
 static inline bool
 CanCompareIterableObjectToCache(JSObject* obj)
 {
     if (obj->isNative())
         return obj->as<NativeObject>().hasEmptyElements();
     if (obj->is<UnboxedPlainObject>()) {
         if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
             return expando->hasEmptyElements();
@@ -826,17 +818,17 @@ LookupInIteratorCache(JSContext* cx, JSO
     auto p = ObjectRealm::get(obj).iteratorCache.lookup(lookup);
     if (!p)
         return nullptr;
 
     PropertyIteratorObject* iterobj = *p;
     MOZ_ASSERT(iterobj->compartment() == cx->compartment());
 
     NativeIterator* ni = iterobj->getNativeIterator();
-    if (ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE))
+    if (!ni->isReusable())
         return nullptr;
 
     return iterobj;
 }
 
 static bool
 CanStoreInIteratorCache(JSObject* obj)
 {
@@ -866,17 +858,17 @@ StoreInIteratorCache(JSContext* cx, JSOb
 {
     MOZ_ASSERT(CanStoreInIteratorCache(obj));
 
     NativeIterator* ni = iterobj->getNativeIterator();
     MOZ_ASSERT(ni->guardCount() > 0);
 
     IteratorHashPolicy::Lookup lookup(reinterpret_cast<ReceiverGuard*>(ni->guardsBegin()),
                                       ni->guardCount(),
-                                      ni->guard_key);
+                                      ni->guardKey());
 
     ObjectRealm::IteratorCache& cache = ObjectRealm::get(obj).iteratorCache;
     bool ok;
     auto p = cache.lookupForAdd(lookup);
     if (MOZ_LIKELY(!p)) {
         ok = cache.add(p, iterobj);
     } else {
         // If we weren't able to use an existing cached iterator, just
@@ -893,17 +885,17 @@ StoreInIteratorCache(JSContext* cx, JSOb
 }
 
 JSObject*
 js::GetIterator(JSContext* cx, HandleObject obj)
 {
     uint32_t numGuards = 0;
     if (PropertyIteratorObject* iterobj = LookupInIteratorCache(cx, obj, &numGuards)) {
         NativeIterator* ni = iterobj->getNativeIterator();
-        UpdateNativeIterator(ni, obj);
+        ni->changeObjectBeingIterated(*obj);
         RegisterEnumerator(ObjectRealm::get(obj), ni);
         return iterobj;
     }
 
     if (numGuards > 0 && !CanStoreInIteratorCache(obj))
         numGuards = 0;
 
     MOZ_ASSERT(!obj->is<PropertyIteratorObject>());
@@ -1019,28 +1011,16 @@ Realm::getOrCreateIterResultTemplateObje
 
     iterResultTemplate_.set(templateObject);
 
     return iterResultTemplate_;
 }
 
 /*** Iterator objects ****************************************************************************/
 
-MOZ_ALWAYS_INLINE void
-NativeIteratorNext(NativeIterator* ni, MutableHandleValue rval)
-{
-    if (ni->propertyCursor_ >= ni->propertiesEnd()) {
-        MOZ_ASSERT(ni->propertyCursor_ == ni->propertiesEnd());
-        rval.setMagic(JS_NO_ITER_VALUE);
-    } else {
-        rval.setString(*ni->currentProperty());
-        ni->incCursor();
-    }
-}
-
 bool
 js::IsPropertyIterator(HandleValue v)
 {
     return v.isObject() && v.toObject().is<PropertyIteratorObject>();
 }
 
 size_t
 PropertyIteratorObject::sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const
@@ -1174,24 +1154,22 @@ void
 js::CloseIterator(JSObject* obj)
 {
     if (obj->is<PropertyIteratorObject>()) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
 
         ni->unlink();
 
-        MOZ_ASSERT(ni->flags & JSITER_ACTIVE);
-        ni->flags &= ~JSITER_ACTIVE;
+        MOZ_ASSERT(ni->isActive());
+        ni->markInactive();
 
-        /*
-         * Reset the enumerator; it may still be in the cached iterators
-         * for this thread, and can be reused.
-         */
-        ni->propertyCursor_ = ni->propertiesBegin();
+        // Reset the enumerator; it may still be in the cached iterators for
+        // this thread and can be reused.
+        ni->resetPropertyCursorForReuse();
     }
 }
 
 bool
 js::IteratorCloseForException(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(cx->isExceptionPending());
 
@@ -1248,35 +1226,35 @@ js::UnwindIteratorForUncatchableExceptio
         ni->unlink();
     }
 }
 
 static bool
 SuppressDeletedProperty(JSContext* cx, NativeIterator* ni, HandleObject obj,
                         Handle<JSFlatString*> str)
 {
-    if (ni->obj != obj)
+    if (ni->objectBeingIterated() != obj)
         return true;
 
     // Optimization for the following common case:
     //
     //    for (var p in o) {
     //        delete o[p];
     //    }
     //
     // Note that usually both strings will be atoms so we only check for pointer
     // equality here.
-    if (ni->propertyCursor_ > ni->propertiesBegin() && ni->propertyCursor_[-1] == str)
+    if (ni->previousPropertyWas(str))
         return true;
 
     while (true) {
         bool restart = false;
 
         // Check whether id is still to come.
-        GCPtrFlatString* const cursor = ni->propertyCursor_;
+        GCPtrFlatString* const cursor = ni->nextProperty();
         GCPtrFlatString* const end = ni->propertiesEnd();
         for (GCPtrFlatString* idp = cursor; idp < end; ++idp) {
             // Common case: both strings are atoms.
             if ((*idp)->isAtom() && str->isAtom()) {
                 if (*idp != str)
                     continue;
             } else {
                 if (!EqualStrings(*idp, str))
@@ -1299,39 +1277,36 @@ SuppressDeletedProperty(JSContext* cx, N
                     return false;
 
                 if (desc.object() && desc.enumerable())
                     continue;
             }
 
             // If GetPropertyDescriptor above removed a property from ni, start
             // over.
-            if (end != ni->propertiesEnd() || cursor != ni->propertyCursor_) {
+            if (end != ni->propertiesEnd() || cursor != ni->nextProperty()) {
                 restart = true;
                 break;
             }
 
             // No property along the prototype chain stepped in to take the
             // property's place, so go ahead and delete id from the list.
             // If it is the next property to be enumerated, just skip it.
             if (idp == cursor) {
                 ni->incCursor();
             } else {
                 for (GCPtrFlatString* p = idp; p + 1 != end; p++)
                     *p = *(p + 1);
-                ni->propertiesEnd_--;
 
-                // This invokes the pre barrier on this element, since
-                // it's no longer going to be marked, and ensures that
-                // any existing remembered set entry will be dropped.
-                *ni->propertiesEnd_ = nullptr;
+                ni->trimLastProperty();
             }
 
-            // Don't reuse modified native iterators.
-            ni->flags |= JSITER_UNREUSABLE;
+            // Modified NativeIterators omit properties that possibly shouldn't
+            // be omitted, so they can't be reused.
+            ni->markNotReusable();
             return true;
         }
 
         if (!restart)
             return true;
     }
 }
 
@@ -1394,17 +1369,17 @@ js::SuppressDeletedElement(JSContext* cx
 }
 
 bool
 js::IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval)
 {
     // Fast path for native iterators.
     if (MOZ_LIKELY(iterobj->is<PropertyIteratorObject>())) {
         NativeIterator* ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
-        NativeIteratorNext(ni, rval);
+        rval.set(ni->nextIteratedValueAndAdvance());
         return true;
     }
 
     if (JS_IsDeadWrapper(iterobj)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
         return false;
     }
 
@@ -1413,17 +1388,17 @@ js::IteratorMore(JSContext* cx, HandleOb
     RootedObject obj(cx, CheckedUnwrap(iterobj));
     if (!obj)
         return false;
 
     MOZ_RELEASE_ASSERT(obj->is<PropertyIteratorObject>());
     {
         AutoRealm ar(cx, obj);
         NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
-        NativeIteratorNext(ni, rval);
+        rval.set(ni->nextIteratedValueAndAdvance());
     }
     return cx->compartment()->wrap(cx, rval);
 }
 
 static const JSFunctionSpec iterator_proto_methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FS_END
 };
--- a/js/src/vm/Iteration.h
+++ b/js/src/vm/Iteration.h
@@ -14,64 +14,69 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "gc/Barrier.h"
 #include "vm/JSContext.h"
 #include "vm/ReceiverGuard.h"
 #include "vm/Stack.h"
 
-/*
- * For cacheable native iterators, whether the iterator is currently active.
- * Not serialized by XDR.
- */
-#define JSITER_ACTIVE       0x1000
-#define JSITER_UNREUSABLE   0x2000
-
 namespace js {
 
 class PropertyIteratorObject;
 
 struct NativeIterator
 {
-  public:
-    // Object being iterated.
-    GCPtrObject obj = {};
+  private:
+    // Object being iterated.  Non-null except in NativeIterator sentinels and
+    // empty property iterators created when |null| or |undefined| is iterated.
+    GCPtrObject objectBeingIterated_ = {};
 
-  private:
     // Internal iterator object.
     JSObject* iterObj_ = nullptr;
 
     // The end of HeapReceiverGuards that appear directly after |this|, as part
     // of an overall allocation that stores |*this|, receiver guards, and
     // iterated strings.  Once this has been fully initialized, it also equals
     // the start of iterated strings.
     HeapReceiverGuard* guardsEnd_; // initialized by constructor
 
-  public:
     // The next property, pointing into an array of strings directly after any
     // HeapReceiverGuards that appear directly after |*this|, as part of an
     // overall allocation that stores |*this|, receiver guards, and iterated
     // strings.
     GCPtrFlatString* propertyCursor_; // initialized by constructor
 
     // The limit/end of properties to iterate (and, assuming no error occurred
     // while constructing this NativeIterator, the end of the full allocation
     // storing |*this|, receiver guards, and strings).  Beware!  This value may
     // change as properties are deleted from the observed object.
     GCPtrFlatString* propertiesEnd_; // initialized by constructor
 
-    uint32_t guard_key = 0;
-    uint32_t flags = 0;
+    uint32_t guardKey_; // initialized by constructor
+
+  public:
+    // For cacheable native iterators, whether the iterator is currently
+    // active.  Not serialized by XDR.
+    struct Flags
+    {
+        static constexpr uint32_t Active = 0x1;
+        static constexpr uint32_t NotReusable = 0x2;
+        static constexpr uint32_t All = Active | NotReusable;
+    };
 
   private:
+    uint32_t flags_ = 0; // consists of Flags bits
+
     /* While in compartment->enumerators, these form a doubly linked list. */
     NativeIterator* next_ = nullptr;
     NativeIterator* prev_ = nullptr;
 
+    // END OF PROPERTIES
+
     // No further fields appear after here *in NativeIterator*, but this class
     // is always allocated with space tacked on immediately after |this| to
     // store iterated property names up to |props_end| and |guard_length|
     // HeapReceiverGuards after that.
 
   public:
     /**
      * Initialize a NativeIterator properly allocated for |props.length()|
@@ -83,16 +88,24 @@ struct NativeIterator
      */
     NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
                    Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
                    uint32_t numGuards, uint32_t guardKey, bool* hadError);
 
     /** Initialize a |JSCompartment::enumerators| sentinel. */
     NativeIterator();
 
+    JSObject* objectBeingIterated() const {
+        return objectBeingIterated_;
+    }
+
+    void changeObjectBeingIterated(JSObject& obj) {
+        objectBeingIterated_ = &obj;
+    }
+
     HeapReceiverGuard* guardsBegin() const {
         static_assert(alignof(HeapReceiverGuard) <= alignof(NativeIterator),
                       "NativeIterator must be aligned to begin storing "
                       "HeapReceiverGuards immediately after it with no "
                       "required padding");
         const NativeIterator* immediatelyAfter = this + 1;
         auto* afterNonConst = const_cast<NativeIterator*>(immediatelyAfter);
         return reinterpret_cast<HeapReceiverGuard*>(afterNonConst);
@@ -113,51 +126,103 @@ struct NativeIterator
                       "NativeIterator, with no padding space required for "
                       "correct alignment");
         static_assert(alignof(NativeIterator) >= alignof(GCPtrFlatString),
                       "GCPtrFlatStrings for properties must be able to appear "
                       "directly after this NativeIterator when no "
                       "HeapReceiverGuards are present, with no padding space "
                       "required for correct alignment");
 
-        // Note: JIT code inlines this computation to reset |propertyCursor_|
-        //       when an iterator ends: see |CodeGenerator::visitIteratorEnd|.
         return reinterpret_cast<GCPtrFlatString*>(guardsEnd_);
     }
 
     GCPtrFlatString* propertiesEnd() const {
         return propertiesEnd_;
     }
 
+    GCPtrFlatString* nextProperty() const {
+        return propertyCursor_;
+    }
+
+    MOZ_ALWAYS_INLINE JS::Value nextIteratedValueAndAdvance() {
+        if (propertyCursor_ >= propertiesEnd_) {
+            MOZ_ASSERT(propertyCursor_ == propertiesEnd_);
+            return JS::MagicValue(JS_NO_ITER_VALUE);
+        }
+
+        JSFlatString* str = *propertyCursor_;
+        incCursor();
+        return JS::StringValue(str);
+    }
+
+    void resetPropertyCursorForReuse() {
+        // Note: JIT code inlines |propertyCursor_| resetting when an iterator
+        //       ends: see |CodeGenerator::visitIteratorEnd|.
+        propertyCursor_ = propertiesBegin();
+    }
+
+    bool previousPropertyWas(JS::Handle<JSFlatString*> str) {
+        return propertyCursor_ > propertiesBegin() && propertyCursor_[-1] == str;
+    }
+
     size_t numKeys() const {
         return mozilla::PointerRangeSize(propertiesBegin(), propertiesEnd());
     }
 
+    void trimLastProperty() {
+        propertiesEnd_--;
+
+        // This invokes the pre barrier on this property, since it's no longer
+        // going to be marked, and it ensures that any existing remembered set
+        // entry will be dropped.
+        *propertiesEnd_ = nullptr;
+    }
+
     JSObject* iterObj() const {
         return iterObj_;
     }
     GCPtrFlatString* currentProperty() const {
         MOZ_ASSERT(propertyCursor_ < propertiesEnd());
         return propertyCursor_;
     }
 
     NativeIterator* next() {
         return next_;
     }
 
-    static inline size_t offsetOfNext() {
-        return offsetof(NativeIterator, next_);
-    }
-    static inline size_t offsetOfPrev() {
-        return offsetof(NativeIterator, prev_);
-    }
-
     void incCursor() {
         propertyCursor_++;
     }
+
+    uint32_t guardKey() const {
+        return guardKey_;
+    }
+
+    bool isActive() const {
+        return flags_ & Flags::Active;
+    }
+
+    void markActive() {
+        flags_ |= Flags::Active;
+    }
+
+    void markInactive() {
+        flags_ &= ~Flags::Active;
+    }
+
+    bool isReusable() const {
+        // Cached NativeIterators are reusable if they're not active and
+        // aren't marked as not reusable, i.e. if no flags are set.
+        return flags_ == 0;
+    }
+
+    void markNotReusable() {
+        flags_ |= Flags::NotReusable;
+    }
+
     void link(NativeIterator* other) {
         /* A NativeIterator cannot appear in the enumerator list twice. */
         MOZ_ASSERT(!next_ && !prev_);
 
         this->next_ = other;
         this->prev_ = other->prev_;
         other->prev_->next_ = this;
         other->prev_ = this;
@@ -168,27 +233,43 @@ struct NativeIterator
         next_ = nullptr;
         prev_ = nullptr;
     }
 
     static NativeIterator* allocateSentinel(JSContext* maybecx);
 
     void trace(JSTracer* trc);
 
+    static constexpr size_t offsetOfObjectBeingIterated() {
+        return offsetof(NativeIterator, objectBeingIterated_);
+    }
+
     static constexpr size_t offsetOfGuardsEnd() {
         return offsetof(NativeIterator, guardsEnd_);
     }
 
     static constexpr size_t offsetOfPropertyCursor() {
         return offsetof(NativeIterator, propertyCursor_);
     }
 
     static constexpr size_t offsetOfPropertiesEnd() {
         return offsetof(NativeIterator, propertiesEnd_);
     }
+
+    static constexpr size_t offsetOfFlags() {
+        return offsetof(NativeIterator, flags_);
+    }
+
+    static constexpr size_t offsetOfNext() {
+        return offsetof(NativeIterator, next_);
+    }
+
+    static constexpr size_t offsetOfPrev() {
+        return offsetof(NativeIterator, prev_);
+    }
 };
 
 class PropertyIteratorObject : public NativeObject
 {
     static const ClassOps classOps_;
 
   public:
     static const Class class_;
--- a/js/src/vm/JSAtom.cpp
+++ b/js/src/vm/JSAtom.cpp
@@ -631,16 +631,24 @@ ToAtomSlow(JSContext* cx, typename Maybe
     if (v.isSymbol()) {
         MOZ_ASSERT(!cx->helperThread());
         if (allowGC) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       JSMSG_SYMBOL_TO_STRING);
         }
         return nullptr;
     }
+#ifdef ENABLE_BIGINT
+    if (v.isBigInt()) {
+        JSAtom* atom = BigIntToAtom(cx, v.toBigInt());
+        if (!allowGC && !atom)
+            cx->recoverFromOutOfMemory();
+        return atom;
+    }
+#endif
     MOZ_ASSERT(v.isUndefined());
     return cx->names().undefined;
 }
 
 template <AllowGC allowGC>
 JSAtom*
 js::ToAtom(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v)
 {
--- a/js/src/vm/JSCompartment-inl.h
+++ b/js/src/vm/JSCompartment-inl.h
@@ -116,16 +116,26 @@ JSCompartment::wrap(JSContext* cx, JS::M
     if (vp.isString()) {
         JS::RootedString str(cx, vp.toString());
         if (!wrap(cx, &str))
             return false;
         vp.setString(str);
         return true;
     }
 
+#ifdef ENABLE_BIGINT
+    if (vp.isBigInt()) {
+        JS::RootedBigInt bi(cx, vp.toBigInt());
+        if (!wrap(cx, &bi))
+            return false;
+        vp.setBigInt(bi);
+        return true;
+    }
+#endif
+
     MOZ_ASSERT(vp.isObject());
 
     /*
      * All that's left are objects.
      *
      * Object wrapping isn't the fastest thing in the world, in part because
      * we have to unwrap and invoke the prewrap hook to find the identity
      * object before we even start checking the cache. Neither of these
@@ -172,14 +182,14 @@ js::ObjectRealm::objectMaybeInIteration(
 
     // If the list is empty we're not iterating any objects.
     js::NativeIterator* next = enumerators->next();
     if (enumerators == next)
         return false;
 
     // If the list contains a single object, check if it's |obj|.
     if (next->next() == enumerators)
-        return next->obj == obj;
+        return next->objectBeingIterated() == obj;
 
     return true;
 }
 
 #endif /* vm_JSCompartment_inl_h */
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -340,16 +340,33 @@ JSCompartment::wrap(JSContext* cx, Mutab
         return false;
     if (!putWrapper(cx, CrossCompartmentKey(key), StringValue(copy)))
         return false;
 
     strp.set(copy);
     return true;
 }
 
+#ifdef ENABLE_BIGINT
+bool
+JSCompartment::wrap(JSContext* cx, MutableHandleBigInt bi)
+{
+    MOZ_ASSERT(cx->compartment() == this);
+
+    if (bi->zone() == cx->zone())
+        return true;
+
+    BigInt* copy = BigInt::copy(cx, bi);
+    if (!copy)
+        return false;
+    bi.set(copy);
+    return true;
+}
+#endif
+
 bool
 JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj)
 {
     // Ensure that we have entered a compartment.
     MOZ_ASSERT(cx->global());
 
     // If we have a cross-compartment wrapper, make sure that the cx isn't
     // associated with the self-hosting global. We don't want to create
@@ -827,17 +844,18 @@ ObjectRealm::sweepNativeIterators()
 {
     /* Sweep list of native iterators. */
     NativeIterator* ni = enumerators->next();
     while (ni != enumerators) {
         JSObject* iterObj = ni->iterObj();
         NativeIterator* next = ni->next();
         if (gc::IsAboutToBeFinalizedUnbarriered(&iterObj))
             ni->unlink();
-        MOZ_ASSERT_IF(ni->obj, &ObjectRealm::get(ni->obj) == this);
+        MOZ_ASSERT_IF(ni->objectBeingIterated(),
+                      &ObjectRealm::get(ni->objectBeingIterated()) == this);
         ni = next;
     }
 }
 
 void
 Realm::sweepObjectRealm()
 {
     objects_.sweepNativeIterators();
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -631,16 +631,19 @@ struct JSCompartment
     ~JSCompartment();
 
     MOZ_MUST_USE bool init(JSContext* maybecx);
 
   public:
     MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
 
     MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
+#ifdef ENABLE_BIGINT
+    MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle<JS::BigInt*> bi);
+#endif
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj);
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<JS::GCVector<JS::Value>> vec);
     MOZ_MUST_USE bool rewrap(JSContext* cx, JS::MutableHandleObject obj, JS::HandleObject existing);
 
     MOZ_MUST_USE bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped,
                                  const js::Value& wrapper);
 
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -20,16 +20,19 @@
 #include "jsapi.h"
 #include "jsexn.h"
 #include "jsfriendapi.h"
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "builtin/Array.h"
+#ifdef ENABLE_BIGINT
+#include "builtin/BigInt.h"
+#endif
 #include "builtin/Eval.h"
 #include "builtin/Object.h"
 #include "builtin/String.h"
 #include "builtin/Symbol.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Policy.h"
 #include "jit/BaselineJIT.h"
 #include "js/MemoryMetrics.h"
@@ -3246,19 +3249,29 @@ js::PrimitiveToObject(JSContext* cx, con
     if (v.isString()) {
         Rooted<JSString*> str(cx, v.toString());
         return StringObject::create(cx, str);
     }
     if (v.isNumber())
         return NumberObject::create(cx, v.toNumber());
     if (v.isBoolean())
         return BooleanObject::create(cx, v.toBoolean());
+#ifdef ENABLE_BIGINT
+    if (v.isSymbol()) {
+        RootedSymbol symbol(cx, v.toSymbol());
+        return SymbolObject::create(cx, symbol);
+    }
+    MOZ_ASSERT(v.isBigInt());
+    RootedBigInt bigInt(cx, v.toBigInt());
+    return BigIntObject::create(cx, bigInt);
+#else
     MOZ_ASSERT(v.isSymbol());
     RootedSymbol symbol(cx, v.toSymbol());
     return SymbolObject::create(cx, symbol);
+#endif
 }
 
 /*
  * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
  * already be an object, use ToObject. reportCantConvert controls how null and
  * undefined errors are reported.
  *
  * Callers must handle the already-object case.
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -8,16 +8,19 @@
 
 #include "gc/GC.h"
 #include "gc/Heap.h"
 #include "gc/Nursery.h"
 #include "gc/PublicIterators.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "vm/ArrayObject.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/HelperThreads.h"
 #include "vm/JSCompartment.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Runtime.h"
 #include "vm/Shape.h"
 #include "vm/StringType.h"
 #include "vm/SymbolType.h"
@@ -551,16 +554,25 @@ StatsCellCallback(JSRuntime* rt, void* d
         }
         break;
       }
 
       case JS::TraceKind::Symbol:
         zStats->symbolsGCHeap += thingSize;
         break;
 
+#ifdef ENABLE_BIGINT
+      case JS::TraceKind::BigInt: {
+        JS::BigInt* bi = static_cast<BigInt*>(thing);
+        zStats->bigIntsGCHeap += thingSize;
+        zStats->bigIntsMallocHeap += bi->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+        break;
+      }
+#endif
+
       case JS::TraceKind::BaseShape: {
         JS::ShapeInfo info;        // This zeroes all the sizes.
         info.shapesGCHeapBase += thingSize;
         // No malloc-heap measurements.
 
         zStats->shapeInfo.add(info);
         break;
       }
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -2066,17 +2066,25 @@ js::ToStringSlow(JSContext* cx, typename
         str = cx->names().null;
     } else if (v.isSymbol()) {
         MOZ_ASSERT(!cx->helperThread());
         if (allowGC) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       JSMSG_SYMBOL_TO_STRING);
         }
         return nullptr;
-    } else {
+    }
+#ifdef ENABLE_BIGINT
+    else if (v.isBigInt()) {
+        if (!allowGC)
+            return nullptr;
+        str = BigInt::toString(cx, v.toBigInt(), 10);
+    }
+#endif
+    else {
         MOZ_ASSERT(v.isUndefined());
         str = cx->names().undefined;
     }
     return str;
 }
 
 template JSString*
 js::ToStringSlow<CanGC>(JSContext* cx, HandleValue arg);
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -185,16 +185,20 @@ PrimitiveTypeFlag(JSValueType type)
       case JSVAL_TYPE_INT32:
         return TYPE_FLAG_INT32;
       case JSVAL_TYPE_DOUBLE:
         return TYPE_FLAG_DOUBLE;
       case JSVAL_TYPE_STRING:
         return TYPE_FLAG_STRING;
       case JSVAL_TYPE_SYMBOL:
         return TYPE_FLAG_SYMBOL;
+#ifdef ENABLE_BIGINT
+      case JSVAL_TYPE_BIGINT:
+        return TYPE_FLAG_BIGINT;
+#endif
       case JSVAL_TYPE_MAGIC:
         return TYPE_FLAG_LAZYARGS;
       default:
         MOZ_CRASH("Bad JSValueType");
     }
 }
 
 inline JSValueType
@@ -210,16 +214,20 @@ TypeFlagPrimitive(TypeFlags flags)
       case TYPE_FLAG_INT32:
         return JSVAL_TYPE_INT32;
       case TYPE_FLAG_DOUBLE:
         return JSVAL_TYPE_DOUBLE;
       case TYPE_FLAG_STRING:
         return JSVAL_TYPE_STRING;
       case TYPE_FLAG_SYMBOL:
         return JSVAL_TYPE_SYMBOL;
+#ifdef ENABLE_BIGINT
+      case TYPE_FLAG_BIGINT:
+        return JSVAL_TYPE_BIGINT;
+#endif
       case TYPE_FLAG_LAZYARGS:
         return JSVAL_TYPE_MAGIC;
       default:
         MOZ_CRASH("Bad TypeFlags");
     }
 }
 
 /*
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -108,16 +108,20 @@ TypeSet::NonObjectTypeString(TypeSet::Ty
           case JSVAL_TYPE_INT32:
             return "int";
           case JSVAL_TYPE_DOUBLE:
             return "float";
           case JSVAL_TYPE_STRING:
             return "string";
           case JSVAL_TYPE_SYMBOL:
             return "symbol";
+#ifdef ENABLE_BIGINT
+          case JSVAL_TYPE_BIGINT:
+            return "BigInt";
+#endif
           case JSVAL_TYPE_MAGIC:
             return "lazyargs";
           default:
             MOZ_CRASH("Bad type");
         }
     }
     if (type.isUnknown())
         return "unknown";
@@ -780,16 +784,20 @@ TypeSet::print(FILE* fp)
     if (flags & TYPE_FLAG_INT32)
         fprintf(fp, " int");
     if (flags & TYPE_FLAG_DOUBLE)
         fprintf(fp, " float");
     if (flags & TYPE_FLAG_STRING)
         fprintf(fp, " string");
     if (flags & TYPE_FLAG_SYMBOL)
         fprintf(fp, " symbol");
+#ifdef ENABLE_BIGINT
+    if (flags & TYPE_FLAG_BIGINT)
+        fprintf(fp, " BigInt");
+#endif
     if (flags & TYPE_FLAG_LAZYARGS)
         fprintf(fp, " lazyargs");
 
     uint32_t objectCount = baseObjectCount();
     if (objectCount) {
         fprintf(fp, " object[%u]", objectCount);
 
         unsigned count = getObjectCount();
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -55,36 +55,48 @@ class HeapTypeSetKey;
 enum : uint32_t {
     TYPE_FLAG_UNDEFINED =   0x1,
     TYPE_FLAG_NULL      =   0x2,
     TYPE_FLAG_BOOLEAN   =   0x4,
     TYPE_FLAG_INT32     =   0x8,
     TYPE_FLAG_DOUBLE    =  0x10,
     TYPE_FLAG_STRING    =  0x20,
     TYPE_FLAG_SYMBOL    =  0x40,
-    TYPE_FLAG_LAZYARGS  =  0x80,
+#ifdef ENABLE_BIGINT
+    TYPE_FLAG_BIGINT    =  0x80,
+    TYPE_FLAG_LAZYARGS  = 0x100,
+    TYPE_FLAG_ANYOBJECT = 0x200,
+#else
+    TYPE_FLAG_LAZYARGS  = 0x80,
     TYPE_FLAG_ANYOBJECT = 0x100,
+#endif
 
     /* Mask containing all primitives */
     TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
                           TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
-                          TYPE_FLAG_SYMBOL,
+                          TYPE_FLAG_SYMBOL |
+                          IF_BIGINT(TYPE_FLAG_BIGINT, 0),
 
     /* Mask/shift for the number of objects in objectSet */
+#ifdef ENABLE_BIGINT
+    TYPE_FLAG_OBJECT_COUNT_MASK     = 0x3c00,
+    TYPE_FLAG_OBJECT_COUNT_SHIFT    = 10,
+#else
     TYPE_FLAG_OBJECT_COUNT_MASK     = 0x3e00,
     TYPE_FLAG_OBJECT_COUNT_SHIFT    = 9,
+#endif
     TYPE_FLAG_OBJECT_COUNT_LIMIT    = 7,
     TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
         TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
 
     /* Whether the contents of this type set are totally unknown. */
     TYPE_FLAG_UNKNOWN             = 0x00004000,
 
     /* Mask of normal type flags on a type set. */
-    TYPE_FLAG_BASE_MASK           = 0x000041ff,
+    TYPE_FLAG_BASE_MASK           = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT | TYPE_FLAG_UNKNOWN,
 
     /* Additional flags for HeapTypeSet sets. */
 
     /*
      * Whether the property has ever been deleted or reconfigured to behave
      * differently from a plain data property, other than making the property
      * non-writable.
      */
@@ -105,16 +117,20 @@ enum : uint32_t {
      * If the property is definite, mask and shift storing the slot + 1.
      * Otherwise these bits are clear.
      */
     TYPE_FLAG_DEFINITE_MASK       = 0xfffc0000,
     TYPE_FLAG_DEFINITE_SHIFT      = 18
 };
 typedef uint32_t TypeFlags;
 
+static_assert(TYPE_FLAG_PRIMITIVE < TYPE_FLAG_ANYOBJECT &&
+              TYPE_FLAG_LAZYARGS < TYPE_FLAG_ANYOBJECT,
+              "TYPE_FLAG_ANYOBJECT should be greater than primitive type flags");
+
 /* Flags and other state stored in ObjectGroup::Flags */
 enum : uint32_t {
     /* Whether this group is associated with some allocation site. */
     OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
 
     /* Whether this group is associated with a single object. */
     OBJECT_FLAG_SINGLETON             = 0x2,
 
@@ -361,16 +377,19 @@ class TypeSet
 
     static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
     static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
     static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
     static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
     static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
     static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
     static inline Type SymbolType()    { return Type(JSVAL_TYPE_SYMBOL); }
+#ifdef ENABLE_BIGINT
+    static inline Type BigIntType()    { return Type(JSVAL_TYPE_BIGINT); }
+#endif
     static inline Type MagicArgType()  { return Type(JSVAL_TYPE_MAGIC); }
     static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
     static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
 
     static inline Type PrimitiveType(JSValueType type) {
         MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
         return Type(type);
     }
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -17,16 +17,19 @@
 
 #include "jit/IonCode.h"
 #include "js/Debug.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 #include "util/Text.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 #include "vm/Debugger.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Scope.h"
 #include "vm/Shape.h"
@@ -198,17 +201,23 @@ Node::exposeToJS() const
             v.setUndefined();
         } else {
             v.setObject(obj);
         }
     } else if (is<JSString>()) {
         v.setString(as<JSString>());
     } else if (is<JS::Symbol>()) {
         v.setSymbol(as<JS::Symbol>());
-    } else {
+    }
+#ifdef ENABLE_BIGINT
+    else if (is<BigInt>()) {
+        v.setBigInt(as<BigInt>());
+    }
+#endif
+    else {
         v.setUndefined();
     }
 
     ExposeValueToActiveJS(v);
 
     return v;
 }
 
@@ -310,16 +319,19 @@ TracerConcrete<Referent>::zone() const
 template JS::Zone* TracerConcrete<JSScript>::zone() const;
 template JS::Zone* TracerConcrete<js::LazyScript>::zone() const;
 template JS::Zone* TracerConcrete<js::Shape>::zone() const;
 template JS::Zone* TracerConcrete<js::BaseShape>::zone() const;
 template JS::Zone* TracerConcrete<js::ObjectGroup>::zone() const;
 template JS::Zone* TracerConcrete<js::RegExpShared>::zone() const;
 template JS::Zone* TracerConcrete<js::Scope>::zone() const;
 template JS::Zone* TracerConcrete<JS::Symbol>::zone() const;
+#ifdef ENABLE_BIGINT
+template JS::Zone* TracerConcrete<BigInt>::zone() const;
+#endif
 template JS::Zone* TracerConcrete<JSString>::zone() const;
 
 template<typename Referent>
 UniquePtr<EdgeRange>
 TracerConcrete<Referent>::edges(JSContext* cx, bool wantNames) const {
     UniquePtr<SimpleEdgeRange, JS::DeletePolicy<SimpleEdgeRange>> range(js_new<SimpleEdgeRange>());
     if (!range)
         return nullptr;
@@ -333,16 +345,19 @@ TracerConcrete<Referent>::edges(JSContex
 template UniquePtr<EdgeRange> TracerConcrete<JSScript>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::LazyScript>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::Shape>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::BaseShape>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::RegExpShared>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::Scope>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<JS::Symbol>::edges(JSContext* cx, bool wantNames) const;
+#ifdef ENABLE_BIGINT
+template UniquePtr<EdgeRange> TracerConcrete<BigInt>::edges(JSContext* cx, bool wantNames) const;
+#endif
 template UniquePtr<EdgeRange> TracerConcrete<JSString>::edges(JSContext* cx, bool wantNames) const;
 
 template<typename Referent>
 JSCompartment*
 TracerConcreteWithCompartment<Referent>::compartment() const
 {
     return TracerBase::get().compartment();
 }
@@ -388,16 +403,19 @@ Concrete<JSObject>::jsObjectConstructorN
     if (!JS_CopyStringChars(cx, chars, name))
         return false;
 
     outName[len] = '\0';
     return true;
 }
 
 const char16_t Concrete<JS::Symbol>::concreteTypeName[] = u"JS::Symbol";
+#ifdef ENABLE_BIGINT
+const char16_t Concrete<BigInt>::concreteTypeName[] = u"JS::BigInt";
+#endif
 const char16_t Concrete<JSScript>::concreteTypeName[] = u"JSScript";
 const char16_t Concrete<js::LazyScript>::concreteTypeName[] = u"js::LazyScript";
 const char16_t Concrete<js::jit::JitCode>::concreteTypeName[] = u"js::jit::JitCode";
 const char16_t Concrete<js::Shape>::concreteTypeName[] = u"js::Shape";
 const char16_t Concrete<js::BaseShape>::concreteTypeName[] = u"js::BaseShape";
 const char16_t Concrete<js::ObjectGroup>::concreteTypeName[] = u"js::ObjectGroup";
 const char16_t Concrete<js::Scope>::concreteTypeName[] = u"js::Scope";
 const char16_t Concrete<js::RegExpShared>::concreteTypeName[] = u"js::RegExpShared";
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -3,29 +3,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccessCheck.h"
 
 #include "nsJSPrincipals.h"
 #include "BasePrincipal.h"
+#include "nsDOMWindowList.h"
 #include "nsGlobalWindow.h"
 
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
 #include "FilteringWrapper.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/LocationBinding.h"
 #include "mozilla/dom/WindowBinding.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
-#include "nsIDOMWindowCollection.h"
 #include "nsJSUtils.h"
 #include "xpcprivate.h"
 
 using namespace mozilla;
 using namespace JS;
 using namespace js;
 
 namespace xpc {
@@ -129,30 +129,30 @@ IsFrameId(JSContext* cx, JSObject* obj, 
     MOZ_ASSERT(!js::IsWrapper(obj));
     RootedId id(cx, idArg);
 
     nsGlobalWindowInner* win = WindowOrNull(obj);
     if (!win) {
         return false;
     }
 
-    nsCOMPtr<nsIDOMWindowCollection> col = win->GetFrames();
+    nsDOMWindowList* col = win->GetFrames();
     if (!col) {
         return false;
     }
 
     nsCOMPtr<mozIDOMWindowProxy> domwin;
     if (JSID_IS_INT(id)) {
-        col->Item(JSID_TO_INT(id), getter_AddRefs(domwin));
+        domwin = col->IndexedGetter(JSID_TO_INT(id));
     } else if (JSID_IS_STRING(id)) {
         nsAutoJSString idAsString;
         if (!idAsString.init(cx, JSID_TO_STRING(id))) {
             return false;
         }
-        col->NamedItem(idAsString, getter_AddRefs(domwin));
+        domwin = col->NamedItem(idAsString);
     }
 
     return domwin != nullptr;
 }
 
 CrossOriginObjectType
 IdentifyCrossOriginObject(JSObject* obj)
 {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2852,20 +2852,20 @@ public:
   mozilla::DisplayItemData* GetDisplayItemData() { return mDisplayItemData; }
 
   // Set the nsDisplayList that this item belongs to, and what
   // index it is within that list. Temporary state for merging
   // used by RetainedDisplayListBuilder.
   void SetOldListIndex(nsDisplayList* aList, OldListIndex aIndex, uint32_t aListKey, uint32_t aNestingDepth)
   {
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-    mOldList = reinterpret_cast<uintptr_t>(aList);
     mOldListKey = aListKey;
     mOldNestingDepth = aNestingDepth;
 #endif
+    mOldList = reinterpret_cast<uintptr_t>(aList);
     mOldListIndex = aIndex;
   }
   bool GetOldListIndex(nsDisplayList* aList, uint32_t aListKey, OldListIndex* aOutIndex)
   {
     if (mOldList != reinterpret_cast<uintptr_t>(aList)) {
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
       MOZ_CRASH_UNSAFE_PRINTF("Item found was in the wrong list! type %d (outer type was %d at depth %d, now is %d)", GetPerFrameKey(), mOldListKey, mOldNestingDepth, aListKey);
 #endif
--- a/servo/components/style/gecko_bindings/sugar/ns_com_ptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_com_ptr.rs
@@ -8,32 +8,18 @@ use gecko_bindings::structs::nsCOMPtr;
 
 #[cfg(feature = "gecko_debug")]
 impl<T> nsCOMPtr<T> {
     /// Get this pointer as a raw pointer.
     #[inline]
     pub fn raw<U>(&self) -> *mut T {
         self.mRawPtr
     }
-
-    /// Set this pointer from an addrefed raw pointer.
-    /// It leaks the old pointer.
-    #[inline]
-    pub unsafe fn set_raw_from_addrefed<U>(&mut self, ptr: *mut T) {
-        self.mRawPtr = ptr;
-    }
 }
 
 #[cfg(not(feature = "gecko_debug"))]
 impl nsCOMPtr {
     /// Get this pointer as a raw pointer.
     #[inline]
     pub fn raw<T>(&self) -> *mut T {
         self._base.mRawPtr as *mut _
     }
-
-    /// Set this pointer from an addrefed raw pointer.
-    /// It leaks the old pointer.
-    #[inline]
-    pub unsafe fn set_raw_from_addrefed<T>(&mut self, ptr: *mut T) {
-        self._base.mRawPtr = ptr as *mut _;
-    }
 }
--- a/taskcluster/docs/release-promotion.rst
+++ b/taskcluster/docs/release-promotion.rst
@@ -42,13 +42,10 @@ fully ship.
 
 In-depth relpro guide
 ---------------------
 
 .. toctree::
 
     release-promotion-action
     balrog
-
-Release Promotion Tasks
------------------------
-
-* :doc:`partials`
+    partials
+    signing
new file mode 100644
--- /dev/null
+++ b/taskcluster/docs/signing.rst
@@ -0,0 +1,190 @@
+Signing
+=======
+
+.. _overview
+
+Overview
+--------
+
+Our `code signing`_ happens in discrete tasks, for both performance reasons
+and to limit which machines have access to the signing servers and keys.
+
+In general, the binary-to-be-signed is generated in one task, and the request
+to sign it is in a second task. We verify the request via the `chain of trust`_,
+sign the binary, then upload the signed binary or original binary + detached
+signature as artifacts.
+
+.. _how the task works
+
+How the Task Works
+------------------
+
+Scriptworker_ verifies the task definition and the upstream tasks until it
+determines the graph comes from a trusted tree; this is `chain of trust`_
+verification. Part of this verification is downloading and verifying the shas
+of the ``upstreamArtifacts`` in the task payload.
+
+An example signing task payload:
+
+::
+
+  {
+    "payload": {
+      "upstreamArtifacts": [{
+        "paths": ["public/build/target.dmg"],
+        "formats": ["macapp"],
+        "taskId": "abcde",
+        "taskType": "build"
+      }, {
+        "paths": ["public/build/target.tar.gz"],
+        "formats": ["gpg"],
+        "taskId": "12345",
+        "taskType": "build"
+      }]
+    }
+  }
+
+In the above example, scriptworker would download the ``target.dmg`` from task
+``abcde`` and ``target.tar.gz`` from task ``12345`` and verify their shas and
+task definitions via `chain of trust`_ verification. Then it will launch
+`signingscript`_, which requests a signing token from the signing server pool.
+
+Signingscript determines it wants to sign ``target.dmg`` with the ``macapp``
+format, and ``target.tar.gz`` with the ``gpg`` format. Each of the
+`signing formats`_ has their own behavior. After performing any format-specific
+checks or optimizations, it calls `signtool`_ to submit the file to the signing
+servers and poll them for signed output. Once it downloads all of the signed
+output files, it exits and scriptworker uploads the signed binaries.
+
+We can specify multiple paths from a single task for a given set of formats,
+and multiple formats for a given set of paths.
+
+Signing kinds
+-------------
+
+We currently have 12 different signing kinds. These fall into several categories:
+
+**Build internal signing**: Certain package types require the internals to be signed.
+For certain package types, e.g. exe or dmg, we extract the internal binaries
+(e.g. xul.dll) and sign them. This is true for certain zipfiles, exes, and dmgs;
+we need to sign the internals before we [re]create the package. For linux
+tarballs, we don't need special packaging, so we can sign everything in this
+task. These kinds include `build-signing`, `nightly-l10n-signing`,
+`release-eme-free-repack-signing`, and `release-partner-repack-signing`.
+
+**Build repackage signing**: Once we take the signed internals and package them
+(known as a `repackage`), certain formats require a signed external package.
+If we have created an update MAR file from the signed internals, the MAR
+file will also need to be signed. These kinds include `repackage-signing`,
+`release-eme-free-repack-repackage-signing`, and `release-partner-repack-repackage-signing`.
+
+`release-source-signing` and `partials-signing` sign the release source tarball
+and partial update MARs.
+
+We generate signed checksums at the top of the releases directories, like
+in `60.0`_. To generate these, we have the checksums signing kinds, including
+`release-generate-checksums-signing`, `checksums-signing`, and
+`release-source-checksums-signing`
+
+.. _signing formats
+
+Signing formats
+---------------
+
+The known signingscript formats are listed in the fourth column of the
+`signing password files`_.
+
+The formats are specified in the ``upstreamArtifacts`` list-of-dicts. The task
+must have a superset of scopes to match. For example, a Firefox signing task
+with an ``upstreamArtifacts`` that lists both ``gpg`` and ``macapp`` formats must
+have both ``project:releng:signing:format:gpg`` and
+``project:releng:signing:format:macapp`` in its scopes.
+
+``gpg`` signing results in a detached ``.asc`` signature file. Because of its
+nature, we gpg-sign at the end if given multiple formats for a given set of
+files.
+
+``jar`` signing is Android apk signing. After signing, we ``zipalign`` the apk.
+This includes the ``focus-jar`` format, which is just a way to specify a different
+set of keys for the Focus app.
+
+``macapp`` signing accepts either a ``dmg`` or ``tar.gz``; it converts ``dmg``
+files to ``tar.gz`` before submitting to the signing server. The signed binary
+is a ``tar.gz``.
+
+``signcode`` signing takes individual binaries or a zipfile. We sign the
+individual file or internals of the zipfile, skipping any already-signed files
+and a select few blocklisted files (using the `_should_sign_windows`_ function).
+It returns a signed individual binary or zipfile with signed internals, depending
+on the input. This format includes ``signcode``, ``osslsigncode``,
+``sha2signcode``, and ``sha2signcodestub``.
+
+``mar`` signing signs our update files (Mozilla ARchive). ``mar_sha384`` is
+the same, but with a different hashing algorithm.
+
+``widevine`` and ``widevine_blessed`` are also video-related; see the
+`widevine site`_. We sign specific files inside the package and rebuild the
+``precomplete`` file that we use for updates.
+
+Cert levels
+-----------
+
+Cert levels are how we separate signing privileges. We have the following levels:
+
+``dep`` is short for ``depend``, which is a term from the Netscape days. (This
+refers to builds that don't clobber, so they keep their dependency object files
+cached from the previous build.) These certs and keys are designed to be used
+for Try or on-push builds that we don't intend to ship. Many of these are
+self-signed and not of high security value; they're intended for testing
+purposes.
+
+``nightly`` refers to the Nightly product and channel. We use these keys for
+signing and shipping nightly builds, as well as Devedition on the beta channel.
+Because these are shipping keys, they are restricted; only a subset of branches
+can request the use of these keys.
+
+``release`` refers to our releases, off the beta, release, or esr channels.
+These are the most restricted keys.
+
+We request a certain cert level via scopes:
+``project:releng:signing:cert:dep-signing``,
+``project:releng:signing:cert:nightly-signing``, or
+``project:releng:signing:cert:release-signing``. Each signing task is required
+to have exactly one of those scopes, and only nightly- and release-enabled
+branches are able to use the latter two scopes. If a task is scheduled with one
+of those restricted scopes on a non-allowlisted branch, Chain of Trust
+verification will raise an exception.
+
+Signing scriptworker workerTypes
+--------------------------------
+
+The `depsigning`_ pool handles all of the dep signing. These are heavily in use
+on try, mozilla-inbound, and autoland, but also other branches. These verify
+the `chain of trust` artifact but not its signature, and they don't have a
+gpg key to sign their own chain of trust artifact. This is by design; the chain
+of trust should and will break if a production scriptworker is downstream from
+a depsigning worker.
+
+The `signing-linux-v1`_ pool is the production signing pool; it handles the
+nightly- and release- signing requests. As such, it verifies the upstream
+chain of trust and all signatures, and signs its chain of trust artifact.
+
+The `signing-linux-dev`_ pool is intended for signingscript and scriptworker
+development use. Because it isn't used on any Firefox-developer-facing branch,
+Mozilla Releng is able to make breaking changes on this pool without affecting
+any other team.
+
+.. _60.0: https://archive.mozilla.org/pub/firefox/releases/60.0/
+.. _addonscript: https://github.com/mozilla-releng/addonscript/
+.. _code signing: https://en.wikipedia.org/wiki/Code_signing
+.. _chain of trust: https://scriptworker.readthedocs.io/en/latest/chain_of_trust.html
+.. _depsigning: https://tools.taskcluster.net/provisioners/scriptworker-prov-v1/worker-types/depsigning
+.. __should_sign_windows: https://github.com/mozilla-releng/signingscript/blob/65cbb99ea53896fda9f4844e050a9695c762d24f/signingscript/sign.py#L369
+.. _Encrypted Media Extensions: https://hacks.mozilla.org/2014/05/reconciling-mozillas-mission-and-w3c-eme/
+.. _signing password files: https://github.com/mozilla/build-puppet/tree/feff5e12ab70f2c060b29940464e77208c7f0ef2/modules/signing_scriptworker/templates
+.. _signingscript: https://github.com/mozilla-releng/signingscript/
+.. _signing-linux-dev: https://tools.taskcluster.net/provisioners/scriptworker-prov-v1/worker-types/signing-linux-dev
+.. _signing-linux-v1: https://tools.taskcluster.net/provisioners/scriptworker-prov-v1/worker-types/signing-linux-v1
+.. _signtool: https://github.com/mozilla-releng/signtool
+.. _Scriptworker: https://github.com/mozilla-releng/scriptworker/
+.. _widevine site: https://www.widevine.com/wv_drm.html
--- a/testing/web-platform/meta/2dcontext/fill-and-stroke-styles/2d.pattern.image.broken.html.ini
+++ b/testing/web-platform/meta/2dcontext/fill-and-stroke-styles/2d.pattern.image.broken.html.ini
@@ -1,11 +1,8 @@
 [2d.pattern.image.broken.html]
   [Canvas test: 2d.pattern.image.broken]
     disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1016482
     expected:
       if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): FAIL
-      if not debug and (os == "mac") and (version == "OS X 10.9") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
-      if not debug and (os == "mac") and (version == "OS X 10.8") and (processor == "x86_64") and (bits == 64): FAIL
 
--- a/testing/web-platform/meta/html/semantics/embedded-content/media-elements/event_timeupdate.html.ini
+++ b/testing/web-platform/meta/html/semantics/embedded-content/media-elements/event_timeupdate.html.ini
@@ -1,10 +1,5 @@
 [event_timeupdate.html]
   expected:
-    if debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
-    if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): TIMEOUT
     if debug and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): CRASH
-  [setting src attribute on a sufficiently long autoplay audio should trigger timeupdate event]
-    expected:
-      if debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): NOTRUN
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): NOTRUN
 
+
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -423,16 +423,60 @@ private:
 };
 
 NS_IMPL_ISUPPORTS(VPXReporter, nsIMemoryReporter)
 
 /* static */ template<> Atomic<size_t>
 CountingAllocatorBase<VPXReporter>::sAmount(0);
 #endif /* MOZ_VPX */
 
+#ifdef ENABLE_BIGINT
+class GMPReporter final
+  : public nsIMemoryReporter
+  , public CountingAllocatorBase<GMPReporter>
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  static void* Alloc(size_t size)
+  {
+    return CountingMalloc(size);
+  }
+
+  static void* Realloc(void* ptr, size_t oldSize, size_t newSize)
+  {
+    return CountingRealloc(ptr, newSize);
+  }
+
+  static void Free(void* ptr, size_t size)
+  {
+    return CountingFree(ptr);
+  }
+
+private:
+  NS_IMETHOD
+  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                 bool aAnonymize) override
+  {
+    MOZ_COLLECT_REPORT(
+      "explicit/gmp", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
+      "Memory allocated through libgmp for BigInt arithmetic.");
+
+    return NS_OK;
+  }
+
+  ~GMPReporter() {}
+};
+
+NS_IMPL_ISUPPORTS(GMPReporter, nsIMemoryReporter)
+
+/* static */ template<> Atomic<size_t>
+CountingAllocatorBase<GMPReporter>::sAmount(0);
+#endif // ENABLE_BIGINT
+
 static bool sInitializedJS = false;
 
 // Note that on OSX, aBinDirectory will point to .app/Contents/Resources/browser
 EXPORT_XPCOM_API(nsresult)
 NS_InitXPCOM2(nsIServiceManager** aResult,
               nsIFile* aBinDirectory,
               nsIDirectoryServiceProvider* aAppFileLocationProvider)
 {
@@ -632,16 +676,21 @@ NS_InitXPCOM2(nsIServiceManager** aResul
                         VPXReporter::CountingCalloc,
                         VPXReporter::CountingRealloc,
                         VPXReporter::CountingFree,
                         memcpy,
                         memset,
                         memmove);
 #endif
 
+#ifdef ENABLE_BIGINT
+  // And for libgmp.
+  mozilla::SetGMPMemoryFunctions();
+#endif
+
   // Initialize the JS engine.
   const char* jsInitFailureReason = JS_InitWithFailureDiagnostic();
   if (jsInitFailureReason) {
     MOZ_CRASH_UNSAFE_OOL(jsInitFailureReason);
   }
   sInitializedJS = true;
 
   rv = nsComponentManagerImpl::gComponentManager->Init();
@@ -792,16 +841,30 @@ SetICUMemoryFunctions()
     if (!JS_SetICUMemoryFunctions(ICUReporter::Alloc, ICUReporter::Realloc,
                                   ICUReporter::Free)) {
       MOZ_CRASH("JS_SetICUMemoryFunctions failed.");
     }
     sICUReporterInitialized = true;
   }
 }
 
+#ifdef ENABLE_BIGINT
+void
+SetGMPMemoryFunctions()
+{
+  static bool sGMPReporterInitialized = false;
+  if (!sGMPReporterInitialized) {
+    JS::SetGMPMemoryFunctions(GMPReporter::Alloc,
+                              GMPReporter::Realloc,
+                              GMPReporter::Free);
+    sGMPReporterInitialized = true;
+  }
+}
+#endif
+
 nsresult
 ShutdownXPCOM(nsIServiceManager* aServMgr)
 {
   // Make sure the hang monitor is enabled for shutdown.
   HangMonitor::NotifyActivity();
 
   if (!NS_IsMainThread()) {
     MOZ_CRASH("Shutdown on wrong thread");
--- a/xpcom/build/nsXPCOMPrivate.h
+++ b/xpcom/build/nsXPCOMPrivate.h
@@ -36,16 +36,20 @@ namespace mozilla {
  *         other error codes indicate a failure during shutdown
  *
  */
 nsresult
 ShutdownXPCOM(nsIServiceManager* aServMgr);
 
 void SetICUMemoryFunctions();
 
+#ifdef ENABLE_BIGINT
+void SetGMPMemoryFunctions();
+#endif
+
 /**
  * C++ namespaced version of NS_LogTerm.
  */
 void LogTerm();
 
 } // namespace mozilla
 
 
--- a/xpcom/ds/nsIPersistentProperties2.idl
+++ b/xpcom/ds/nsIPersistentProperties2.idl
@@ -4,16 +4,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIProperties.idl"
 
 interface nsIInputStream;
 interface nsIOutputStream;
 interface nsISimpleEnumerator;
 
+%{C++
+#include "mozilla/MemoryReporting.h"
+%}
+
 [scriptable, uuid(283EE646-1AEF-11D4-98B3-00C04fA0CE9A)]
 interface nsIPropertyElement : nsISupports {
   attribute AUTF8String key;
   attribute AString value;
 };
 
 [scriptable, uuid(706867af-0400-4faa-beb1-0dae87308784)]
 interface nsIPersistentProperties : nsIProperties
@@ -43,21 +47,24 @@ interface nsIPersistentProperties : nsIP
   AString getStringProperty(in AUTF8String key);
 
   /**
    * shortcut to nsIProperty's set() which sets a string value
    * directly (and thus faster). If the given property already exists,
    * then the old value will be returned
    */
   AString setStringProperty(in AUTF8String key, in AString value);
+
+%{C++
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+%}
 };
 
 
 %{C++
 
 #define NS_IPERSISTENTPROPERTIES_CID \
 { 0x2245e573, 0x9464, 0x11d2, \
   { 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
 
 #define NS_PERSISTENTPROPERTIES_CONTRACTID "@mozilla.org/persistent-properties;1"
 
 %}
-
--- a/xpcom/ds/nsPersistentProperties.cpp
+++ b/xpcom/ds/nsPersistentProperties.cpp
@@ -439,16 +439,26 @@ nsPersistentProperties::nsPersistentProp
   , mArena()
 {
 }
 
 nsPersistentProperties::~nsPersistentProperties()
 {
 }
 
+size_t
+nsPersistentProperties::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  // The memory used by mTable is accounted for in mArena.
+  size_t n = 0;
+  n += mArena.SizeOfExcludingThis(aMallocSizeOf);
+  n += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  return aMallocSizeOf(this) + n;
+}
+
 nsresult
 nsPersistentProperties::Create(nsISupports* aOuter, REFNSIID aIID,
                                void** aResult)
 {
   if (aOuter) {
     return NS_ERROR_NO_AGGREGATION;
   }
   RefPtr<nsPersistentProperties> props = new nsPersistentProperties();
--- a/xpcom/ds/nsPersistentProperties.h
+++ b/xpcom/ds/nsPersistentProperties.h
@@ -23,16 +23,18 @@ public:
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIPROPERTIES
   NS_DECL_NSIPERSISTENTPROPERTIES
 
   static MOZ_MUST_USE nsresult
   Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
 private:
   ~nsPersistentProperties();
 
 protected:
   nsCOMPtr<nsIUnicharInputStream> mIn;
 
   PLDHashTable mTable;
   mozilla::ArenaAllocator<2048,4> mArena;