merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sat, 08 Apr 2017 22:49:04 +0200
changeset 352009 2a3ecdb7d1ea814708021fee6735b3aedcf03e48
parent 351959 21c4aca1ae6046f4b90b001badcabee97f543820 (current diff)
parent 352008 0cf22ef8e29c1581d5dbd97714dcec6af521249b (diff)
child 352010 0a53c62750fffbbc61bece811c429b8eabed0064
child 352012 c9a4d8de18087d34d76515d749f9af80544e2c5f
child 352038 fa479184aa2bfc40e510540b26ac0de1267a580a
push id31624
push userarchaeopteryx@coole-files.de
push dateSat, 08 Apr 2017 20:49:20 +0000
treeherdermozilla-central@2a3ecdb7d1ea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone55.0a1
first release with
nightly mac
2a3ecdb7d1ea / 55.0a1 / 20170409030205 / files
nightly win32
2a3ecdb7d1ea / 55.0a1 / 20170409030205 / files
nightly win64
2a3ecdb7d1ea / 55.0a1 / 20170409030205 / files
nightly linux32
nightly linux64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: IkoXCAwjjKu
dom/base/test/browser_docgroup_forbid.js
dom/base/test/file_docgroup_forbid.html
js/xpconnect/wrappers/DocGroupValidationWrapper.cpp
js/xpconnect/wrappers/DocGroupValidationWrapper.h
layout/inspector/inDOMUtils.cpp
modules/libpref/init/all.js
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/fetch-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/fetch-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/fetch-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/object-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/object-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/object-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/picture-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/picture-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/picture-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/script-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/script-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/script-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/xhr-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/xhr-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/xhr-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/fetch-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/fetch-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/fetch-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/object-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/object-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/object-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/picture-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/picture-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/picture-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/script-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/script-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/script-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/xhr-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/xhr-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/xhr-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/audio-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/audio-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/audio-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/img-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/img-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/img-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/video-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/audio-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/audio-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/audio-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/img-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/img-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/img-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
testing/web-platform/tests/service-workers/service-worker/registration-useCache.https.html
testing/web-platform/tests/service-workers/service-worker/resources/update-max-aged-worker-imported-script.py
testing/web-platform/tests/service-workers/service-worker/resources/update-max-aged-worker.py
toolkit/components/telemetry/Histograms.json
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -57,16 +57,17 @@ nsContextMenu.prototype = {
         onCanvas: this.onCanvas,
         onEditableArea: this.onEditableArea,
         onPassword: this.onPassword,
         srcUrl: this.mediaURL,
         frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
         pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
         linkUrl: this.linkURL,
         selectionText: this.isTextSelected ? this.selectionInfo.text : undefined,
+        windowId: this.frameOuterWindowID,
       };
       subject.wrappedJSObject = subject;
       Services.obs.notifyObservers(subject, "on-build-contextmenu", null);
     }
 
     this.isFrameImage = document.getElementById("isFrameImage");
     this.ellipsis = "\u2026";
     try {
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -1,12 +1,13 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
+Cu.import("resource://gre/modules/ExtensionManagement.jsm");
 Cu.import("resource://gre/modules/MatchPattern.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 
 var {
   ExtensionError,
@@ -490,16 +491,21 @@ MenuItem.prototype = {
     }
     if (contextData.onAudio) {
       mediaType = "audio";
     }
     if (contextData.onImage) {
       mediaType = "image";
     }
 
+    let frameId;
+    if (contextData.windowId) {
+      frameId = ExtensionManagement.getFrameId(contextData.windowId);
+    }
+
     let info = {
       menuItemId: this.id,
       editable: contextData.onEditableArea || contextData.onPassword,
     };
 
     function setIfDefined(argName, value) {
       if (value !== undefined) {
         info[argName] = value;
@@ -507,16 +513,17 @@ MenuItem.prototype = {
     }
 
     setIfDefined("parentMenuItemId", this.parentId);
     setIfDefined("mediaType", mediaType);
     setIfDefined("linkUrl", contextData.linkUrl);
     setIfDefined("srcUrl", contextData.srcUrl);
     setIfDefined("pageUrl", contextData.pageUrl);
     setIfDefined("frameUrl", contextData.frameUrl);
+    setIfDefined("frameId", frameId);
     setIfDefined("selectionText", contextData.selectionText);
 
     if ((this.type === "checkbox") || (this.type === "radio")) {
       info.checked = this.checked;
       info.wasChecked = wasChecked;
     }
 
     return info;
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus_chrome.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_chrome.js
@@ -120,13 +120,52 @@ add_task(function* test_tabContextMenu()
   is(alpha.label, "alpha", "First menu item label is correct");
   is(beta.tagName, "menuitem", "Second menu item type is correct");
   is(beta.label, "beta", "Second menu item label is correct");
 
   yield closeTabContextMenu(beta);
   const click = yield first.awaitMessage("click");
   is(click.info.pageUrl, "http://example.com/", "Click info pageUrl is correct");
   is(click.tab.id, tabId, "Click event tab ID is correct");
+  is(click.info.frameId, undefined, "no frameId on chrome");
 
   yield BrowserTestUtils.removeTab(tab);
   yield first.unload();
   yield second.unload();
 });
+
+add_task(function* test_onclick_frameid() {
+  const manifest = {
+    permissions: ["contextMenus"],
+  };
+
+  function background() {
+    function onclick(info) {
+      browser.test.sendMessage("click", info);
+    }
+    browser.contextMenus.create({contexts: ["frame", "page"], title: "modify", onclick});
+    browser.test.sendMessage("ready");
+  }
+
+  const extension = ExtensionTestUtils.loadExtension({manifest, background});
+  const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
+    "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
+
+  yield extension.startup();
+  yield extension.awaitMessage("ready");
+
+  function* click(selectorOrId) {
+    const func = (selectorOrId == "body") ? openContextMenu : openContextMenuInFrame;
+    const menu = yield func(selectorOrId);
+    const items = menu.getElementsByAttribute("label", "modify");
+    yield closeExtensionContextMenu(items[0]);
+    return extension.awaitMessage("click");
+  }
+
+  let info = yield click("body");
+  is(info.frameId, 0, "top level click");
+  info = yield click("frame");
+  isnot(info.frameId, undefined, "frame click, frameId is not undefined");
+  isnot(info.frameId, 0, "frame click, frameId probably okay");
+
+  yield BrowserTestUtils.removeTab(tab);
+  yield extension.unload();
+});
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -211,17 +211,17 @@ module.exports = createClass({
     let marginRight = this.getMarginValue("margin-right", "right");
     let marginBottom = this.getMarginValue("margin-bottom", "bottom");
     let marginLeft = this.getMarginValue("margin-left", "left");
 
     height = this.getHeightValue(height);
     width = this.getWidthValue(width);
 
     let contentBox = layout["box-sizing"] == "content-box" ?
-      dom.p(
+      dom.div(
         {
           className: "boxmodel-size",
         },
         BoxModelEditable({
           box: "content",
           property: "width",
           textContent: width,
           onShowBoxModelEditor
--- a/devtools/client/inspector/grids/components/GridItem.js
+++ b/devtools/client/inspector/grids/components/GridItem.js
@@ -112,17 +112,16 @@ module.exports = createClass({
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
     } = this.props;
     let { nodeFront } = grid;
 
     return dom.li(
       {
-        key: grid.id,
         className: "grid-item",
       },
       dom.label(
         {},
         dom.input(
           {
             type: "checkbox",
             value: grid.id,
--- a/devtools/client/inspector/grids/components/GridList.js
+++ b/devtools/client/inspector/grids/components/GridList.js
@@ -45,16 +45,17 @@ module.exports = createClass({
       },
       dom.span(
         {},
         getStr("layout.overlayGrid")
       ),
       dom.ul(
         {},
         grids.map(grid => GridItem({
+          key: grid.id,
           getSwatchColorPickerTooltip,
           grid,
           setSelectedNode,
           onHideBoxModelHighlighter,
           onSetGridOverlayColor,
           onShowBoxModelHighlighterForNode,
           onToggleGridHighlighter,
         }))
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -480,23 +480,28 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "fill",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
+      "repeat",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
+      "round",
+      "space",
+      "stretch",
       "unset",
       "url"
     ]
   },
   "-moz-border-left-colors": {
     "isInherited": false,
     "subproperties": [
       "-moz-border-left-colors"
@@ -1194,18 +1199,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "perspective-origin"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-moz-stack-sizing": {
     "isInherited": false,
     "subproperties": [
       "-moz-stack-sizing"
     ],
@@ -1265,18 +1275,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "transform-origin"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-moz-transform-style": {
     "isInherited": false,
     "subproperties": [
       "transform-style"
     ],
@@ -1781,16 +1796,18 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "background-size"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
+      "contain",
+      "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-border-bottom-left-radius": {
     "isInherited": false,
     "subproperties": [
@@ -1840,23 +1857,28 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "fill",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
+      "repeat",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
+      "round",
+      "space",
+      "stretch",
       "unset",
       "url"
     ]
   },
   "-webkit-border-radius": {
     "isInherited": false,
     "subproperties": [
       "border-top-left-radius",
@@ -2002,16 +2024,17 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [
       2,
       6
     ],
     "values": [
       "inherit",
       "initial",
+      "inset",
       "unset"
     ]
   },
   "-webkit-box-sizing": {
     "isInherited": false,
     "subproperties": [
       "box-sizing"
     ],
@@ -2213,39 +2236,46 @@ exports.CSS_PROPERTIES = {
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
       "add",
       "alpha",
       "border-box",
+      "bottom",
+      "center",
+      "contain",
       "content-box",
+      "cover",
       "exclude",
       "fill-box",
       "inherit",
       "initial",
       "intersect",
+      "left",
       "linear-gradient",
       "luminance",
       "match-source",
       "no-clip",
       "no-repeat",
       "none",
       "padding-box",
       "radial-gradient",
       "repeat",
       "repeat-x",
       "repeat-y",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
+      "right",
       "round",
       "space",
       "stroke-box",
       "subtract",
+      "top",
       "unset",
       "url",
       "view-box"
     ]
   },
   "-webkit-mask-clip": {
     "isInherited": false,
     "subproperties": [
@@ -2333,48 +2363,63 @@ exports.CSS_PROPERTIES = {
       "mask-position-x",
       "mask-position-y"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-webkit-mask-position-x": {
     "isInherited": false,
     "subproperties": [
       "mask-position-x"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-webkit-mask-position-y": {
     "isInherited": false,
     "subproperties": [
       "mask-position-y"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-webkit-mask-repeat": {
     "isInherited": false,
     "subproperties": [
       "mask-repeat"
     ],
@@ -2396,16 +2441,18 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "mask-size"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
+      "contain",
+      "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-order": {
     "isInherited": false,
     "subproperties": [
@@ -2440,18 +2487,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "perspective-origin"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-webkit-text-fill-color": {
     "isInherited": true,
     "subproperties": [
       "-webkit-text-fill-color"
     ],
@@ -2568,18 +2620,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "transform-origin"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "-webkit-transform-style": {
     "isInherited": false,
     "subproperties": [
       "transform-style"
     ],
@@ -3109,185 +3166,232 @@ exports.CSS_PROPERTIES = {
       8,
       9,
       10,
       11
     ],
     "values": [
       "COLOR",
       "-moz-all",
+      "-moz-alt-content",
+      "-moz-anchor-decoration",
       "-moz-available",
       "-moz-block-height",
       "-moz-box",
+      "-moz-button",
       "-moz-center",
       "-moz-crisp-edges",
       "-moz-deck",
+      "-moz-desktop",
+      "-moz-dialog",
+      "-moz-document",
       "-moz-element",
+      "-moz-field",
       "-moz-fit-content",
       "-moz-grid",
       "-moz-grid-group",
       "-moz-grid-line",
       "-moz-groupbox",
       "-moz-gtk-info-bar",
       "-moz-hidden-unscrollable",
       "-moz-image-rect",
+      "-moz-info",
       "-moz-inline-box",
       "-moz-inline-grid",
       "-moz-inline-stack",
       "-moz-left",
       "-moz-linear-gradient",
+      "-moz-list",
       "-moz-mac-active-source-list-selection",
       "-moz-mac-disclosure-button-closed",
       "-moz-mac-disclosure-button-open",
       "-moz-mac-fullscreen-button",
       "-moz-mac-help-button",
       "-moz-mac-source-list",
       "-moz-mac-source-list-selection",
       "-moz-mac-vibrancy-dark",
       "-moz-mac-vibrancy-light",
       "-moz-max-content",
       "-moz-middle-with-baseline",
       "-moz-min-content",
       "-moz-none",
       "-moz-popup",
       "-moz-pre-space",
+      "-moz-pull-down-menu",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
       "-moz-right",
       "-moz-stack",
       "-moz-text",
       "-moz-win-borderless-glass",
       "-moz-win-browsertabbar-toolbox",
       "-moz-win-communications-toolbox",
       "-moz-win-exclude-glass",
       "-moz-win-glass",
       "-moz-win-media-toolbox",
+      "-moz-window",
       "-moz-window-button-box",
       "-moz-window-button-box-maximized",
       "-moz-window-button-close",
       "-moz-window-button-maximize",
       "-moz-window-button-minimize",
       "-moz-window-button-restore",
       "-moz-window-frame-bottom",
       "-moz-window-frame-left",
       "-moz-window-frame-right",
       "-moz-window-titlebar",
       "-moz-window-titlebar-maximized",
+      "-moz-workspace",
       "-webkit-box",
       "-webkit-flex",
       "-webkit-inline-box",
       "-webkit-inline-flex",
       "absolute",
       "active",
       "add",
+      "alias",
       "all",
       "all-petite-caps",
+      "all-scroll",
       "all-small-caps",
       "alpha",
       "alphabetic",
       "alternate",
       "alternate-reverse",
       "always",
       "auto",
       "avoid",
       "backwards",
       "balance",
       "baseline",
       "bevel",
+      "blink",
       "block",
       "block-axis",
+      "bold",
+      "bolder",
       "border-box",
       "both",
       "bottom",
       "bottom-outside",
       "break-all",
       "break-word",
       "butt",
       "button",
       "button-arrow-down",
       "button-arrow-next",
       "button-arrow-previous",
       "button-arrow-up",
       "button-bevel",
       "button-focus",
       "calc",
       "capitalize",
+      "caption",
       "caret",
+      "cell",
       "center",
       "central",
       "checkbox",
       "checkbox-container",
       "checkbox-label",
       "checkmenuitem",
+      "clip",
       "clone",
+      "close-quote",
+      "col-resize",
       "collapse",
       "color",
       "color-burn",
       "color-dodge",
       "column",
       "column-reverse",
+      "common-ligatures",
       "condensed",
       "contain",
       "content-box",
       "contents",
+      "context-fill",
+      "context-fill-opacity",
+      "context-menu",
+      "context-stroke",
+      "context-stroke-opacity",
+      "context-value",
+      "contextual",
+      "copy",
       "cover",
       "crispedges",
+      "crosshair",
       "cubic-bezier",
       "currentColor",
       "darken",
       "dashed",
       "default",
+      "dense",
+      "diagonal-fractions",
       "dialog",
       "difference",
+      "digits",
       "disabled",
+      "discretionary-ligatures",
       "distribute",
       "dotted",
       "double",
       "drag",
       "dualbutton",
+      "e-resize",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "economy",
       "element",
       "elements",
+      "ellipsis",
       "enabled",
       "end",
       "evenodd",
+      "ew-resize",
       "exact",
       "exclude",
       "exclusion",
       "expanded",
       "extra-condensed",
       "extra-expanded",
       "fill",
       "fill-box",
       "fixed",
       "flat",
       "flex",
       "flex-end",
       "flex-start",
+      "flip",
       "flow-root",
       "forwards",
+      "from-image",
       "full-width",
       "geometricprecision",
+      "grab",
+      "grabbing",
       "grid",
       "groove",
       "groupbox",
       "hanging",
       "hard-light",
+      "help",
       "hidden",
       "hide",
+      "historical-forms",
+      "historical-ligatures",
       "horizontal",
       "horizontal-tb",
       "hsl",
       "hsla",
       "hue",
+      "icon",
       "ideographic",
       "ignore",
       "inactive",
       "infinite",
       "inherit",
       "initial",
       "inline",
       "inline-axis",
@@ -3299,93 +3403,127 @@ exports.CSS_PROPERTIES = {
       "inline-table",
       "inset",
       "inside",
       "inter-character",
       "inter-word",
       "intersect",
       "isolate",
       "italic",
+      "jis04",
+      "jis78",
+      "jis83",
+      "jis90",
       "justify",
       "keep-all",
       "large",
       "larger",
       "last baseline",
       "left",
       "lighten",
+      "lighter",
+      "line-through",
       "linear",
       "linear-gradient",
       "linearrgb",
+      "lining-nums",
       "list-item",
       "listbox",
       "listitem",
       "local",
       "lowercase",
       "lr",
       "lr-tb",
       "luminance",
       "luminosity",
       "mandatory",
       "manipulation",
       "manual",
       "margin-box",
       "match-source",
       "mathematical",
+      "max-content",
       "medium",
+      "menu",
       "menuarrow",
       "menubar",
       "menucheckbox",
       "menuimage",
       "menuitem",
       "menuitemtext",
       "menulist",
       "menulist-button",
       "menulist-text",
       "menulist-textfield",
       "menupopup",
       "menuradio",
       "menuseparator",
+      "message-box",
       "meterbar",
       "meterchunk",
       "middle",
+      "min-content",
       "miter",
       "mixed",
+      "move",
       "multiply",
+      "n-resize",
+      "ne-resize",
+      "nesw-resize",
       "no-change",
       "no-clip",
+      "no-close-quote",
+      "no-common-ligatures",
+      "no-contextual",
+      "no-discretionary-ligatures",
       "no-drag",
+      "no-drop",
+      "no-historical-ligatures",
+      "no-open-quote",
       "no-repeat",
       "non-scaling-stroke",
       "none",
       "nonzero",
       "normal",
+      "not-allowed",
       "nowrap",
+      "ns-resize",
       "number-input",
+      "nw-resize",
+      "nwse-resize",
       "oblique",
+      "oldstyle-nums",
+      "open-quote",
       "optimizelegibility",
       "optimizequality",
       "optimizespeed",
+      "ordinal",
       "outset",
       "outside",
       "over",
       "overlay",
+      "overline",
       "padding-box",
       "painted",
       "pan-x",
       "pan-y",
       "paused",
       "petite-caps",
+      "pointer",
       "pre",
       "pre-line",
       "pre-wrap",
       "preserve-3d",
+      "progress",
       "progressbar",
       "progressbar-vertical",
       "progresschunk",
       "progresschunk-vertical",
+      "proportional-nums",
+      "proportional-width",
       "proximity",
       "radial-gradient",
       "radio",
       "radio-container",
       "radio-label",
       "radiomenuitem",
       "range",
       "range-thumb",
@@ -3404,23 +3542,25 @@ exports.CSS_PROPERTIES = {
       "rgb",
       "rgba",
       "ridge",
       "right",
       "rl",
       "rl-tb",
       "round",
       "row",
+      "row-resize",
       "row-reverse",
       "ruby",
       "ruby-base",
       "ruby-base-container",
       "ruby-text",
       "ruby-text-container",
       "running",
+      "s-resize",
       "saturation",
       "scale-down",
       "scale-horizontal",
       "scale-vertical",
       "scalethumb-horizontal",
       "scalethumb-vertical",
       "scalethumbend",
       "scalethumbstart",
@@ -3434,16 +3574,17 @@ exports.CSS_PROPERTIES = {
       "scrollbarbutton-down",
       "scrollbarbutton-left",
       "scrollbarbutton-right",
       "scrollbarbutton-up",
       "scrollbarthumb-horizontal",
       "scrollbarthumb-vertical",
       "scrollbartrack-horizontal",
       "scrollbartrack-vertical",
+      "se-resize",
       "searchfield",
       "select-after",
       "select-all",
       "select-before",
       "select-menu",
       "select-same",
       "self-end",
       "self-start",
@@ -3451,63 +3592,71 @@ exports.CSS_PROPERTIES = {
       "semi-expanded",
       "separate",
       "separator",
       "show",
       "sideways",
       "sideways-lr",
       "sideways-right",
       "sideways-rl",
+      "simplified",
+      "slashed-zero",
       "slice",
       "small",
       "small-caps",
+      "small-caption",
       "smaller",
       "smooth",
       "soft-light",
       "solid",
       "space",
       "space-around",
       "space-between",
       "space-evenly",
       "spinner",
       "spinner-downbutton",
       "spinner-textfield",
       "spinner-upbutton",
       "splitter",
       "square",
       "srgb",
+      "stacked-fractions",
       "start",
       "static",
+      "status-bar",
       "statusbar",
       "statusbarpanel",
       "step-end",
       "step-start",
       "steps",
       "sticky",
       "stretch",
       "stretch-to-fit",
       "stroke",
       "stroke-box",
+      "style",
       "sub",
       "subtract",
       "super",
+      "sw-resize",
       "tab",
       "tab-scroll-arrow-back",
       "tab-scroll-arrow-forward",
       "table",
       "table-caption",
       "table-cell",
       "table-column",
       "table-column-group",
       "table-footer-group",
       "table-header-group",
       "table-row",
       "table-row-group",
       "tabpanel",
       "tabpanels",
+      "tabular-nums",
       "tb",
       "tb-rl",
       "text",
       "text-after-edge",
       "text-before-edge",
       "text-bottom",
       "text-top",
       "textfield",
@@ -3519,52 +3668,60 @@ exports.CSS_PROPERTIES = {
       "toolbar",
       "toolbarbutton",
       "toolbarbutton-dropdown",
       "toolbargripper",
       "toolbox",
       "tooltip",
       "top",
       "top-outside",
+      "traditional",
       "transparent",
       "treeheader",
       "treeheadercell",
       "treeheadersortarrow",
       "treeitem",
       "treeline",
       "treetwisty",
       "treetwistyopen",
       "treeview",
       "tri-state",
       "ultra-condensed",
       "ultra-expanded",
       "under",
+      "underline",
       "unicase",
       "unset",
       "uppercase",
       "upright",
       "url",
       "use-script",
       "vertical",
       "vertical-lr",
       "vertical-rl",
+      "vertical-text",
       "view-box",
       "visible",
       "visiblefill",
       "visiblepainted",
       "visiblestroke",
+      "w-resize",
+      "wait",
       "wavy",
+      "weight",
       "window",
       "wrap",
       "wrap-reverse",
       "write-only",
       "x-large",
       "x-small",
       "xx-large",
-      "xx-small"
+      "xx-small",
+      "zoom-in",
+      "zoom-out"
     ]
   },
   "animation": {
     "isInherited": false,
     "subproperties": [
       "animation-duration",
       "animation-timing-function",
       "animation-delay",
@@ -3783,40 +3940,47 @@ exports.CSS_PROPERTIES = {
       "COLOR",
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
       "border-box",
+      "bottom",
+      "center",
+      "contain",
       "content-box",
+      "cover",
       "currentColor",
       "fixed",
       "hsl",
       "hsla",
       "inherit",
       "initial",
+      "left",
       "linear-gradient",
       "local",
       "no-repeat",
       "none",
       "padding-box",
       "radial-gradient",
       "repeat",
       "repeat-x",
       "repeat-y",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
       "rgb",
       "rgba",
+      "right",
       "round",
       "scroll",
       "space",
       "text",
+      "top",
       "transparent",
       "unset",
       "url"
     ]
   },
   "background-attachment": {
     "isInherited": false,
     "subproperties": [
@@ -3946,48 +4110,63 @@ exports.CSS_PROPERTIES = {
       "background-position-x",
       "background-position-y"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "background-position-x": {
     "isInherited": false,
     "subproperties": [
       "background-position-x"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "background-position-y": {
     "isInherited": false,
     "subproperties": [
       "background-position-y"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "background-repeat": {
     "isInherited": false,
     "subproperties": [
       "background-repeat"
     ],
@@ -4009,16 +4188,18 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "background-size"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
+      "contain",
+      "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "block-size": {
     "isInherited": false,
     "subproperties": [
@@ -4073,34 +4254,39 @@ exports.CSS_PROPERTIES = {
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
       "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
+      "fill",
       "groove",
       "hidden",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "inset",
       "linear-gradient",
       "medium",
       "none",
       "outset",
       "radial-gradient",
+      "repeat",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
       "rgb",
       "rgba",
       "ridge",
+      "round",
       "solid",
+      "space",
+      "stretch",
       "thick",
       "thin",
       "transparent",
       "unset",
       "url"
     ]
   },
   "border-block-end": {
@@ -4487,23 +4673,28 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "fill",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
+      "repeat",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
+      "round",
+      "space",
+      "stretch",
       "unset",
       "url"
     ]
   },
   "border-image-outset": {
     "isInherited": false,
     "subproperties": [
       "border-image-outset"
@@ -4522,29 +4713,34 @@ exports.CSS_PROPERTIES = {
     "isInherited": false,
     "subproperties": [
       "border-image-repeat"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "repeat",
+      "round",
+      "space",
+      "stretch",
       "unset"
     ]
   },
   "border-image-slice": {
     "isInherited": false,
     "subproperties": [
       "border-image-slice"
     ],
     "supports": [
       7,
       8
     ],
     "values": [
+      "fill",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "border-image-source": {
     "isInherited": false,
     "subproperties": [
@@ -5230,16 +5426,17 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [
       2,
       6
     ],
     "values": [
       "inherit",
       "initial",
+      "inset",
       "unset"
     ]
   },
   "box-sizing": {
     "isInherited": false,
     "subproperties": [
       "box-sizing"
     ],
@@ -5597,18 +5794,23 @@ exports.CSS_PROPERTIES = {
     "isInherited": false,
     "subproperties": [
       "content"
     ],
     "supports": [
       11
     ],
     "values": [
-      "inherit",
-      "initial",
+      "-moz-alt-content",
+      "close-quote",
+      "inherit",
+      "initial",
+      "no-close-quote",
+      "no-open-quote",
+      "open-quote",
       "unset"
     ]
   },
   "counter-increment": {
     "isInherited": false,
     "subproperties": [
       "counter-increment"
     ],
@@ -5635,19 +5837,55 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "cursor"
     ],
     "supports": [
       11
     ],
     "values": [
-      "inherit",
-      "initial",
-      "unset"
+      "alias",
+      "all-scroll",
+      "auto",
+      "cell",
+      "col-resize",
+      "context-menu",
+      "copy",
+      "crosshair",
+      "default",
+      "e-resize",
+      "ew-resize",
+      "grab",
+      "grabbing",
+      "help",
+      "inherit",
+      "initial",
+      "move",
+      "n-resize",
+      "ne-resize",
+      "nesw-resize",
+      "no-drop",
+      "none",
+      "not-allowed",
+      "ns-resize",
+      "nw-resize",
+      "nwse-resize",
+      "pointer",
+      "progress",
+      "row-resize",
+      "s-resize",
+      "se-resize",
+      "sw-resize",
+      "text",
+      "unset",
+      "vertical-text",
+      "w-resize",
+      "wait",
+      "zoom-in",
+      "zoom-out"
     ]
   },
   "direction": {
     "isInherited": true,
     "subproperties": [
       "direction"
     ],
     "supports": [],
@@ -5755,30 +5993,34 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "fill"
     ],
     "supports": [
       2,
       11
     ],
     "values": [
+      "context-fill",
+      "context-stroke",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "fill-opacity": {
     "isInherited": true,
     "subproperties": [
       "fill-opacity"
     ],
     "supports": [
       7
     ],
     "values": [
+      "context-fill-opacity",
+      "context-stroke-opacity",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "fill-rule": {
     "isInherited": true,
     "subproperties": [
@@ -6006,42 +6248,87 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [
       6,
       7,
       8
     ],
     "values": [
       "-moz-block-height",
+      "-moz-button",
+      "-moz-desktop",
+      "-moz-dialog",
+      "-moz-document",
+      "-moz-field",
+      "-moz-info",
+      "-moz-list",
+      "-moz-pull-down-menu",
+      "-moz-window",
+      "-moz-workspace",
       "all-petite-caps",
       "all-small-caps",
       "auto",
+      "bold",
+      "bolder",
       "calc",
+      "caption",
+      "common-ligatures",
       "condensed",
+      "contextual",
+      "diagonal-fractions",
+      "discretionary-ligatures",
       "expanded",
       "extra-condensed",
       "extra-expanded",
+      "full-width",
+      "historical-forms",
+      "historical-ligatures",
+      "icon",
       "inherit",
       "initial",
       "italic",
+      "jis04",
+      "jis78",
+      "jis83",
+      "jis90",
       "large",
       "larger",
+      "lighter",
+      "lining-nums",
       "medium",
+      "menu",
+      "message-box",
+      "no-common-ligatures",
+      "no-contextual",
+      "no-discretionary-ligatures",
+      "no-historical-ligatures",
       "none",
       "normal",
       "oblique",
+      "oldstyle-nums",
+      "ordinal",
       "petite-caps",
+      "proportional-nums",
+      "proportional-width",
+      "ruby",
       "semi-condensed",
       "semi-expanded",
+      "simplified",
+      "slashed-zero",
       "small",
       "small-caps",
+      "small-caption",
       "smaller",
+      "stacked-fractions",
+      "status-bar",
       "sub",
       "super",
+      "tabular-nums",
       "titling-caps",
+      "traditional",
       "ultra-condensed",
       "ultra-expanded",
       "unicase",
       "unset",
       "x-large",
       "x-small",
       "xx-large",
       "xx-small"
@@ -6179,52 +6466,81 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "font-synthesis"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
-      "unset"
+      "style",
+      "unset",
+      "weight"
     ]
   },
   "font-variant": {
     "isInherited": true,
     "subproperties": [
       "font-variant-alternates",
       "font-variant-caps",
       "font-variant-east-asian",
       "font-variant-ligatures",
       "font-variant-numeric",
       "font-variant-position"
     ],
     "supports": [],
     "values": [
       "all-petite-caps",
       "all-small-caps",
-      "inherit",
-      "initial",
+      "common-ligatures",
+      "contextual",
+      "diagonal-fractions",
+      "discretionary-ligatures",
+      "full-width",
+      "historical-forms",
+      "historical-ligatures",
+      "inherit",
+      "initial",
+      "jis04",
+      "jis78",
+      "jis83",
+      "jis90",
+      "lining-nums",
+      "no-common-ligatures",
+      "no-contextual",
+      "no-discretionary-ligatures",
+      "no-historical-ligatures",
       "normal",
+      "oldstyle-nums",
+      "ordinal",
       "petite-caps",
+      "proportional-nums",
+      "proportional-width",
+      "ruby",
+      "simplified",
+      "slashed-zero",
       "small-caps",
+      "stacked-fractions",
       "sub",
       "super",
+      "tabular-nums",
       "titling-caps",
+      "traditional",
       "unicase",
       "unset"
     ]
   },
   "font-variant-alternates": {
     "isInherited": true,
     "subproperties": [
       "font-variant-alternates"
     ],
     "supports": [],
     "values": [
+      "historical-forms",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "font-variant-caps": {
     "isInherited": true,
     "subproperties": [
@@ -6246,42 +6562,67 @@ exports.CSS_PROPERTIES = {
   },
   "font-variant-east-asian": {
     "isInherited": true,
     "subproperties": [
       "font-variant-east-asian"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "full-width",
+      "inherit",
+      "initial",
+      "jis04",
+      "jis78",
+      "jis83",
+      "jis90",
+      "proportional-width",
+      "ruby",
+      "simplified",
+      "traditional",
       "unset"
     ]
   },
   "font-variant-ligatures": {
     "isInherited": true,
     "subproperties": [
       "font-variant-ligatures"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "common-ligatures",
+      "contextual",
+      "discretionary-ligatures",
+      "historical-ligatures",
+      "inherit",
+      "initial",
+      "no-common-ligatures",
+      "no-contextual",
+      "no-discretionary-ligatures",
+      "no-historical-ligatures",
       "unset"
     ]
   },
   "font-variant-numeric": {
     "isInherited": true,
     "subproperties": [
       "font-variant-numeric"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "diagonal-fractions",
+      "inherit",
+      "initial",
+      "lining-nums",
+      "oldstyle-nums",
+      "ordinal",
+      "proportional-nums",
+      "slashed-zero",
+      "stacked-fractions",
+      "tabular-nums",
       "unset"
     ]
   },
   "font-variant-position": {
     "isInherited": true,
     "subproperties": [
       "font-variant-position"
     ],
@@ -6299,18 +6640,22 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "font-weight"
     ],
     "supports": [
       7
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bold",
+      "bolder",
+      "inherit",
+      "initial",
+      "lighter",
+      "normal",
       "unset"
     ]
   },
   "grid": {
     "isInherited": false,
     "subproperties": [
       "grid-template-areas",
       "grid-template-rows",
@@ -6322,18 +6667,23 @@ exports.CSS_PROPERTIES = {
       "grid-column-gap"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
       "calc",
-      "inherit",
-      "initial",
+      "column",
+      "dense",
+      "inherit",
+      "initial",
+      "max-content",
+      "min-content",
+      "row",
       "unset"
     ]
   },
   "grid-area": {
     "isInherited": false,
     "subproperties": [
       "grid-row-start",
       "grid-column-start",
@@ -6356,43 +6706,50 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [
       6,
       8
     ],
     "values": [
       "inherit",
       "initial",
+      "max-content",
+      "min-content",
       "unset"
     ]
   },
   "grid-auto-flow": {
     "isInherited": false,
     "subproperties": [
       "grid-auto-flow"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "column",
+      "dense",
+      "inherit",
+      "initial",
+      "row",
       "unset"
     ]
   },
   "grid-auto-rows": {
     "isInherited": false,
     "subproperties": [
       "grid-auto-rows"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
       "inherit",
       "initial",
+      "max-content",
+      "min-content",
       "unset"
     ]
   },
   "grid-column": {
     "isInherited": false,
     "subproperties": [
       "grid-column-start",
       "grid-column-end"
@@ -6535,16 +6892,18 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [
       6,
       8
     ],
     "values": [
       "inherit",
       "initial",
+      "max-content",
+      "min-content",
       "unset"
     ]
   },
   "grid-template-areas": {
     "isInherited": false,
     "subproperties": [
       "grid-template-areas"
     ],
@@ -6562,31 +6921,35 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [
       6,
       8
     ],
     "values": [
       "inherit",
       "initial",
+      "max-content",
+      "min-content",
       "unset"
     ]
   },
   "grid-template-rows": {
     "isInherited": false,
     "subproperties": [
       "grid-template-rows"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
       "inherit",
       "initial",
+      "max-content",
+      "min-content",
       "unset"
     ]
   },
   "height": {
     "isInherited": false,
     "subproperties": [
       "height"
     ],
@@ -6625,16 +6988,18 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "image-orientation"
     ],
     "supports": [
       1
     ],
     "values": [
+      "flip",
+      "from-image",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "image-rendering": {
     "isInherited": true,
     "subproperties": [
@@ -7163,39 +7528,46 @@ exports.CSS_PROPERTIES = {
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
       "add",
       "alpha",
       "border-box",
+      "bottom",
+      "center",
+      "contain",
       "content-box",
+      "cover",
       "exclude",
       "fill-box",
       "inherit",
       "initial",
       "intersect",
+      "left",
       "linear-gradient",
       "luminance",
       "match-source",
       "no-clip",
       "no-repeat",
       "none",
       "padding-box",
       "radial-gradient",
       "repeat",
       "repeat-x",
       "repeat-y",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
+      "right",
       "round",
       "space",
       "stroke-box",
       "subtract",
+      "top",
       "unset",
       "url",
       "view-box"
     ]
   },
   "mask-clip": {
     "isInherited": false,
     "subproperties": [
@@ -7298,48 +7670,63 @@ exports.CSS_PROPERTIES = {
       "mask-position-x",
       "mask-position-y"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "mask-position-x": {
     "isInherited": false,
     "subproperties": [
       "mask-position-x"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "mask-position-y": {
     "isInherited": false,
     "subproperties": [
       "mask-position-y"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "mask-repeat": {
     "isInherited": false,
     "subproperties": [
       "mask-repeat"
     ],
@@ -7361,16 +7748,18 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "mask-size"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
+      "contain",
+      "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "mask-type": {
     "isInherited": false,
     "subproperties": [
@@ -7595,18 +7984,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "object-position"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "offset-block-end": {
     "isInherited": false,
     "subproperties": [
       "offset-block-end"
     ],
@@ -8108,18 +8502,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "perspective-origin"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "place-content": {
     "isInherited": false,
     "subproperties": [
       "align-content",
       "justify-content"
@@ -8332,33 +8731,43 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "scroll-snap-coordinate"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "scroll-snap-destination": {
     "isInherited": false,
     "subproperties": [
       "scroll-snap-destination"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "scroll-snap-points-x": {
     "isInherited": false,
     "subproperties": [
       "scroll-snap-points-x"
     ],
@@ -8483,48 +8892,52 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "stroke"
     ],
     "supports": [
       2,
       11
     ],
     "values": [
+      "context-fill",
+      "context-stroke",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "stroke-dasharray": {
     "isInherited": true,
     "subproperties": [
       "stroke-dasharray"
     ],
     "supports": [
       6,
       7,
       8
     ],
     "values": [
+      "context-value",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "stroke-dashoffset": {
     "isInherited": true,
     "subproperties": [
       "stroke-dashoffset"
     ],
     "supports": [
       6,
       7,
       8
     ],
     "values": [
+      "context-value",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "stroke-linecap": {
     "isInherited": true,
     "subproperties": [
@@ -8573,32 +8986,35 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "stroke-opacity"
     ],
     "supports": [
       7
     ],
     "values": [
+      "context-fill-opacity",
+      "context-stroke-opacity",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "stroke-width": {
     "isInherited": true,
     "subproperties": [
       "stroke-width"
     ],
     "supports": [
       6,
       7,
       8
     ],
     "values": [
+      "context-value",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "table-layout": {
     "isInherited": false,
     "subproperties": [
@@ -8670,46 +9086,55 @@ exports.CSS_PROPERTIES = {
   },
   "text-combine-upright": {
     "isInherited": true,
     "subproperties": [
       "text-combine-upright"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "all",
+      "digits",
+      "inherit",
+      "initial",
+      "none",
       "unset"
     ]
   },
   "text-decoration": {
     "isInherited": false,
     "subproperties": [
       "text-decoration-color",
       "text-decoration-line",
       "text-decoration-style"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
+      "-moz-anchor-decoration",
       "-moz-none",
+      "blink",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "hsl",
       "hsla",
       "inherit",
       "initial",
+      "line-through",
+      "none",
+      "overline",
       "rgb",
       "rgba",
       "solid",
       "transparent",
+      "underline",
       "unset",
       "wavy"
     ]
   },
   "text-decoration-color": {
     "isInherited": false,
     "subproperties": [
       "text-decoration-color"
@@ -8732,18 +9157,24 @@ exports.CSS_PROPERTIES = {
   },
   "text-decoration-line": {
     "isInherited": false,
     "subproperties": [
       "text-decoration-line"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "-moz-anchor-decoration",
+      "blink",
+      "inherit",
+      "initial",
+      "line-through",
+      "none",
+      "overline",
+      "underline",
       "unset"
     ]
   },
   "text-decoration-style": {
     "isInherited": false,
     "subproperties": [
       "text-decoration-style"
     ],
@@ -8807,16 +9238,20 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "text-emphasis-position"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "left",
+      "over",
+      "right",
+      "under",
       "unset"
     ]
   },
   "text-emphasis-style": {
     "isInherited": true,
     "subproperties": [
       "text-emphasis-style"
     ],
@@ -8878,16 +9313,18 @@ exports.CSS_PROPERTIES = {
   },
   "text-overflow": {
     "isInherited": false,
     "subproperties": [
       "text-overflow"
     ],
     "supports": [],
     "values": [
+      "clip",
+      "ellipsis",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "text-rendering": {
     "isInherited": true,
     "subproperties": [
@@ -9002,18 +9439,23 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "transform-origin"
     ],
     "supports": [
       6,
       8
     ],
     "values": [
-      "inherit",
-      "initial",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "right",
+      "top",
       "unset"
     ]
   },
   "transform-style": {
     "isInherited": false,
     "subproperties": [
       "transform-style"
     ],
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -88,22 +88,16 @@ public:
   virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
 
   // Ensure that it's valid to access the DocGroup at this time.
   void ValidateAccess() const
   {
     mTabGroup->ValidateAccess();
   }
 
-  // Like ValidateAccess, but it returns a bool rather than asserting.
-  bool AccessAllowed() const
-  {
-    return mTabGroup->AccessAllowed();
-  }
-
   // Return a pointer that can be continually checked to see if access to this
   // DocGroup is valid. This pointer should live at least as long as the
   // DocGroup.
   bool* GetValidAccessPtr();
 
 private:
   virtual AbstractThread*
   AbstractMainThreadForImpl(TaskCategory aCategory) override;
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1671,27 +1671,16 @@ Element::BindToTree(nsIDocument* aDocume
 
   if (MayHaveStyle() && !IsXULElement()) {
     // XXXbz if we already have a style attr parsed, this won't do
     // anything... need to fix that.
     // If MayHaveStyle() is true, we must be an nsStyledElement
     static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(false, false);
   }
 
-  if (aDocument) {
-    // If we're in a document now, let our mapped attrs know what their new
-    // sheet is.  This is safe to run for non-mapped-attribute elements too;
-    // it'll just do a small bit of unnecessary work.  But most elements in
-    // practice are mapped-attribute elements.
-    nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
-    if (sheet) {
-      mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
-    }
-  }
-
   // Call BindToTree on shadow root children.
   ShadowRoot* shadowRoot = GetShadowRoot();
   if (shadowRoot) {
     shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
     for (nsIContent* child = shadowRoot->GetFirstChild(); child;
          child = child->GetNextSibling()) {
       rv = child->BindToTree(nullptr, shadowRoot,
                              shadowRoot->GetBindingParent(),
@@ -2459,17 +2448,17 @@ Element::SetAttrAndNotify(int32_t aNames
     if (aName == nsGkAtoms::dir) {
       hadValidDir = HasValidDir() || IsHTMLElement(nsGkAtoms::bdi);
       hadDirAuto = HasDirAuto(); // already takes bdi into account
     }
 
     // XXXbz Perhaps we should push up the attribute mapping function
     // stuff to Element?
     if (!IsAttributeMapped(aName) ||
-        !SetMappedAttribute(aComposedDocument, aName, aParsedValue, &rv)) {
+        !SetMappedAttribute(aName, aParsedValue, &rv)) {
       rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
     }
   }
   else {
     RefPtr<mozilla::dom::NodeInfo> ni;
     ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
                                                    aNamespaceID,
                                                    nsIDOMNode::ATTRIBUTE_NODE);
@@ -2578,18 +2567,17 @@ Element::ParseAttribute(int32_t aNamespa
       return true;
     }
   }
 
   return false;
 }
 
 bool
-Element::SetMappedAttribute(nsIDocument* aDocument,
-                            nsIAtom* aName,
+Element::SetMappedAttribute(nsIAtom* aName,
                             nsAttrValue& aValue,
                             nsresult* aRetval)
 {
   *aRetval = NS_OK;
   return false;
 }
 
 EventListenerManager*
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1385,26 +1385,24 @@ protected:
 
   /**
    * Try to set the attribute as a mapped attribute, if applicable.  This will
    * only be called for attributes that are in the null namespace and only on
    * attributes that returned true when passed to IsAttributeMapped.  The
    * caller will not try to set the attr in any other way if this method
    * returns true (the value of aRetval does not matter for that purpose).
    *
-   * @param aDocument the current document of this node (an optimization)
    * @param aName the name of the attribute
    * @param aValue the nsAttrValue to set
    * @param [out] aRetval the nsresult status of the operation, if any.
    * @return true if the setting was attempted, false otherwise.
    */
-  virtual bool SetMappedAttribute(nsIDocument* aDocument,
-                                    nsIAtom* aName,
-                                    nsAttrValue& aValue,
-                                    nsresult* aRetval);
+  virtual bool SetMappedAttribute(nsIAtom* aName,
+                                  nsAttrValue& aValue,
+                                  nsresult* aRetval);
 
   /**
    * Hook that is called by Element::SetAttr to allow subclasses to
    * deal with attribute sets.  This will only be called after we verify that
    * we're actually doing an attr set and will be called before
    * AttributeWillChange and before ParseAttribute and hence before we've set
    * the new value.
    *
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -175,16 +175,17 @@
 #include "nsIURIWithPrincipal.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
 #include "nsIWindowMediator.h"
 #include "nsIWordBreaker.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsLWBrkCIID.h"
+#include "nsMappedAttributes.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsNodeInfoManager.h"
 #include "NullPrincipal.h"
 #include "nsParserCIID.h"
 #include "nsParserConstants.h"
 #include "nsPIDOMWindow.h"
 #include "nsPresContext.h"
@@ -1988,16 +1989,17 @@ nsContentUtils::Shutdown()
   delete sAltText;
   sAltText = nullptr;
   delete sModifierSeparator;
   sModifierSeparator = nullptr;
 
   NS_IF_RELEASE(sSameOriginChecker);
 
   HTMLInputElement::Shutdown();
+  nsMappedAttributes::Shutdown();
 }
 
 /**
  * Checks whether two nodes come from the same origin. aTrustedNode is
  * considered 'safe' in that a user can operate on it and that it isn't
  * a js-object that implements nsIDOMNode.
  * Never call this function with the first node provided by script, it
  * must always be known to be a 'real' node!
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1712,17 +1712,16 @@ nsMessageManagerScriptExecutor::InitChil
 
 
   JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
   NS_ENSURE_TRUE(global, false);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information.
   xpc::SetLocationForGlobal(global, aID);
-  xpc::SetDocGroupValidation(global);
 
   DidCreateGlobal();
   return true;
 }
 
 void
 nsMessageManagerScriptExecutor::MarkScopesForCC()
 {
--- a/dom/base/nsMappedAttributeElement.cpp
+++ b/dom/base/nsMappedAttributeElement.cpp
@@ -10,33 +10,37 @@
 nsresult
 nsMappedAttributeElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
 {
   mAttrsAndChildren.WalkMappedAttributeStyleRules(aRuleWalker);
   return NS_OK;
 }
 
 bool
-nsMappedAttributeElement::SetMappedAttribute(nsIDocument* aDocument,
-                                             nsIAtom* aName,
+nsMappedAttributeElement::SetMappedAttribute(nsIAtom* aName,
                                              nsAttrValue& aValue,
                                              nsresult* aRetval)
 {
-  NS_PRECONDITION(aDocument == GetComposedDoc(), "Unexpected document");
-  nsHTMLStyleSheet* sheet = aDocument ?
-    aDocument->GetAttributeStyleSheet() : nullptr;
-
+  nsHTMLStyleSheet* sheet = OwnerDoc()->GetAttributeStyleSheet();
   *aRetval = mAttrsAndChildren.SetAndTakeMappedAttr(aName, aValue,
                                                     this, sheet);
   return true;
 }
 
 nsMapRuleToAttributesFunc
 nsMappedAttributeElement::GetAttributeMappingFunction() const
 {
   return &MapNoAttributesInto;
 }
 
 void
 nsMappedAttributeElement::MapNoAttributesInto(const nsMappedAttributes* aAttributes,
                                               mozilla::GenericSpecifiedValues* aGenericData)
 {
 }
+
+void
+nsMappedAttributeElement::NodeInfoChanged(nsIDocument* aOldDoc)
+{
+  nsHTMLStyleSheet* sheet = OwnerDoc()->GetAttributeStyleSheet();
+  mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
+  nsMappedAttributeElementBase::NodeInfoChanged(aOldDoc);
+}
--- a/dom/base/nsMappedAttributeElement.h
+++ b/dom/base/nsMappedAttributeElement.h
@@ -35,15 +35,16 @@ protected:
 
 public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
 
   static void MapNoAttributesInto(const nsMappedAttributes* aAttributes, 
                                   mozilla::GenericSpecifiedValues* aGenericData);
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
-  virtual bool SetMappedAttribute(nsIDocument* aDocument,
-                                    nsIAtom* aName,
-                                    nsAttrValue& aValue,
-                                    nsresult* aRetval) override;
+  virtual bool SetMappedAttribute(nsIAtom* aName,
+                                  nsAttrValue& aValue,
+                                  nsresult* aRetval) override;
+
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 };
 
 #endif // NS_MAPPEDATTRIBUTEELEMENT_H_
--- a/dom/base/nsMappedAttributes.cpp
+++ b/dom/base/nsMappedAttributes.cpp
@@ -16,34 +16,56 @@
 #include "mozilla/GenericSpecifiedValues.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ServoDeclarationBlock.h"
 #include "mozilla/ServoSpecifiedValues.h"
 
 using namespace mozilla;
 
+bool
+nsMappedAttributes::sShuttingDown = false;
+nsTArray<void*>*
+nsMappedAttributes::sCachedMappedAttributeAllocations = nullptr;
+
+void
+nsMappedAttributes::Shutdown()
+{
+  sShuttingDown = true;
+  if (sCachedMappedAttributeAllocations) {
+    for (uint32_t i = 0; i < sCachedMappedAttributeAllocations->Length(); ++i) {
+      void* cachedValue = (*sCachedMappedAttributeAllocations)[i];
+      ::operator delete(cachedValue);
+    }
+  }
+
+  delete sCachedMappedAttributeAllocations;
+  sCachedMappedAttributeAllocations = nullptr;
+}
+
 nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet,
                                        nsMapRuleToAttributesFunc aMapRuleFunc)
   : mAttrCount(0),
     mSheet(aSheet),
     mRuleMapper(aMapRuleFunc),
     mServoStyle(nullptr)
 {
+  MOZ_ASSERT(mRefCnt == 0); // Ensure caching works as expected.
 }
 
 nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy)
   : mAttrCount(aCopy.mAttrCount),
     mSheet(aCopy.mSheet),
     mRuleMapper(aCopy.mRuleMapper),
     // This is only called by ::Clone, which is used to create independent
     // nsMappedAttributes objects which should not share a ServoDeclarationBlock
     mServoStyle(nullptr)
 {
   NS_ASSERTION(mBufferSize >= aCopy.mAttrCount, "can't fit attributes");
+  MOZ_ASSERT(mRefCnt == 0); // Ensure caching works as expected.
 
   uint32_t i;
   for (i = 0; i < mAttrCount; ++i) {
     new (&Attrs()[i]) InternalAttr(aCopy.Attrs()[i]);
   }
 }
 
 nsMappedAttributes::~nsMappedAttributes()
@@ -76,26 +98,67 @@ void* nsMappedAttributes::operator new(s
   // aSize will include the mAttrs buffer so subtract that.
   // We don't want to under-allocate, however, so do not subtract
   // if we have zero attributes. The zero attribute case only happens
   // for <body>'s mapped attributes
   if (aAttrCount != 0) {
     size -= sizeof(void*[1]);
   }
 
+  if (sCachedMappedAttributeAllocations) {
+    void* cached =
+      sCachedMappedAttributeAllocations->SafeElementAt(aAttrCount);
+    if (cached) {
+      (*sCachedMappedAttributeAllocations)[aAttrCount] = nullptr;
+      return cached;
+    }
+  }
+
   void* newAttrs = ::operator new(size);
 
 #ifdef DEBUG
   static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount;
 #endif
   return newAttrs;
 }
 
-NS_IMPL_ISUPPORTS(nsMappedAttributes,
-                  nsIStyleRule)
+void
+nsMappedAttributes::LastRelease()
+{
+  if (!sShuttingDown) {
+    if (!sCachedMappedAttributeAllocations) {
+      sCachedMappedAttributeAllocations = new nsTArray<void*>();
+    }
+
+    // Ensure the cache array is at least mAttrCount + 1 long and
+    // that each item is either null or pointing to a cached item.
+    // The size of the array is capped because mapped attributes are defined
+    // statically in element implementations.
+    sCachedMappedAttributeAllocations->SetCapacity(mAttrCount + 1);
+    for (uint32_t i = sCachedMappedAttributeAllocations->Length();
+         i < (uint32_t(mAttrCount) + 1); ++i) {
+      sCachedMappedAttributeAllocations->AppendElement(nullptr);
+    }
+
+    if (!(*sCachedMappedAttributeAllocations)[mAttrCount]) {
+      void* memoryToCache = this;
+      this->~nsMappedAttributes();
+      (*sCachedMappedAttributeAllocations)[mAttrCount] = memoryToCache;
+      return;
+    }
+  }
+
+  delete this;
+}
+
+NS_IMPL_ADDREF(nsMappedAttributes)
+NS_IMPL_RELEASE_WITH_DESTROY(nsMappedAttributes, LastRelease())
+
+NS_IMPL_QUERY_INTERFACE(nsMappedAttributes,
+                        nsIStyleRule)
 
 void
 nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
 {
   NS_PRECONDITION(aAttrName, "null name");
   uint32_t i;
   for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
     if (Attrs()[i].mName.Equals(aAttrName)) {
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -95,17 +95,21 @@ public:
   virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
                                              nsCSSValue* aValue) override;
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
+  static void Shutdown();
 private:
+
+  void LastRelease();
+
   nsMappedAttributes(const nsMappedAttributes& aCopy);
   ~nsMappedAttributes();
 
   struct InternalAttr
   {
     nsAttrName mName;
     nsAttrValue mValue;
   };
@@ -129,11 +133,17 @@ private:
   uint16_t mAttrCount;
 #ifdef DEBUG
   uint16_t mBufferSize;
 #endif
   nsHTMLStyleSheet* mSheet; //weak
   nsMapRuleToAttributesFunc mRuleMapper;
   RefPtr<RawServoDeclarationBlock> mServoStyle;
   void* mAttrs[1];
+
+  static bool sShuttingDown;
+
+  // We're caching some memory to avoid trashing the allocator.
+  // The memory stored at index N can hold N attribute values.
+  static nsTArray<void*>* sCachedMappedAttributeAllocations;
 };
 
 #endif /* nsMappedAttributes_h___ */
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -4,17 +4,16 @@ support-files =
   empty.html
   file_audioLoop.html
   file_audioLoopInIframe.html
   file_bug1011748_redirect.sjs
   file_bug1011748_OK.sjs
   file_bug1303838.html
   file_bug1303838_target.html
   file_bug1303838_with_iframe.html
-  file_docgroup_forbid.html
   file_messagemanager_unload.html
   file_pluginAudio.html
   file_use_counter_outer.html
   file_use_counter_svg_getElementById.svg
   file_use_counter_svg_currentScale.svg
   file_use_counter_svg_fill_pattern_definition.svg
   file_use_counter_svg_fill_pattern.svg
   file_use_counter_svg_fill_pattern_internal.svg
@@ -22,18 +21,16 @@ support-files =
   file_webaudioLoop.html
   plugin.js
 
 [browser_bug593387.js]
 [browser_bug902350.js]
 tags = mcb
 [browser_bug1011748.js]
 [browser_bug1058164.js]
-[browser_docgroup_forbid.js]
-skip-if = !e10s
 [browser_messagemanager_loadprocessscript.js]
 [browser_messagemanager_targetframeloader.js]
 [browser_messagemanager_unload.js]
 [browser_pagehide_on_tab_close.js]
 skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
 [browser_state_notifications.js]
 skip-if = true # Bug 1271028
 [browser_use_counters.js]
deleted file mode 100644
--- a/dom/base/test/browser_docgroup_forbid.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const url = "https://example.com/browser/dom/base/test/file_docgroup_forbid.html";
-
-function frameScript() {
-  let e = Services.ww.getWindowEnumerator();
-  let exception = false;
-  while (e.hasMoreElements()) {
-    try {
-      /*
-       * If this is a window we're not supposed to touch, we'll get an
-       * error very early here (during the QI).
-       */
-      var window = e.getNext().QueryInterface(Components.interfaces.nsIDOMWindow);
-      var doc = window.document;
-    } catch (e) {
-      if (/accessing object in wrong DocGroup/.test(e.toString())) {
-        exception = true;
-        break;
-      }
-      throw e;
-    }
-
-    /*
-     * Do some stuff that will trigger the DocGroup assertions if we
-     * didn't throw.
-     */
-
-    let elt = doc.createElement("div");
-    elt.innerHTML = "hello!";
-    doc.body.appendChild(elt);
-
-    let evt = new window.CustomEvent("foopy");
-    doc.dispatchEvent(evt);
-  }
-  sendAsyncMessage("DocGroupTest:Done", exception);
-}
-
-function promiseMessage(messageManager, message) {
-  return new Promise(resolve => {
-    let listener = (msg) => {
-      messageManager.removeMessageListener(message, listener);
-      resolve(msg);
-    };
-
-    messageManager.addMessageListener(message, listener);
-  })
-}
-
-add_task(function*() {
-  // This pref is normally disabled during tests, but we want to test
-  // it here, so we enable it.
-  yield new Promise(go => {
-    SpecialPowers.pushPrefEnv({set: [["extensions.throw_on_docgroup_mismatch.enabled", true]]}, go)
-  });
-
-  let url1 = url + "?tab=1";
-  let url2 = url + "?tab=2";
-
-  let browser1 = gBrowser.selectedBrowser;
-
-  let tab2 = gBrowser.addTab(url2, {sameProcessAsFrameLoader: browser1.frameLoader});
-  let browser2 = tab2.linkedBrowser;
-  yield BrowserTestUtils.browserLoaded(browser2, false, url2);
-
-  browser1.loadURI(url1);
-  yield BrowserTestUtils.browserLoaded(browser1, false, url1);
-
-  browser1.messageManager.loadFrameScript(`data:,(${frameScript})();`, false);
-
-  let exception = yield promiseMessage(browser1.messageManager, "DocGroupTest:Done");
-
-  ok(exception, "Touching two windows threw an exception (that's good!)");
-
-  gBrowser.removeTab(tab2);
-});
deleted file mode 100644
--- a/dom/base/test/file_docgroup_forbid.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-  <body>
-    <script>
-      document.addEventListener("foopy", function() { dump("ran event handler\n"); });
-    </script>
-  </body>
-</html>
--- a/dom/webidl/ServiceWorkerContainer.webidl
+++ b/dom/webidl/ServiceWorkerContainer.webidl
@@ -37,10 +37,9 @@ interface ServiceWorkerContainer : Event
 // Testing only.
 partial interface ServiceWorkerContainer {
   [Throws,Pref="dom.serviceWorkers.testing.enabled"]
   DOMString getScopeForUrl(DOMString url);
 };
 
 dictionary RegistrationOptions {
   USVString scope;
-  boolean useCache;
 };
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -202,19 +202,19 @@ ServiceWorkerContainer::Register(const n
     }
 
     aRv = CheckForSlashEscapedCharsInPath(scopeURI);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  bool useCache = aOptions.mUseCache.WasPassed() && aOptions.mUseCache.Value();
-  nsLoadFlags loadFlags = useCache ? nsIRequest::LOAD_NORMAL
-                                   : nsIRequest::VALIDATE_ALWAYS;
+  // This is a quick fix for temporarily turning off script loading setting when
+  // registering a service worker. This should be removed in Bug 1353636.
+  nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
 
   // The spec says that the "client" passed to Register() must be the global
   // where the ServiceWorkerContainer was retrieved from.
   aRv = swm->Register(GetOwner(), scopeURI, scriptURI, loadFlags,
                       getter_AddRefs(promise));
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
--- a/image/test/mochitest/mochitest.ini
+++ b/image/test/mochitest/mochitest.ini
@@ -126,16 +126,17 @@ skip-if = os == 'android'
 [test_bug1217571.html]
 [test_bullet_animation.html]
 skip-if = os == 'android'
 [test_changeOfSource.html]
 skip-if = os == 'android'
 [test_changeOfSource2.html]
 skip-if = os == 'android'
 [test_discardAnimatedImage.html]
+disabled = bug 1354499
 [test_drawDiscardedImage.html]
 [test_error_events.html]
 [test_image_crossorigin_data_url.html]
 [test_ImageContentLoaded.html]
 [test_has_transparency.html]
 skip-if = os == 'android'
 [test_net_failedtoprocess.html]
 skip-if = os == 'android'
--- a/image/test/mochitest/test_discardAnimatedImage.html
+++ b/image/test/mochitest/test_discardAnimatedImage.html
@@ -23,16 +23,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   </div>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 686905. **/
 SimpleTest.waitForExplicitFinish();
 
+var gFinished = false;
+
 var gNumDiscards = 0;
 
 window.onload = function() {
   // Enable discarding for the test.
   SpecialPowers.pushPrefEnv({
     'set':[['image.mem.discardable',true]]
   }, runTest);
 }
@@ -44,16 +46,18 @@ var gCountingFrameUpdates = false;
 // after discarding. (The last two images are finite looping so we don't expect
 // them to get incremented but it's possible if they don't finish their
 // animation before we discard them.)
 var gNumFrameUpdates = [0, 0, 0, 0];
 // The last snapshot of the image. Used to check that the image actually changes.
 var gLastSnapShot = [null, null, null, null];
 // Number of observed changes in the snapshot.
 var gNumSnapShotChanges = [0, 0, 0, 0];
+// If we've removed the observer.
+var gRemovedObserver = [false, false, false, false];
 
 // 2 would probably be a good enough test, we arbitrarily choose 4.
 var kNumFrameUpdatesToExpect = 4;
 
 function runTest() {
   var animatedDiscardable =
     SpecialPowers.getBoolPref('image.mem.animated.discardable');
   if (!animatedDiscardable) {
@@ -95,36 +99,44 @@ function step4() {
 
   // Draw the images to canvas to force them to be decoded again.
   for (var i = 0; i < gImgs.length; i++) {
     drawCanvas(document.getElementById(gImgs[i]));
   }
 }
 
 function checkIfFinished() {
+  if (gFinished) {
+    return;
+  }
+
   if ((gNumFrameUpdates[0] >= kNumFrameUpdatesToExpect) &&
       (gNumFrameUpdates[1] >= kNumFrameUpdatesToExpect) &&
       (gNumSnapShotChanges[0] >= kNumFrameUpdatesToExpect) &&
       (gNumSnapShotChanges[1] >= kNumFrameUpdatesToExpect)) {
     ok(true, "got expected frame updates");
+    gFinished = true;
     SimpleTest.finish();
   }
 }
 
 // arrayIndex is the index into the arrays gNumFrameUpdates and gNumDecodes
 // to increment when a frame update notification is received.
 function addCallbacks(anImage, arrayIndex) {
   var observer = new ImageDecoderObserverStub();
   observer.discard = function () {
     gNumDiscards++;
     ok(true, "got image discard");
     if (arrayIndex >= 2) {
       // The last two images are finite, so we don't expect any frame updates,
       // this image is done the test, so remove the observer.
-      imgLoadingContent.removeObserver(scriptedObserver);
+      if (!gRemovedObserver[arrayIndex]) {
+        gRemovedObserver[arrayIndex] = true;
+        imgLoadingContent.removeObserver(scriptedObserver);
+      }
     }
     if (gNumDiscards == gImgs.length) {
       step4();
     }
   };
   observer.frameUpdate = function () {
     if (!gCountingFrameUpdates) {
       return;
@@ -143,19 +155,26 @@ function addCallbacks(anImage, arrayInde
         if (snapshot.toDataURL() != gLastSnapShot[arrayIndex].toDataURL()) {
           gNumSnapShotChanges[arrayIndex]++;
         }
       }
       gLastSnapShot[arrayIndex] = snapshot;
 
       if (gNumFrameUpdates[arrayIndex] >= kNumFrameUpdatesToExpect &&
           gNumSnapShotChanges[arrayIndex] >= kNumFrameUpdatesToExpect) {
-        imgLoadingContent.removeObserver(scriptedObserver);
+        if (!gRemovedObserver[arrayIndex]) {
+          gRemovedObserver[arrayIndex] = true;
+          imgLoadingContent.removeObserver(scriptedObserver);
+        }
       }
-      ok(true, "got frame update");
+      if (!gFinished) {
+        // because we do this in a setTimeout we can have several in flight
+        // so don't call ok if we've already finished.
+        ok(true, "got frame update");
+      }
       checkIfFinished();
     }, 0);
   };
   observer = SpecialPowers.wrapCallbackObject(observer);
 
   var scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
                            .getService(SpecialPowers.Ci.imgITools)
                            .createScriptedObserver(observer);
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -12,16 +12,17 @@
 
 #include <stdint.h>
 
 #include "jstypes.h"
 
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Value.h"
+#include "js/Vector.h"
 
 struct JSRuntime;
 struct JSStructuredCloneReader;
 struct JSStructuredCloneWriter;
 
 // API for the HTML5 internal structured cloning algorithm.
 
 namespace JS {
@@ -183,29 +184,52 @@ struct JSStructuredCloneCallbacks {
 };
 
 enum OwnTransferablePolicy {
     OwnsTransferablesIfAny,
     IgnoreTransferablesIfAny,
     NoTransferables
 };
 
+namespace js
+{
+    class SharedArrayRawBuffer;
+
+    class SharedArrayRawBufferRefs
+    {
+      public:
+        SharedArrayRawBufferRefs() = default;
+        SharedArrayRawBufferRefs(SharedArrayRawBufferRefs&& other) = default;
+        SharedArrayRawBufferRefs& operator=(SharedArrayRawBufferRefs&& other);
+        ~SharedArrayRawBufferRefs();
+
+        MOZ_MUST_USE bool acquire(JSContext* cx, SharedArrayRawBuffer* rawbuf);
+        MOZ_MUST_USE bool acquireAll(JSContext* cx, const SharedArrayRawBufferRefs& that);
+        void takeOwnership(SharedArrayRawBufferRefs&&);
+        void releaseAll();
+
+      private:
+        js::Vector<js::SharedArrayRawBuffer*, 0, js::SystemAllocPolicy> refs_;
+    };
+}
+
 class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) :
     public mozilla::BufferList<js::SystemAllocPolicy>
 {
     typedef js::SystemAllocPolicy AllocPolicy;
     typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
 
     static const size_t kInitialSize = 0;
     static const size_t kInitialCapacity = 4096;
     static const size_t kStandardCapacity = 4096;
 
     const JSStructuredCloneCallbacks* callbacks_;
     void* closure_;
     OwnTransferablePolicy ownTransferables_;
+    js::SharedArrayRawBufferRefs refsHeld_;
 
     void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
                               void* closure,
                               OwnTransferablePolicy policy) {
         callbacks_ = callbacks;
         closure_ = closure;
         ownTransferables_ = policy;
     }
@@ -274,17 +298,18 @@ class JS_PUBLIC_API(JSAutoStructuredClon
     ~JSAutoStructuredCloneBuffer() { clear(); }
 
     JSStructuredCloneData& data() { return data_; }
     bool empty() const { return !data_.Size(); }
 
     void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
     /** Copy some memory. It will be automatically freed by the destructor. */
-    bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
+    bool copy(JSContext* cx, const JSStructuredCloneData& data,
+              uint32_t version=JS_STRUCTURED_CLONE_VERSION,
               const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
 
     /**
      * Adopt some memory. It will be automatically freed by the destructor.
      * data must have been allocated by the JS engine (e.g., extracted via
      * JSAutoStructuredCloneBuffer::steal).
      */
     void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -289,54 +289,69 @@ function TypedArrayEvery(callbackfn/*, t
         if (!testResult)
             return false;
     }
 
     // Step 10.
     return true;
 }
 
-// ES6 draft rev29 (2014/12/06) 22.2.3.8 %TypedArray%.prototype.fill(value [, start [, end ]])
+// ES2018 draft rev ad2d1c60c5dc42a806696d4b58b4dca42d1f7dd4
+// 22.2.3.8 %TypedArray%.prototype.fill ( value [ , start [ , end ] ] )
 function TypedArrayFill(value, start = 0, end = undefined) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, value, start, end,
                             "TypedArrayFill");
     }
 
-    GetAttachedArrayBuffer(this);
-
-    // Steps 1-2.
+    // Step 1.
     var O = this;
 
-    // Steps 3-5.
+    // Step 2.
+    var buffer = GetAttachedArrayBuffer(this);
+
+    // Step 3.
     var len = TypedArrayLength(O);
 
-    // Steps 6-7.
+    // Step 4.
+    value = ToNumber(value);
+
+    // Step 5.
     var relativeStart = ToInteger(start);
 
-    // Step 8.
+    // Step 6.
     var k = relativeStart < 0
             ? std_Math_max(len + relativeStart, 0)
             : std_Math_min(relativeStart, len);
 
-    // Steps 9-10.
+    // Step 7.
     var relativeEnd = end === undefined ? len : ToInteger(end);
 
-    // Step 11.
+    // Step 8.
     var final = relativeEnd < 0
                 ? std_Math_max(len + relativeEnd, 0)
                 : std_Math_min(relativeEnd, len);
 
-    // Step 12.
+    // Step 9.
+    if (buffer === null) {
+        // A typed array previously using inline storage may acquire a
+        // buffer, so we must check with the source.
+        buffer = ViewedArrayBufferIfReified(O);
+    }
+
+    if (IsDetachedBuffer(buffer))
+        ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+
+    // Step 10.
     for (; k < final; k++) {
         O[k] = value;
     }
 
-    // Step 13.
+    // Step 11.
     return O;
 }
 
 // ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
 // %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] )
 function TypedArrayFilter(callbackfn/*, thisArg*/) {
     // Step 1.
     var O = this;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -352,29 +352,34 @@ class BytecodeEmitter::EmitterScope : pu
         return nameCache_.acquire(bce->cx);
     }
 
     template <typename BindingIter>
     MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi) {
         if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
             bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
         {
-            return bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
+            bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
+            return false;
         }
         return true;
     }
 
     MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
         uint32_t hops;
         if (EmitterScope* emitterScope = enclosing(&bce))
             hops = emitterScope->environmentChainLength_;
         else
             hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
-        if (hops >= ENVCOORD_HOPS_LIMIT - 1)
-            return bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
+
+        if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
+            bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
+            return false;
+        }
+
         environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
         return true;
     }
 
     void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
         nextFrameSlot_ = bi.nextFrameSlot();
         if (nextFrameSlot_ > bce->maxFixedSlots)
             bce->maxFixedSlots = nextFrameSlot_;
@@ -2495,18 +2500,21 @@ LengthOfSetLine(unsigned line)
 }
 
 /* Updates line number notes, not column notes. */
 bool
 BytecodeEmitter::updateLineNumberNotes(uint32_t offset)
 {
     TokenStream* ts = &parser->tokenStream;
     bool onThisLine;
-    if (!ts->srcCoords.isOnThisLine(offset, currentLine(), &onThisLine))
-        return ts->reportError(JSMSG_OUT_OF_MEMORY);
+    if (!ts->srcCoords.isOnThisLine(offset, currentLine(), &onThisLine)) {
+        ts->reportError(JSMSG_OUT_OF_MEMORY);
+        return false;
+    }
+
     if (!onThisLine) {
         unsigned line = ts->srcCoords.lineNum(offset);
         unsigned delta = line - currentLine();
 
         /*
          * Encode any change in the current source line number by using
          * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
          * whichever consumes less space.
@@ -3557,27 +3565,30 @@ BytecodeEmitter::tellDebuggerAboutCompil
 }
 
 inline TokenStream&
 BytecodeEmitter::tokenStream()
 {
     return parser->tokenStream;
 }
 
-bool
+void
 BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
 {
     TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
 
     va_list args;
     va_start(args, errorNumber);
-    bool result = tokenStream().reportCompileErrorNumberVA(nullptr, pos.begin, JSREPORT_ERROR,
-                                                           errorNumber, args);
+
+    TokenStream& ts = tokenStream();
+    ErrorMetadata metadata;
+    if (ts.computeErrorMetadata(&metadata, pos.begin))
+        ts.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
-    return result;
 }
 
 bool
 BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
 {
     TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
 
     va_list args;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -386,17 +386,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
         return lastOpcodeIsJumpTarget() ? current->lastTarget.offset : offset();
     }
 
     void setFunctionBodyEndPos(TokenPos pos) {
         functionBodyEndPos = pos.end;
         functionBodyEndPosSet = true;
     }
 
-    bool reportError(ParseNode* pn, unsigned errorNumber, ...);
+    void reportError(ParseNode* pn, unsigned errorNumber, ...);
     bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
     bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
 
     // If pn contains a useful expression, return true with *answer set to true.
     // If pn contains a useless expression, return true with *answer set to
     // false. Return false on error.
     //
     // The caller should initialize *answer to false and invoke this function on
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -588,152 +588,172 @@ FunctionBox::initWithEnclosingScope(Scop
     computeInWith(enclosingScope);
 }
 
 void
 ParserBase::error(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_ERROR,
-                                               errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
+
+    ErrorMetadata metadata;
+    if (tokenStream.computeErrorMetadata(&metadata, pos().begin))
+        tokenStream.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
 }
 
 void
 ParserBase::errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        tokenStream.reportCompileErrorNumberVA(Move(notes), pos().begin, JSREPORT_ERROR,
-                                               errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
+
+    ErrorMetadata metadata;
+    if (tokenStream.computeErrorMetadata(&metadata, pos().begin))
+        tokenStream.compileError(Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
 }
 
 void
 ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
+
+    ErrorMetadata metadata;
+    if (tokenStream.computeErrorMetadata(&metadata, offset))
+        tokenStream.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
 }
 
 void
 ParserBase::errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset,
                              unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        tokenStream.reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_ERROR,
-                                               errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
+
+    ErrorMetadata metadata;
+    if (tokenStream.computeErrorMetadata(&metadata, offset))
+        tokenStream.compileError(Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
 }
 
 bool
 ParserBase::warning(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
+
+    ErrorMetadata metadata;
     bool result =
-        tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_WARNING,
-                                               errorNumber, args);
+        tokenStream.computeErrorMetadata(&metadata, pos().begin) &&
+        tokenStream.compileWarning(Move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);
+
     va_end(args);
     return result;
 }
 
 bool
 ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-    bool result =
-        tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING,
-                                               errorNumber, args);
+
+    ErrorMetadata metadata;
+    bool result = tokenStream.computeErrorMetadata(&metadata, offset);
+    if (result) {
+        result =
+            tokenStream.compileWarning(Move(metadata), nullptr, JSREPORT_WARNING, errorNumber,
+                                      args);
+    }
+
     va_end(args);
     return result;
 }
 
 bool
 ParserBase::extraWarning(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-    bool result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin,
-                                                              errorNumber, args);
+
+    bool result =
+        tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin, errorNumber, args);
+
     va_end(args);
     return result;
 }
 
 bool
 ParserBase::strictModeError(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
+
     bool res =
         tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(),
                                                   errorNumber, args);
+
     va_end(args);
     return res;
 }
 
 bool
 ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
+
     bool res =
         tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(),
                                                   errorNumber, args);
+
     va_end(args);
     return res;
 }
 
 bool
 ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
+
     bool result = false;
-    uint32_t offset = TokenStream::NoOffset;
     switch (kind) {
       case ParseError:
-        result = tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR,
-                                                        errorNumber, args);
+      case ParseWarning: {
+        ErrorMetadata metadata;
+        tokenStream.computeErrorMetadataNoOffset(&metadata);
+
+        if (kind == ParseError) {
+            tokenStream.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+            MOZ_ASSERT(!result);
+        } else {
+            result =
+                tokenStream.compileWarning(Move(metadata), nullptr, JSREPORT_WARNING, errorNumber,
+                                           args);
+        }
+
         break;
-      case ParseWarning:
-        result =
-            tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING,
-                                                   errorNumber, args);
-        break;
+      }
       case ParseExtraWarning:
-        result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset,
+        result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, TokenStream::NoOffset,
                                                              errorNumber, args);
         break;
       case ParseStrictError:
-        result = tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, strict,
+        result = tokenStream.reportStrictModeErrorNumberVA(nullptr, TokenStream::NoOffset, strict,
                                                            errorNumber, args);
         break;
     }
+
     va_end(args);
     return result;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::abortIfSyntaxParser()
 {
@@ -3628,24 +3648,25 @@ Parser<ParseHandler>::functionFormalPara
 
     // Parse the function body.
     FunctionBodyType bodyType = StatementListBody;
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return false;
     uint32_t openedPos = 0;
     if (tt != TOK_LC) {
-        if (funbox->isStarGenerator() || kind == Method ||
-            kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
-            IsConstructorKind(kind)) {
-            error(JSMSG_CURLY_BEFORE_BODY);
-            return false;
-        }
-
         if (kind != Arrow) {
+            if (funbox->isStarGenerator() || funbox->isAsync() || kind == Method ||
+                kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
+                IsConstructorKind(kind))
+            {
+                error(JSMSG_CURLY_BEFORE_BODY);
+                return false;
+            }
+
 #if JS_HAS_EXPR_CLOSURES
             addTelemetry(JSCompartment::DeprecatedExpressionClosure);
             if (!warnOnceAboutExprClosure())
                 return false;
 #else
             error(JSMSG_CURLY_BEFORE_BODY);
             return false;
 #endif
@@ -7095,18 +7116,17 @@ Parser<ParseHandler>::classDefinition(Yi
 
         PropertyType propType;
         Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
         if (!propName)
             return null();
 
         if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
             propType != PropertyType::Method && propType != PropertyType::GeneratorMethod &&
-            propType != PropertyType::AsyncMethod &&
-            propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor)
+            propType != PropertyType::AsyncMethod)
         {
             errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
             return null();
         }
 
         if (propType == PropertyType::Getter)
             propType = PropertyType::GetterNoExpressionClosure;
         if (propType == PropertyType::Setter)
@@ -7219,16 +7239,21 @@ Parser<ParseHandler>::nextTokenContinues
     // legacy generator syntax, but that's dead now.)  If YieldIsName,
     // declaration-parsing code will (if necessary) enforce a strict mode
     // restriction on defining "yield".  If YieldIsKeyword, consider this the
     // end of the declaration, in case ASI induces a semicolon that makes the
     // "yield" valid.
     if (next == TOK_YIELD)
         return yieldHandling == YieldIsName;
 
+    // Somewhat similar logic applies for "await", except that it's not tracked
+    // with an AwaitHandling argument.
+    if (next == TOK_AWAIT)
+        return !awaitIsKeyword();
+
     // Otherwise a let declaration must have a name.
     if (TokenKindIsPossibleIdentifier(next)) {
         // A "let" edge case deserves special comment.  Consider this:
         //
         //   let     // not an ASI opportunity
         //   let;
         //
         // Static semantics in ยง13.3.1.1 turn a LexicalDeclaration that binds
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -449,17 +449,17 @@ class FunctionBox : public ObjectBox, pu
     uint32_t        bufStart;
     uint32_t        bufEnd;
     uint32_t        startLine;
     uint32_t        startColumn;
     uint32_t        preludeStart;
     uint16_t        length;
 
     uint8_t         generatorKindBits_;     /* The GeneratorKind of this function. */
-    uint8_t         asyncKindBits_;         /* The FunctionAsyncKing of this function. */
+    uint8_t         asyncKindBits_;         /* The FunctionAsyncKind of this function. */
 
     bool            isGenexpLambda:1;       /* lambda from generator expression */
     bool            hasDestructuringArgs:1; /* parameter list contains destructuring expression */
     bool            hasParameterExprs:1;    /* parameter list contains expressions */
     bool            hasDirectEvalInParameterExpr:1; /* parameter list contains direct eval */
     bool            hasDuplicateParameters:1; /* parameter list contains duplicate names */
     bool            useAsm:1;               /* see useAsmOrInsideUseAsm */
     bool            insideUseAsm:1;         /* see useAsmOrInsideUseAsm */
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -234,17 +234,17 @@ frontend::ReservedWordToCharZ(PropertyNa
 #undef EMIT_CASE
       default:
         MOZ_ASSERT_UNREACHABLE("Not a reserved word PropertyName.");
     }
     return nullptr;
 }
 
 PropertyName*
-TokenStream::reservedWordToPropertyName(TokenKind tt) const
+TokenStreamBase::reservedWordToPropertyName(TokenKind tt) const
 {
     MOZ_ASSERT(tt != TOK_NAME);
     switch (tt) {
 #define EMIT_CASE(word, name, type) case type: return cx->names().name;
       FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE)
 #undef EMIT_CASE
       default:
         MOZ_ASSERT_UNREACHABLE("Not a reserved word TokenKind.");
@@ -401,36 +401,42 @@ TokenStream::SourceCoords::lineNumAndCol
     *columnIndex = offset - lineStartOffset;
 }
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
-TokenStream::TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
-                         const char16_t* base, size_t length, StrictModeGetter* smg)
+TokenStreamBase::TokenStreamBase(JSContext* cx, const ReadOnlyCompileOptions& options,
+                                 StrictModeGetter* smg)
   : srcCoords(cx, options.lineno),
     options_(options),
     tokens(),
     cursor(),
     lookahead(),
     lineno(options.lineno),
     flags(),
     linebase(0),
     prevLinebase(size_t(-1)),
-    userbuf(cx, base, length, options.column),
     filename(options.filename()),
     displayURL_(nullptr),
     sourceMapURL_(nullptr),
-    tokenbuf(cx),
     cx(cx),
     mutedErrors(options.mutedErrors()),
     strictModeGetter(smg)
 {
+}
+
+TokenStream::TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
+                         const char16_t* base, size_t length, StrictModeGetter* smg)
+  : TokenStreamBase(cx, options, smg),
+    userbuf(cx, base, length, options.column),
+    tokenbuf(cx)
+{
     // Nb: the following tables could be static, but initializing them here is
     // much easier.  Don't worry, the time to initialize them for each
     // TokenStream is trivial.  See bug 639420.
 
     // See Parser::assignExpr() for an explanation of isExprEnding[].
     memset(isExprEnding, 0, sizeof(isExprEnding));
     isExprEnding[TOK_COMMA] = 1;
     isExprEnding[TOK_SEMI]  = 1;
@@ -452,20 +458,16 @@ TokenStream::checkOptions()
     if (options().column >= mozilla::MaxValue<int32_t>::value / 2 + 1) {
         reportErrorNoOffset(JSMSG_BAD_COLUMN_NUMBER);
         return false;
     }
 
     return true;
 }
 
-TokenStream::~TokenStream()
-{
-}
-
 // Use the fastest available getc.
 #if defined(HAVE_GETC_UNLOCKED)
 # define fast_getc getc_unlocked
 #elif defined(HAVE__GETC_NOLOCK)
 # define fast_getc _getc_nolock
 #else
 # define fast_getc getc
 #endif
@@ -475,17 +477,17 @@ TokenStream::updateLineInfoForEOL()
 {
     prevLinebase = linebase;
     linebase = userbuf.offset();
     lineno++;
     return srcCoords.add(lineno, linebase);
 }
 
 MOZ_ALWAYS_INLINE void
-TokenStream::updateFlagsForEOL()
+TokenStreamBase::updateFlagsForEOL()
 {
     flags.isDirtyLine = false;
 }
 
 // This gets the next char, normalizing all EOL sequences to '\n' as it goes.
 bool
 TokenStream::getChar(int32_t* cp)
 {
@@ -671,26 +673,30 @@ TokenStream::seek(const Position& pos, c
     seek(pos);
     return true;
 }
 
 bool
 TokenStream::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
                                            bool strictMode, unsigned errorNumber, va_list args)
 {
-    // In strict mode code, this is an error, not merely a warning.
-    unsigned flags;
-    if (strictMode)
-        flags = JSREPORT_ERROR;
-    else if (options().extraWarningsOption)
-        flags = JSREPORT_WARNING | JSREPORT_STRICT;
-    else
+    if (!strictMode && !options().extraWarningsOption)
         return true;
 
-    return reportCompileErrorNumberVA(Move(notes), offset, flags, errorNumber, args);
+    ErrorMetadata metadata;
+    if (!computeErrorMetadata(&metadata, offset))
+        return false;
+
+    if (strictMode) {
+        compileError(Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
+        return false;
+    }
+
+    return compileWarning(Move(metadata), Move(notes), JSREPORT_WARNING | JSREPORT_STRICT,
+                          errorNumber, args);
 }
 
 void
 CompileError::throwError(JSContext* cx)
 {
     if (JSREPORT_IS_WARNING(flags)) {
         CallWarningReporter(cx, this);
         return;
@@ -705,214 +711,283 @@ CompileError::throwError(JSContext* cx)
     // reporter is to ignore a report with this flag for all but top-level
     // compilation errors.  The exception will remain pending, and so long
     // as the non-top-level "load", "eval", or "compile" native function
     // returns false, the top-level reporter will eventually receive the
     // uncaught exception report.
     ErrorToException(cx, this, nullptr, nullptr);
 }
 
+void
+TokenStream::computeErrorMetadataNoOffset(ErrorMetadata* err)
+{
+    err->filename = filename;
+    err->lineNumber = 0;
+    err->columnNumber = 0;
+
+    MOZ_ASSERT(err->lineOfContext == nullptr);
+}
+
 bool
-TokenStream::reportCompileErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
-                                        unsigned flags, unsigned errorNumber, va_list args)
+TokenStream::computeErrorMetadata(ErrorMetadata* err, uint32_t offset)
+{
+    if (offset == NoOffset) {
+        computeErrorMetadataNoOffset(err);
+        return true;
+    }
+
+    // If this TokenStream doesn't have location information, try to get it
+    // from the caller.
+    if (!filename && !cx->helperThread()) {
+        NonBuiltinFrameIter iter(cx,
+                                 FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK,
+                                 cx->compartment()->principals());
+        if (!iter.done() && iter.filename()) {
+            err->filename = iter.filename();
+            err->lineNumber = iter.computeLine(&err->columnNumber);
+
+            // We can't get a line of context if we're using the caller's
+            // location, so we're done.
+            return true;
+        }
+    }
+
+    // Otherwise this TokenStream's location information should be used.
+    err->filename = filename;
+    srcCoords.lineNumAndColumnIndex(offset,
+                                    &err->lineNumber, &err->columnNumber);
+
+    // Add a line of context from this TokenStream to help with debugging.
+    return computeLineOfContext(err, offset);
+}
+
+bool
+TokenStream::computeLineOfContext(ErrorMetadata* err, uint32_t offset)
 {
-    bool warning = JSREPORT_IS_WARNING(flags);
+    // This function presumes |err| is filled in *except* for line-of-context
+    // fields.  It exists to make |TokenStream::computeErrorMetadata|, above,
+    // more readable.
+
+    // We only have line-start information for the current line.  If the error
+    // is on a different line, we can't easily provide context.  (This means
+    // any error in a multi-line token, e.g. an unterminated multiline string
+    // literal, won't have context.)
+    if (err->lineNumber != lineno)
+        return true;
+
+    // We show only a portion (a "window") of the line around the erroneous
+    // token -- the first char in the token, plus |windowRadius| chars before
+    // it and |windowRadius - 1| chars after it.  This is because for a very
+    // long line, printing the whole line is (a) not that helpful, and (b) can
+    // waste a lot of memory.  See bug 634444.
+    constexpr size_t windowRadius = 60;
+
+    // The window must start within the current line, no earlier than
+    // |windowRadius| characters before |offset|.
+    MOZ_ASSERT(offset >= linebase);
+    size_t windowStart = (offset - linebase > windowRadius) ?
+                         offset - windowRadius :
+                         linebase;
+
+    // The window must start within the portion of the current line that we
+    // actually have in our buffer.
+    if (windowStart < userbuf.startOffset())
+        windowStart = userbuf.startOffset();
+
+    // The window must end within the current line, no later than
+    // windowRadius after offset.
+    size_t windowEnd = userbuf.findEOLMax(offset, windowRadius);
+    size_t windowLength = windowEnd - windowStart;
+    MOZ_ASSERT(windowLength <= windowRadius * 2);
+
+    // Create the windowed string, not including the potential line
+    // terminator.
+    StringBuffer windowBuf(cx);
+    if (!windowBuf.append(userbuf.rawCharPtrAt(windowStart), windowLength) ||
+        !windowBuf.append('\0'))
+    {
+        return false;
+    }
 
-    if (warning && options().werrorOption) {
+    err->lineOfContext.reset(windowBuf.stealChars());
+    if (!err->lineOfContext)
+        return false;
+
+    err->lineLength = windowLength;
+    err->tokenOffset = offset - windowStart;
+    return true;
+}
+
+void
+TokenStream::compileError(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, unsigned flags,
+                          unsigned errorNumber, va_list args)
+{
+    // On the active thread, report the error immediately. When compiling off
+    // thread, save the error so that the thread finishing the parse can report
+    // it later.
+    CompileError tempErr;
+    CompileError* err = &tempErr;
+    if (cx->helperThread() && !cx->addPendingCompileError(&err))
+        return;
+
+    err->notes = Move(notes);
+    err->flags = flags;
+    err->errorNumber = errorNumber;
+    err->isMuted = mutedErrors;
+
+    err->filename = metadata.filename;
+    err->lineno = metadata.lineNumber;
+    err->column = metadata.columnNumber;
+
+    if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext))
+        err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset);
+
+    if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber,
+                                nullptr, ArgumentsAreLatin1, err, args))
+    {
+        return;
+    }
+
+    if (!cx->helperThread())
+        err->throwError(cx);
+}
+
+bool
+TokenStream::compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
+                            unsigned flags, unsigned errorNumber, va_list args)
+{
+    if (options().werrorOption) {
         flags &= ~JSREPORT_WARNING;
-        warning = false;
+        compileError(Move(metadata), Move(notes), flags, errorNumber, args);
+        return false;
     }
 
     // On the active thread, report the error immediately. When compiling off
     // thread, save the error so that the thread finishing the parse can report
     // it later.
     CompileError tempErr;
-    CompileError* tempErrPtr = &tempErr;
-    if (cx->helperThread() && !cx->addPendingCompileError(&tempErrPtr))
+    CompileError* err = &tempErr;
+    if (cx->helperThread() && !cx->addPendingCompileError(&err))
         return false;
-    CompileError& err = *tempErrPtr;
 
-    err.notes = Move(notes);
-    err.flags = flags;
-    err.errorNumber = errorNumber;
-    err.filename = filename;
-    err.isMuted = mutedErrors;
-    if (offset == NoOffset) {
-        err.lineno = 0;
-        err.column = 0;
-    } else {
-        err.lineno = srcCoords.lineNum(offset);
-        err.column = srcCoords.columnIndex(offset);
-    }
+    err->notes = Move(notes);
+    err->flags = flags;
+    err->errorNumber = errorNumber;
+    err->isMuted = mutedErrors;
 
-    // If we have no location information, try to get one from the caller.
-    bool callerFilename = false;
-    if (offset != NoOffset && !err.filename && !cx->helperThread()) {
-        NonBuiltinFrameIter iter(cx,
-                                 FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK,
-                                 cx->compartment()->principals());
-        if (!iter.done() && iter.filename()) {
-            callerFilename = true;
-            err.filename = iter.filename();
-            err.lineno = iter.computeLine(&err.column);
-        }
-    }
+    err->filename = metadata.filename;
+    err->lineno = metadata.lineNumber;
+    err->column = metadata.columnNumber;
+
+    if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext))
+        err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset);
 
     if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber,
-                                nullptr, ArgumentsAreLatin1, &err, args))
+                                nullptr, ArgumentsAreLatin1, err, args))
     {
         return false;
     }
 
-    // Given a token, T, that we want to complain about: if T's (starting)
-    // lineno doesn't match TokenStream's lineno, that means we've scanned past
-    // the line that T starts on, which makes it hard to print some or all of
-    // T's (starting) line for context.
-    //
-    // So we don't even try, leaving report.linebuf and friends zeroed.  This
-    // means that any error involving a multi-line token (e.g. an unterminated
-    // multi-line string literal) won't have a context printed.
-    if (offset != NoOffset && err.lineno == lineno && !callerFilename) {
-        // We show only a portion (a "window") of the line around the erroneous
-        // token -- the first char in the token, plus |windowRadius| chars
-        // before it and |windowRadius - 1| chars after it.  This is because
-        // lines can be very long and printing the whole line is (a) not that
-        // helpful, and (b) can waste a lot of memory.  See bug 634444.
-        static const size_t windowRadius = 60;
-
-        // The window must start within the current line, no earlier than
-        // windowRadius characters before offset.
-        size_t windowStart = (offset - linebase > windowRadius) ?
-                             offset - windowRadius :
-                             linebase;
-
-        // The window must start within the portion of the current line
-        // that we actually have in our buffer.
-        if (windowStart < userbuf.startOffset())
-            windowStart = userbuf.startOffset();
+    if (!cx->helperThread())
+        err->throwError(cx);
 
-        // The window must end within the current line, no later than
-        // windowRadius after offset.
-        size_t windowEnd = userbuf.findEOLMax(offset, windowRadius);
-        size_t windowLength = windowEnd - windowStart;
-        MOZ_ASSERT(windowLength <= windowRadius * 2);
-
-        // Create the windowed strings.
-        StringBuffer windowBuf(cx);
-        if (!windowBuf.append(userbuf.rawCharPtrAt(windowStart), windowLength) ||
-            !windowBuf.append('\0'))
-        {
-            return false;
-        }
-
-        // The window into the offending source line, without final \n.
-        UniqueTwoByteChars linebuf(windowBuf.stealChars());
-        if (!linebuf)
-            return false;
-
-        err.initOwnedLinebuf(linebuf.release(), windowLength, offset - windowStart);
-    }
-
-    if (!cx->helperThread())
-        err.throwError(cx);
-
-    return warning;
+    return true;
 }
 
 bool
 TokenStream::reportStrictModeError(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
     bool result = reportStrictModeErrorNumberVA(nullptr, currentToken().pos.begin, strictMode(),
                                                 errorNumber, args);
     va_end(args);
     return result;
 }
 
-bool
+void
 TokenStream::reportError(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-    bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR,
-                                             errorNumber, args);
+
+    ErrorMetadata metadata;
+    if (computeErrorMetadata(&metadata, currentToken().pos.begin))
+        compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
-    return result;
 }
 
-bool
+void
 TokenStream::reportErrorNoOffset(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-    bool result = reportCompileErrorNumberVA(nullptr, NoOffset, JSREPORT_ERROR,
-                                             errorNumber, args);
+
+    ErrorMetadata metadata;
+    computeErrorMetadataNoOffset(&metadata);
+
+    compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
-    return result;
 }
 
 bool
 TokenStream::warning(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-    bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_WARNING,
-                                             errorNumber, args);
+
+    ErrorMetadata metadata;
+    bool result =
+        computeErrorMetadata(&metadata, currentToken().pos.begin) &&
+        compileWarning(Move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);
+
     va_end(args);
     return result;
 }
 
 bool
 TokenStream::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
                                              unsigned errorNumber, va_list args)
 {
     if (!options().extraWarningsOption)
         return true;
 
-    return reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_STRICT|JSREPORT_WARNING,
-                                      errorNumber, args);
-}
+    ErrorMetadata metadata;
+    if (!computeErrorMetadata(&metadata, offset))
+        return false;
 
-void
-TokenStream::reportAsmJSError(uint32_t offset, unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    unsigned flags = options().throwOnAsmJSValidationFailureOption
-                     ? JSREPORT_ERROR
-                     : JSREPORT_WARNING;
-    reportCompileErrorNumberVA(nullptr, offset, flags, errorNumber, args);
-    va_end(args);
+    return compileWarning(Move(metadata), Move(notes), JSREPORT_STRICT | JSREPORT_WARNING,
+                          errorNumber, args);
 }
 
 void
 TokenStream::error(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR,
-                                   errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
+
+    ErrorMetadata metadata;
+    if (computeErrorMetadata(&metadata, currentToken().pos.begin))
+        compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
 }
 
 void
 TokenStream::errorAt(uint32_t offset, unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
+
+    ErrorMetadata metadata;
+    if (computeErrorMetadata(&metadata, offset))
+        compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+
     va_end(args);
 }
 
 // We have encountered a '\': check for a Unicode escape sequence after it.
 // Return the length of the escape sequence and the character code point (by
 // value) if we found a Unicode escape sequence.  Otherwise, return 0.  In both
 // cases, do not advance along the buffer.
 uint32_t
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -9,16 +9,17 @@
 
 // JS lexical scanner interface.
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/PodOperations.h"
+#include "mozilla/Unused.h"
 
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 
 #include "jscntxt.h"
 #include "jspubtd.h"
 
@@ -88,17 +89,17 @@ enum class InvalidEscapeType {
     Unicode,
     // An otherwise well-formed \u escape which represents a
     // codepoint > 10FFFF.
     UnicodeOverflow,
     // An octal escape in a template token.
     Octal
 };
 
-class TokenStream;
+class TokenStreamBase;
 
 struct Token
 {
   private:
     // Sometimes the parser needs to inform the tokenizer to interpret
     // subsequent text in a particular manner: for example, to tokenize a
     // keyword as an identifier, not as the actual keyword, on the right-hand
     // side of a dotted property access.  Such information is communicated to
@@ -156,17 +157,17 @@ struct Token
         // operand before try getting colon/comma/semicolon.
         // See also the comment in Parser::assignExpr().
         NoneIsOperand,
 
         // If a semicolon is inserted automatically, the next token is already
         // gotten with None, but we expect Operand.
         OperandIsNone,
     };
-    friend class TokenStream;
+    friend class TokenStreamBase;
 
   public:
     TokenKind           type;           // char value or above enumerator
     TokenPos            pos;            // token position in file
     union {
       private:
         friend struct Token;
         PropertyName*   name;          // non-numeric atom
@@ -264,91 +265,76 @@ IsStrictReservedWord(JSLinearString* str
 // This class is a tiny back-channel from TokenStream to the strict mode flag
 // that avoids exposing the rest of SharedContext to TokenStream.
 //
 class StrictModeGetter {
   public:
     virtual bool strictMode() = 0;
 };
 
-// TokenStream is the lexical scanner for Javascript source text.
-//
-// It takes a buffer of char16_t characters and linearly scans it into |Token|s.
-// Internally the class uses a four element circular buffer |tokens| of
-// |Token|s. As an index for |tokens|, the member |cursor| points to the
-// current token.
-// Calls to getToken() increase |cursor| by one and return the new current
-// token. If a TokenStream was just created, the current token is initialized
-// with random data (i.e. not initialized). It is therefore important that
-// one of the first four member functions listed below is called first.
-// The circular buffer lets us go back up to two tokens from the last
-// scanned token. Internally, the relative number of backward steps that were
-// taken (via ungetToken()) after the last token was scanned is stored in
-// |lookahead|.
-//
-// The following table lists in which situations it is safe to call each listed
-// function. No checks are made by the functions in non-debug builds.
-//
-// Function Name     | Precondition; changes to |lookahead|
-// ------------------+---------------------------------------------------------
-// getToken          | none; if |lookahead > 0| then |lookahead--|
-// peekToken         | none; if |lookahead == 0| then |lookahead == 1|
-// peekTokenSameLine | none; if |lookahead == 0| then |lookahead == 1|
-// matchToken        | none; if |lookahead > 0| and the match succeeds then
-//                   |       |lookahead--|
-// consumeKnownToken | none; if |lookahead > 0| then |lookahead--|
-// ungetToken        | 0 <= |lookahead| <= |maxLookahead - 1|; |lookahead++|
-//
-// The behavior of the token scanning process (see getTokenInternal()) can be
-// modified by calling one of the first four above listed member functions with
-// an optional argument of type Modifier.  However, the modifier will be
-// ignored unless |lookahead == 0| holds.  Due to constraints of the grammar,
-// this turns out not to be a problem in practice. See the
-// mozilla.dev.tech.js-engine.internals thread entitled 'Bug in the scanner?'
-// for more details:
-// https://groups.google.com/forum/?fromgroups=#!topic/mozilla.dev.tech.js-engine.internals/2JLH5jRcr7E).
-//
-// The methods seek() and tell() allow to rescan from a previous visited
-// location of the buffer.
-//
-class MOZ_STACK_CLASS TokenStream
+/**
+ * Metadata for a compilation error (or warning) at a particular offset, or at
+ * no offset (i.e. with respect to a script overall).
+ */
+struct ErrorMetadata
 {
+    // The file/URL where the error occurred.
+    const char* filename;
+
+    // The line and column numbers where the error occurred.  If the error
+    // is with respect to the entire script and not with respect to a
+    // particular location, these will both be zero.
+    uint32_t lineNumber;
+    uint32_t columnNumber;
+
+    // If the error occurs at a particular location, context surrounding the
+    // location of the error: the line that contained the error, or a small
+    // portion of it if the line is long.
+    //
+    // This information is provided on a best-effort basis: code populating
+    // ErrorMetadata instances isn't obligated to supply this.
+    UniqueTwoByteChars lineOfContext;
+
+    // If |lineOfContext| is non-null, its length.
+    size_t lineLength;
+
+    // If |lineOfContext| is non-null, the offset within it of the token that
+    // triggered the error.
+    size_t tokenOffset;
+};
+
+class TokenStreamBase
+{
+  protected:
+    TokenStreamBase(JSContext* cx, const ReadOnlyCompileOptions& options, StrictModeGetter* smg);
+
     // Unicode separators that are treated as line terminators, in addition to \n, \r.
     enum {
         LINE_SEPARATOR = 0x2028,
         PARA_SEPARATOR = 0x2029
     };
 
     static const size_t ntokens = 4;                // 1 current + 2 lookahead, rounded
                                                     // to power of 2 to avoid divmod by 3
     static const unsigned maxLookahead = 2;
     static const unsigned ntokensMask = ntokens - 1;
 
   public:
-    typedef Vector<char16_t, 32> CharBuffer;
-
-    TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
-                const char16_t* base, size_t length, StrictModeGetter* smg);
-
-    ~TokenStream();
-
-    MOZ_MUST_USE bool checkOptions();
-
     // Accessors.
     const Token& currentToken() const { return tokens[cursor]; }
     bool isCurrentTokenType(TokenKind type) const {
         return currentToken().type == type;
     }
-    const CharBuffer& getTokenbuf() const { return tokenbuf; }
+
     const char* getFilename() const { return filename; }
     bool getMutedErrors() const { return mutedErrors; }
     JSVersion versionNumber() const { return VersionNumber(options().version); }
     JSVersion versionWithFlags() const { return options().version; }
 
-  private:
+  protected:
     PropertyName* reservedWordToPropertyName(TokenKind tt) const;
 
   public:
     PropertyName* currentName() const {
         if (isCurrentTokenType(TOK_NAME))
             return currentToken().name();
 
         MOZ_ASSERT(TokenKindIsPossibleIdentifierName(currentToken().type));
@@ -375,134 +361,48 @@ class MOZ_STACK_CLASS TokenStream
 
     bool hasInvalidTemplateEscape() const {
         return invalidTemplateEscapeType != InvalidEscapeType::None;
     }
     void clearInvalidTemplateEscape() {
         invalidTemplateEscapeType = InvalidEscapeType::None;
     }
 
-    // If there is an invalid escape in a template, report it and return false,
-    // otherwise return true.
-    bool checkForInvalidTemplateEscapeError() {
-        if (invalidTemplateEscapeType == InvalidEscapeType::None)
-            return true;
-
-        reportInvalidEscapeError(invalidTemplateEscapeOffset, invalidTemplateEscapeType);
-        return false;
-    }
-
-    // TokenStream-specific error reporters.
-    bool reportError(unsigned errorNumber, ...);
-    bool reportErrorNoOffset(unsigned errorNumber, ...);
-
-    // Report the given error at the current offset.
-    void error(unsigned errorNumber, ...);
-
-    // Report the given error at the given offset.
-    void errorAt(uint32_t offset, unsigned errorNumber, ...);
-
-    // Warn at the current offset.
-    MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
-
     static const uint32_t NoOffset = UINT32_MAX;
 
-    // General-purpose error reporters.  You should avoid calling these
-    // directly, and instead use the more succinct alternatives (error(),
-    // warning(), &c.) in TokenStream, Parser, and BytecodeEmitter.
-    bool reportCompileErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, unsigned flags,
-                                    unsigned errorNumber, va_list args);
-    bool reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
-                                       bool strictMode, unsigned errorNumber, va_list args);
-    bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
-                                         unsigned errorNumber, va_list args);
-
-    // asm.js reporter
-    void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...);
-
-    JSAtom* getRawTemplateStringAtom() {
-        MOZ_ASSERT(currentToken().type == TOK_TEMPLATE_HEAD ||
-                   currentToken().type == TOK_NO_SUBS_TEMPLATE);
-        const char16_t* cur = userbuf.rawCharPtrAt(currentToken().pos.begin + 1);
-        const char16_t* end;
-        if (currentToken().type == TOK_TEMPLATE_HEAD) {
-            // Of the form    |`...${|   or   |}...${|
-            end = userbuf.rawCharPtrAt(currentToken().pos.end - 2);
-        } else {
-            // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
-            end = userbuf.rawCharPtrAt(currentToken().pos.end - 1);
-        }
-
-        CharBuffer charbuf(cx);
-        while (cur < end) {
-            int32_t ch = *cur;
-            if (ch == '\r') {
-                ch = '\n';
-                if ((cur + 1 < end) && (*(cur + 1) == '\n'))
-                    cur++;
-            }
-            if (!charbuf.append(ch))
-                return nullptr;
-            cur++;
-        }
-        return AtomizeChars(cx, charbuf.begin(), charbuf.length());
-    }
-
-  private:
-    // These are private because they should only be called by the tokenizer
+  protected:
+    // This is protected because it should only be called by the tokenizer
     // while tokenizing not by, for example, BytecodeEmitter.
-    bool reportStrictModeError(unsigned errorNumber, ...);
     bool strictMode() const { return strictModeGetter && strictModeGetter->strictMode(); }
 
     void setInvalidTemplateEscape(uint32_t offset, InvalidEscapeType type) {
         MOZ_ASSERT(type != InvalidEscapeType::None);
         if (invalidTemplateEscapeType != InvalidEscapeType::None)
             return;
         invalidTemplateEscapeOffset = offset;
         invalidTemplateEscapeType = type;
     }
-    void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) {
-        switch (type) {
-            case InvalidEscapeType::None:
-                MOZ_ASSERT_UNREACHABLE("unexpected InvalidEscapeType");
-                return;
-            case InvalidEscapeType::Hexadecimal:
-                errorAt(offset, JSMSG_MALFORMED_ESCAPE, "hexadecimal");
-                return;
-            case InvalidEscapeType::Unicode:
-                errorAt(offset, JSMSG_MALFORMED_ESCAPE, "Unicode");
-                return;
-            case InvalidEscapeType::UnicodeOverflow:
-                errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence");
-                return;
-            case InvalidEscapeType::Octal:
-                errorAt(offset, JSMSG_DEPRECATED_OCTAL);
-                return;
-        }
-    }
 
-    static JSAtom* atomize(JSContext* cx, CharBuffer& cb);
-    MOZ_MUST_USE bool putIdentInTokenbuf(const char16_t* identStart);
+    uint32_t invalidTemplateEscapeOffset = 0;
+    InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None;
 
+  protected:
     struct Flags
     {
         bool isEOF:1;           // Hit end of file.
         bool isDirtyLine:1;     // Non-whitespace since start of line.
         bool sawOctalEscape:1;  // Saw an octal character escape.
         bool hadError:1;        // Hit a syntax error, at start or during a
                                 // token.
 
         Flags()
           : isEOF(), isDirtyLine(), sawOctalEscape(), hadError()
         {}
     };
 
-    uint32_t invalidTemplateEscapeOffset = 0;
-    InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None;
-
   public:
     typedef Token::Modifier Modifier;
     static constexpr Modifier None = Token::None;
     static constexpr Modifier Operand = Token::Operand;
     static constexpr Modifier TemplateTail = Token::TemplateTail;
 
     typedef Token::ModifierException ModifierException;
     static constexpr ModifierException NoException = Token::NoException;
@@ -563,193 +463,22 @@ class MOZ_STACK_CLASS TokenStream
         }
 
         MOZ_ASSERT_UNREACHABLE("this token was previously looked up with a "
                                "different modifier, potentially making "
                                "tokenization non-deterministic");
 #endif
     }
 
-    // Advance to the next token.  If the token stream encountered an error,
-    // return false.  Otherwise return true and store the token kind in |*ttp|.
-    MOZ_MUST_USE bool getToken(TokenKind* ttp, Modifier modifier = None) {
-        // Check for a pushed-back token resulting from mismatching lookahead.
-        if (lookahead != 0) {
-            MOZ_ASSERT(!flags.hadError);
-            lookahead--;
-            cursor = (cursor + 1) & ntokensMask;
-            TokenKind tt = currentToken().type;
-            MOZ_ASSERT(tt != TOK_EOL);
-            verifyConsistentModifier(modifier, currentToken());
-            *ttp = tt;
-            return true;
-        }
-
-        return getTokenInternal(ttp, modifier);
-    }
-
-    // Push the last scanned token back into the stream.
-    void ungetToken() {
-        MOZ_ASSERT(lookahead < maxLookahead);
-        lookahead++;
-        cursor = (cursor - 1) & ntokensMask;
-    }
-
-    MOZ_MUST_USE bool peekToken(TokenKind* ttp, Modifier modifier = None) {
-        if (lookahead > 0) {
-            MOZ_ASSERT(!flags.hadError);
-            verifyConsistentModifier(modifier, nextToken());
-            *ttp = nextToken().type;
-            return true;
-        }
-        if (!getTokenInternal(ttp, modifier))
-            return false;
-        ungetToken();
-        return true;
-    }
-
-    MOZ_MUST_USE bool peekTokenPos(TokenPos* posp, Modifier modifier = None) {
-        if (lookahead == 0) {
-            TokenKind tt;
-            if (!getTokenInternal(&tt, modifier))
-                return false;
-            ungetToken();
-            MOZ_ASSERT(hasLookahead());
-        } else {
-            MOZ_ASSERT(!flags.hadError);
-            verifyConsistentModifier(modifier, nextToken());
-        }
-        *posp = nextToken().pos;
-        return true;
-    }
-
-    MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) {
-        TokenPos pos;
-        if (!peekTokenPos(&pos, modifier))
-            return false;
-        *offset = pos.begin;
-        return true;
-    }
-
-    // This is like peekToken(), with one exception:  if there is an EOL
-    // between the end of the current token and the start of the next token, it
-    // return true and store TOK_EOL in |*ttp|.  In that case, no token with
-    // TOK_EOL is actually created, just a TOK_EOL TokenKind is returned, and
-    // currentToken() shouldn't be consulted.  (This is the only place TOK_EOL
-    // is produced.)
-    MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
-    peekTokenSameLine(TokenKind* ttp, Modifier modifier = None) {
-        const Token& curr = currentToken();
-
-        // If lookahead != 0, we have scanned ahead at least one token, and
-        // |lineno| is the line that the furthest-scanned token ends on.  If
-        // it's the same as the line that the current token ends on, that's a
-        // stronger condition than what we are looking for, and we don't need
-        // to return TOK_EOL.
-        if (lookahead != 0) {
-            bool onThisLine;
-            if (!srcCoords.isOnThisLine(curr.pos.end, lineno, &onThisLine))
-                return reportError(JSMSG_OUT_OF_MEMORY);
-            if (onThisLine) {
-                MOZ_ASSERT(!flags.hadError);
-                verifyConsistentModifier(modifier, nextToken());
-                *ttp = nextToken().type;
-                return true;
-            }
-        }
-
-        // The above check misses two cases where we don't have to return
-        // TOK_EOL.
-        // - The next token starts on the same line, but is a multi-line token.
-        // - The next token starts on the same line, but lookahead==2 and there
-        //   is a newline between the next token and the one after that.
-        // The following test is somewhat expensive but gets these cases (and
-        // all others) right.
-        TokenKind tmp;
-        if (!getToken(&tmp, modifier))
-            return false;
-        const Token& next = currentToken();
-        ungetToken();
-
-        *ttp = srcCoords.lineNum(curr.pos.end) == srcCoords.lineNum(next.pos.begin)
-             ? next.type
-             : TOK_EOL;
-        return true;
-    }
-
-    // Get the next token from the stream if its kind is |tt|.
-    MOZ_MUST_USE bool matchToken(bool* matchedp, TokenKind tt, Modifier modifier = None) {
-        TokenKind token;
-        if (!getToken(&token, modifier))
-            return false;
-        if (token == tt) {
-            *matchedp = true;
-        } else {
-            ungetToken();
-            *matchedp = false;
-        }
-        return true;
-    }
-
-    void consumeKnownToken(TokenKind tt, Modifier modifier = None) {
-        bool matched;
-        MOZ_ASSERT(hasLookahead());
-        MOZ_ALWAYS_TRUE(matchToken(&matched, tt, modifier));
-        MOZ_ALWAYS_TRUE(matched);
-    }
-
-    MOZ_MUST_USE bool nextTokenEndsExpr(bool* endsExpr) {
-        TokenKind tt;
-        if (!peekToken(&tt))
-            return false;
-        *endsExpr = isExprEnding[tt];
-        return true;
-    }
-
-    class MOZ_STACK_CLASS Position {
-      public:
-        // The Token fields may contain pointers to atoms, so for correct
-        // rooting we must ensure collection of atoms is disabled while objects
-        // of this class are live.  Do this by requiring a dummy AutoKeepAtoms
-        // reference in the constructor.
-        //
-        // This class is explicity ignored by the analysis, so don't add any
-        // more pointers to GC things here!
-        explicit Position(AutoKeepAtoms&) { }
-      private:
-        Position(const Position&) = delete;
-        friend class TokenStream;
-        const char16_t* buf;
-        Flags flags;
-        unsigned lineno;
-        size_t linebase;
-        size_t prevLinebase;
-        Token currentToken;
-        unsigned lookahead;
-        Token lookaheadTokens[maxLookahead];
-    };
-
-    MOZ_MUST_USE bool advance(size_t position);
-    void tell(Position*);
-    void seek(const Position& pos);
-    MOZ_MUST_USE bool seek(const Position& pos, const TokenStream& other);
 #ifdef DEBUG
     inline bool debugHasNoLookahead() const {
         return lookahead == 0;
     }
 #endif
 
-    const char16_t* rawCharPtrAt(size_t offset) const {
-        return userbuf.rawCharPtrAt(offset);
-    }
-
-    const char16_t* rawLimit() const {
-        return userbuf.limit();
-    }
-
     bool hasDisplayURL() const {
         return displayURL_ != nullptr;
     }
 
     char16_t* displayURL() {
         return displayURL_.get();
     }
 
@@ -840,16 +569,379 @@ class MOZ_STACK_CLASS TokenStream
     JSContext* context() const {
         return cx;
     }
 
     const ReadOnlyCompileOptions& options() const {
         return options_;
     }
 
+    void updateFlagsForEOL();
+
+    const Token& nextToken() const {
+        MOZ_ASSERT(hasLookahead());
+        return tokens[(cursor + 1) & ntokensMask];
+    }
+
+    bool hasLookahead() const { return lookahead > 0; }
+
+  protected:
+    // Options used for parsing/tokenizing.
+    const ReadOnlyCompileOptions& options_;
+
+    Token               tokens[ntokens];    // circular token buffer
+    unsigned            cursor;             // index of last parsed token
+    unsigned            lookahead;          // count of lookahead tokens
+    unsigned            lineno;             // current line number
+    Flags               flags;              // flags -- see above
+    size_t              linebase;           // start of current line
+    size_t              prevLinebase;       // start of previous line;  size_t(-1) if on the first line
+    const char*         filename;           // input filename or null
+    UniqueTwoByteChars  displayURL_;        // the user's requested source URL or null
+    UniqueTwoByteChars  sourceMapURL_;      // source map's filename or null
+    uint8_t             isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
+    JSContext* const    cx;
+    bool                mutedErrors;
+    StrictModeGetter*   strictModeGetter;  // used to test for strict mode
+};
+
+// TokenStream is the lexical scanner for Javascript source text.
+//
+// It takes a buffer of char16_t characters and linearly scans it into |Token|s.
+// Internally the class uses a four element circular buffer |tokens| of
+// |Token|s. As an index for |tokens|, the member |cursor| points to the
+// current token.
+// Calls to getToken() increase |cursor| by one and return the new current
+// token. If a TokenStream was just created, the current token is initialized
+// with random data (i.e. not initialized). It is therefore important that
+// one of the first four member functions listed below is called first.
+// The circular buffer lets us go back up to two tokens from the last
+// scanned token. Internally, the relative number of backward steps that were
+// taken (via ungetToken()) after the last token was scanned is stored in
+// |lookahead|.
+//
+// The following table lists in which situations it is safe to call each listed
+// function. No checks are made by the functions in non-debug builds.
+//
+// Function Name     | Precondition; changes to |lookahead|
+// ------------------+---------------------------------------------------------
+// getToken          | none; if |lookahead > 0| then |lookahead--|
+// peekToken         | none; if |lookahead == 0| then |lookahead == 1|
+// peekTokenSameLine | none; if |lookahead == 0| then |lookahead == 1|
+// matchToken        | none; if |lookahead > 0| and the match succeeds then
+//                   |       |lookahead--|
+// consumeKnownToken | none; if |lookahead > 0| then |lookahead--|
+// ungetToken        | 0 <= |lookahead| <= |maxLookahead - 1|; |lookahead++|
+//
+// The behavior of the token scanning process (see getTokenInternal()) can be
+// modified by calling one of the first four above listed member functions with
+// an optional argument of type Modifier.  However, the modifier will be
+// ignored unless |lookahead == 0| holds.  Due to constraints of the grammar,
+// this turns out not to be a problem in practice. See the
+// mozilla.dev.tech.js-engine.internals thread entitled 'Bug in the scanner?'
+// for more details:
+// https://groups.google.com/forum/?fromgroups=#!topic/mozilla.dev.tech.js-engine.internals/2JLH5jRcr7E).
+//
+// The methods seek() and tell() allow to rescan from a previous visited
+// location of the buffer.
+//
+class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
+{
+  public:
+    using CharBuffer = Vector<char16_t, 32>;
+
+    TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
+                const char16_t* base, size_t length, StrictModeGetter* smg);
+
+    MOZ_MUST_USE bool checkOptions();
+
+    const CharBuffer& getTokenbuf() const { return tokenbuf; }
+
+    // If there is an invalid escape in a template, report it and return false,
+    // otherwise return true.
+    bool checkForInvalidTemplateEscapeError() {
+        if (invalidTemplateEscapeType == InvalidEscapeType::None)
+            return true;
+
+        reportInvalidEscapeError(invalidTemplateEscapeOffset, invalidTemplateEscapeType);
+        return false;
+    }
+
+    // TokenStream-specific error reporters.
+    void reportError(unsigned errorNumber, ...);
+    void reportErrorNoOffset(unsigned errorNumber, ...);
+
+    // Report the given error at the current offset.
+    void error(unsigned errorNumber, ...);
+
+    // Report the given error at the given offset.
+    void errorAt(uint32_t offset, unsigned errorNumber, ...);
+
+    // Warn at the current offset.
+    MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
+
+  private:
+    // Compute a line of context for an otherwise-filled-in |err| at the given
+    // offset in this token stream.  (This function basically exists to make
+    // |computeErrorMetadata| more readable and shouldn't be called elsewhere.)
+    MOZ_MUST_USE bool computeLineOfContext(ErrorMetadata* err, uint32_t offset);
+
+  public:
+    // Compute error metadata for an error at no offset.
+    void computeErrorMetadataNoOffset(ErrorMetadata* err);
+
+    // Compute error metadata for an error at the given offset.
+    MOZ_MUST_USE bool computeErrorMetadata(ErrorMetadata* err, uint32_t offset);
+
+    // General-purpose error reporters.  You should avoid calling these
+    // directly, and instead use the more succinct alternatives (error(),
+    // warning(), &c.) in TokenStream, Parser, and BytecodeEmitter.
+    void compileError(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, unsigned flags,
+                      unsigned errorNumber, va_list args);
+
+    MOZ_MUST_USE bool compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
+                                     unsigned flags, unsigned errorNumber, va_list args);
+
+    bool reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
+                                       bool strictMode, unsigned errorNumber, va_list args);
+    bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
+                                         unsigned errorNumber, va_list args);
+
+    JSAtom* getRawTemplateStringAtom() {
+        MOZ_ASSERT(currentToken().type == TOK_TEMPLATE_HEAD ||
+                   currentToken().type == TOK_NO_SUBS_TEMPLATE);
+        const char16_t* cur = userbuf.rawCharPtrAt(currentToken().pos.begin + 1);
+        const char16_t* end;
+        if (currentToken().type == TOK_TEMPLATE_HEAD) {
+            // Of the form    |`...${|   or   |}...${|
+            end = userbuf.rawCharPtrAt(currentToken().pos.end - 2);
+        } else {
+            // NO_SUBS_TEMPLATE is of the form   |`...`|   or   |}...`|
+            end = userbuf.rawCharPtrAt(currentToken().pos.end - 1);
+        }
+
+        CharBuffer charbuf(cx);
+        while (cur < end) {
+            int32_t ch = *cur;
+            if (ch == '\r') {
+                ch = '\n';
+                if ((cur + 1 < end) && (*(cur + 1) == '\n'))
+                    cur++;
+            }
+            if (!charbuf.append(ch))
+                return nullptr;
+            cur++;
+        }
+        return AtomizeChars(cx, charbuf.begin(), charbuf.length());
+    }
+
+  private:
+    // This is private because it should only be called by the tokenizer while
+    // tokenizing not by, for example, BytecodeEmitter.
+    bool reportStrictModeError(unsigned errorNumber, ...);
+
+    void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) {
+        switch (type) {
+            case InvalidEscapeType::None:
+                MOZ_ASSERT_UNREACHABLE("unexpected InvalidEscapeType");
+                return;
+            case InvalidEscapeType::Hexadecimal:
+                errorAt(offset, JSMSG_MALFORMED_ESCAPE, "hexadecimal");
+                return;
+            case InvalidEscapeType::Unicode:
+                errorAt(offset, JSMSG_MALFORMED_ESCAPE, "Unicode");
+                return;
+            case InvalidEscapeType::UnicodeOverflow:
+                errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence");
+                return;
+            case InvalidEscapeType::Octal:
+                errorAt(offset, JSMSG_DEPRECATED_OCTAL);
+                return;
+        }
+    }
+
+    static JSAtom* atomize(JSContext* cx, CharBuffer& cb);
+    MOZ_MUST_USE bool putIdentInTokenbuf(const char16_t* identStart);
+
+  public:
+    // Advance to the next token.  If the token stream encountered an error,
+    // return false.  Otherwise return true and store the token kind in |*ttp|.
+    MOZ_MUST_USE bool getToken(TokenKind* ttp, Modifier modifier = None) {
+        // Check for a pushed-back token resulting from mismatching lookahead.
+        if (lookahead != 0) {
+            MOZ_ASSERT(!flags.hadError);
+            lookahead--;
+            cursor = (cursor + 1) & ntokensMask;
+            TokenKind tt = currentToken().type;
+            MOZ_ASSERT(tt != TOK_EOL);
+            verifyConsistentModifier(modifier, currentToken());
+            *ttp = tt;
+            return true;
+        }
+
+        return getTokenInternal(ttp, modifier);
+    }
+
+    // Push the last scanned token back into the stream.
+    void ungetToken() {
+        MOZ_ASSERT(lookahead < maxLookahead);
+        lookahead++;
+        cursor = (cursor - 1) & ntokensMask;
+    }
+
+    MOZ_MUST_USE bool peekToken(TokenKind* ttp, Modifier modifier = None) {
+        if (lookahead > 0) {
+            MOZ_ASSERT(!flags.hadError);
+            verifyConsistentModifier(modifier, nextToken());
+            *ttp = nextToken().type;
+            return true;
+        }
+        if (!getTokenInternal(ttp, modifier))
+            return false;
+        ungetToken();
+        return true;
+    }
+
+    MOZ_MUST_USE bool peekTokenPos(TokenPos* posp, Modifier modifier = None) {
+        if (lookahead == 0) {
+            TokenKind tt;
+            if (!getTokenInternal(&tt, modifier))
+                return false;
+            ungetToken();
+            MOZ_ASSERT(hasLookahead());
+        } else {
+            MOZ_ASSERT(!flags.hadError);
+            verifyConsistentModifier(modifier, nextToken());
+        }
+        *posp = nextToken().pos;
+        return true;
+    }
+
+    MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) {
+        TokenPos pos;
+        if (!peekTokenPos(&pos, modifier))
+            return false;
+        *offset = pos.begin;
+        return true;
+    }
+
+    // This is like peekToken(), with one exception:  if there is an EOL
+    // between the end of the current token and the start of the next token, it
+    // return true and store TOK_EOL in |*ttp|.  In that case, no token with
+    // TOK_EOL is actually created, just a TOK_EOL TokenKind is returned, and
+    // currentToken() shouldn't be consulted.  (This is the only place TOK_EOL
+    // is produced.)
+    MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
+    peekTokenSameLine(TokenKind* ttp, Modifier modifier = None) {
+        const Token& curr = currentToken();
+
+        // If lookahead != 0, we have scanned ahead at least one token, and
+        // |lineno| is the line that the furthest-scanned token ends on.  If
+        // it's the same as the line that the current token ends on, that's a
+        // stronger condition than what we are looking for, and we don't need
+        // to return TOK_EOL.
+        if (lookahead != 0) {
+            bool onThisLine;
+            if (!srcCoords.isOnThisLine(curr.pos.end, lineno, &onThisLine)) {
+                reportError(JSMSG_OUT_OF_MEMORY);
+                return false;
+            }
+
+            if (onThisLine) {
+                MOZ_ASSERT(!flags.hadError);
+                verifyConsistentModifier(modifier, nextToken());
+                *ttp = nextToken().type;
+                return true;
+            }
+        }
+
+        // The above check misses two cases where we don't have to return
+        // TOK_EOL.
+        // - The next token starts on the same line, but is a multi-line token.
+        // - The next token starts on the same line, but lookahead==2 and there
+        //   is a newline between the next token and the one after that.
+        // The following test is somewhat expensive but gets these cases (and
+        // all others) right.
+        TokenKind tmp;
+        if (!getToken(&tmp, modifier))
+            return false;
+        const Token& next = currentToken();
+        ungetToken();
+
+        *ttp = srcCoords.lineNum(curr.pos.end) == srcCoords.lineNum(next.pos.begin)
+             ? next.type
+             : TOK_EOL;
+        return true;
+    }
+
+    // Get the next token from the stream if its kind is |tt|.
+    MOZ_MUST_USE bool matchToken(bool* matchedp, TokenKind tt, Modifier modifier = None) {
+        TokenKind token;
+        if (!getToken(&token, modifier))
+            return false;
+        if (token == tt) {
+            *matchedp = true;
+        } else {
+            ungetToken();
+            *matchedp = false;
+        }
+        return true;
+    }
+
+    void consumeKnownToken(TokenKind tt, Modifier modifier = None) {
+        bool matched;
+        MOZ_ASSERT(hasLookahead());
+        MOZ_ALWAYS_TRUE(matchToken(&matched, tt, modifier));
+        MOZ_ALWAYS_TRUE(matched);
+    }
+
+    MOZ_MUST_USE bool nextTokenEndsExpr(bool* endsExpr) {
+        TokenKind tt;
+        if (!peekToken(&tt))
+            return false;
+        *endsExpr = isExprEnding[tt];
+        return true;
+    }
+
+    class MOZ_STACK_CLASS Position {
+      public:
+        // The Token fields may contain pointers to atoms, so for correct
+        // rooting we must ensure collection of atoms is disabled while objects
+        // of this class are live.  Do this by requiring a dummy AutoKeepAtoms
+        // reference in the constructor.
+        //
+        // This class is explicity ignored by the analysis, so don't add any
+        // more pointers to GC things here!
+        explicit Position(AutoKeepAtoms&) { }
+      private:
+        Position(const Position&) = delete;
+        friend class TokenStream;
+        const char16_t* buf;
+        Flags flags;
+        unsigned lineno;
+        size_t linebase;
+        size_t prevLinebase;
+        Token currentToken;
+        unsigned lookahead;
+        Token lookaheadTokens[maxLookahead];
+    };
+
+    MOZ_MUST_USE bool advance(size_t position);
+    void tell(Position*);
+    void seek(const Position& pos);
+    MOZ_MUST_USE bool seek(const Position& pos, const TokenStream& other);
+
+    const char16_t* rawCharPtrAt(size_t offset) const {
+        return userbuf.rawCharPtrAt(offset);
+    }
+
+    const char16_t* rawLimit() const {
+        return userbuf.limit();
+    }
+
   private:
     // This is the low-level interface to the JS source code buffer.  It just
     // gets raw chars, basically.  TokenStreams functions are layered on top
     // and do some extra stuff like converting all EOL sequences to '\n',
     // tracking the line number, and setting |flags.isEOF|.  (The "raw" in "raw
     // chars" refers to the lack of EOL sequence normalization.)
     //
     // buf[0..length-1] often represents a substring of some larger source,
@@ -1014,44 +1106,19 @@ class MOZ_STACK_CLASS TokenStream
     void skipCharsIgnoreEOL(uint8_t n) {
         while (n-- > 0) {
             MOZ_ASSERT(userbuf.hasRawChars());
             getCharIgnoreEOL();
         }
     }
 
     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL();
-    void updateFlagsForEOL();
 
-    const Token& nextToken() const {
-        MOZ_ASSERT(hasLookahead());
-        return tokens[(cursor + 1) & ntokensMask];
-    }
-
-    bool hasLookahead() const { return lookahead > 0; }
-
-    // Options used for parsing/tokenizing.
-    const ReadOnlyCompileOptions& options_;
-
-    Token               tokens[ntokens];    // circular token buffer
-    unsigned            cursor;             // index of last parsed token
-    unsigned            lookahead;          // count of lookahead tokens
-    unsigned            lineno;             // current line number
-    Flags               flags;              // flags -- see above
-    size_t              linebase;           // start of current line
-    size_t              prevLinebase;       // start of previous line;  size_t(-1) if on the first line
     TokenBuf            userbuf;            // user input buffer
-    const char*         filename;           // input filename or null
-    UniqueTwoByteChars  displayURL_;        // the user's requested source URL or null
-    UniqueTwoByteChars  sourceMapURL_;      // source map's filename or null
     CharBuffer          tokenbuf;           // current token string buffer
-    uint8_t             isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
-    JSContext* const    cx;
-    bool                mutedErrors;
-    StrictModeGetter*   strictModeGetter;  // used to test for strict mode
 };
 
 extern const char*
 TokenKindToDesc(TokenKind tt);
 
 } // namespace frontend
 } // namespace js
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -429,16 +429,17 @@ MSG_DEF(JSMSG_BAD_TRAP,                1
 MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION,    0, JSEXN_ERR, "unsupported structured clone version")
 MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA,  1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
 MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE,     0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
 MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE,     0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
 MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE,     0, JSEXN_TYPEERR, "unsupported type for structured data")
 MSG_DEF(JSMSG_SC_NOT_CLONABLE,         1, JSEXN_TYPEERR, "{0} cannot be cloned in this context")
 MSG_DEF(JSMSG_SC_SAB_TRANSFERABLE,     0, JSEXN_TYPEERR, "SharedArrayBuffer must not be in the transfer list")
 MSG_DEF(JSMSG_SC_SAB_DISABLED,         0, JSEXN_TYPEERR, "SharedArrayBuffer not cloned - shared memory disabled in receiver")
+MSG_DEF(JSMSG_SC_SAB_REFCNT_OFLO,      0, JSEXN_TYPEERR, "SharedArrayBuffer has too many references")
 
 // Debugger
 MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
 MSG_DEF(JSMSG_DEBUG_BAD_LINE,          0, JSEXN_TYPEERR, "invalid line number")
 MSG_DEF(JSMSG_DEBUG_BAD_OFFSET,        0, JSEXN_TYPEERR, "invalid script offset")
 MSG_DEF(JSMSG_DEBUG_BAD_REFERENT,      2, JSEXN_TYPEERR, "{0} does not refer to {1}")
 MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION,    0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
 MSG_DEF(JSMSG_DEBUG_BAD_YIELD,         0, JSEXN_TYPEERR, "generator yielded invalid value")
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5510,60 +5510,72 @@ DestructSharedArrayBufferMailbox()
     js_delete(sharedArrayBufferMailboxLock);
 }
 
 static bool
 GetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSObject* newObj = nullptr;
-    bool rval = true;
-
-    sharedArrayBufferMailboxLock->lock();
-    SharedArrayRawBuffer* buf = sharedArrayBufferMailbox;
-    if (buf) {
-        buf->addReference();
-        // Shared memory is enabled globally in the shell: there can't be a worker
-        // that does not enable it if the main thread has it.
-        MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
-        newObj = SharedArrayBufferObject::New(cx, buf);
-        if (!newObj) {
-            buf->dropReference();
-            rval = false;
-        }
-    }
-    sharedArrayBufferMailboxLock->unlock();
+
+    {
+        sharedArrayBufferMailboxLock->lock();
+        auto unlockMailbox = MakeScopeExit([]() { sharedArrayBufferMailboxLock->unlock(); });
+
+        SharedArrayRawBuffer* buf = sharedArrayBufferMailbox;
+        if (buf) {
+            if (!buf->addReference()) {
+                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
+                return false;
+            }
+
+            // Shared memory is enabled globally in the shell: there can't be a worker
+            // that does not enable it if the main thread has it.
+            MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
+            newObj = SharedArrayBufferObject::New(cx, buf);
+            if (!newObj) {
+                buf->dropReference();
+                return false;
+            }
+        }
+    }
 
     args.rval().setObjectOrNull(newObj);
-    return rval;
+    return true;
 }
 
 static bool
 SetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     SharedArrayRawBuffer* newBuffer = nullptr;
 
     if (argc == 0 || args.get(0).isNullOrUndefined()) {
         // Clear out the mailbox
     }
     else if (args.get(0).isObject() && args[0].toObject().is<SharedArrayBufferObject>()) {
         newBuffer = args[0].toObject().as<SharedArrayBufferObject>().rawBufferObject();
-        newBuffer->addReference();
+        if (!newBuffer->addReference()) {
+            JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer");
+            return false;
+        }
     } else {
         JS_ReportErrorASCII(cx, "Only a SharedArrayBuffer can be installed in the global mailbox");
         return false;
     }
 
-    sharedArrayBufferMailboxLock->lock();
-    SharedArrayRawBuffer* oldBuffer = sharedArrayBufferMailbox;
-    if (oldBuffer)
-        oldBuffer->dropReference();
-    sharedArrayBufferMailbox = newBuffer;
-    sharedArrayBufferMailboxLock->unlock();
+    {
+        sharedArrayBufferMailboxLock->lock();
+        auto unlockMailbox = MakeScopeExit([]() { sharedArrayBufferMailboxLock->unlock(); });
+
+        SharedArrayRawBuffer* oldBuffer = sharedArrayBufferMailbox;
+        if (oldBuffer)
+            oldBuffer->dropReference();
+        sharedArrayBufferMailbox = newBuffer;
+    }
 
     args.rval().setUndefined();
     return true;
 }
 
 class SprintOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeInfoOp
 {
     Sprinter* sp;
--- a/js/src/tests/Makefile.in
+++ b/js/src/tests/Makefile.in
@@ -15,16 +15,17 @@ TEST_FILES = \
   ecma/ \
   ecma_2/ \
   ecma_3/ \
   ecma_3_1/ \
   ecma_5/ \
   ecma_6/ \
   ecma_7/ \
   ecma_2017/ \
+  ecma_2018/ \
   Intl/ \
   js1_1/ \
   js1_2/ \
   js1_3/ \
   js1_4/ \
   js1_5/ \
   js1_6/ \
   js1_7/ \
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_2017/AsyncFunctions/no-expression-closure.js
@@ -0,0 +1,17 @@
+function assertSyntaxError(code) {
+    assertThrowsInstanceOf(function () { Function(code); }, SyntaxError, "Function:" + code);
+    assertThrowsInstanceOf(function () { eval(code); }, SyntaxError, "eval:" + code);
+    var ieval = eval;
+    assertThrowsInstanceOf(function () { ieval(code); }, SyntaxError, "indirect eval:" + code);
+}
+
+// AsyncFunction statement
+assertSyntaxError(`async function f() 0`);
+
+// AsyncFunction expression
+assertSyntaxError(`void async function() 0`);
+assertSyntaxError(`void async function f() 0`);
+
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/src/tests/ecma_2017/Expressions/shell.js
+++ b/js/src/tests/ecma_2017/Expressions/shell.js
@@ -1,1 +0,0 @@
-
--- a/js/src/tests/ecma_2017/Statements/shell.js
+++ b/js/src/tests/ecma_2017/Statements/shell.js
@@ -1,1 +0,0 @@
-
--- a/js/src/tests/ecma_2017/shell.js
+++ b/js/src/tests/ecma_2017/shell.js
@@ -1,1 +0,0 @@
-
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_2018/TypedArray/fill-detached.js
@@ -0,0 +1,36 @@
+// Ensure %TypedArray%.prototype.fill checks for detached buffers.
+
+function DetachArrayBufferValue(buffer, value) {
+    return {
+        valueOf() {
+            detachArrayBuffer(buffer);
+            return value;
+        }
+    };
+}
+
+function DetachTypedArrayValue(ta, value) {
+    return {
+        valueOf() {
+            detachArrayBuffer(ta.buffer);
+            return value;
+        }
+    };
+}
+
+// Test when ArrayBuffer is already reified.
+for (let length of [0, 1, 10, 4096]) {
+    let ta = new Int32Array(length);
+    let value = DetachArrayBufferValue(ta.buffer, 123);
+    assertThrowsInstanceOf(() => ta.fill(value), TypeError);
+}
+
+// Test when ArrayBuffer is reified during the fill() call.
+for (let length of [0, 1, 10, 4096]) {
+    let ta = new Int32Array(length);
+    let value = DetachTypedArrayValue(ta, 123);
+    assertThrowsInstanceOf(() => ta.fill(value), TypeError);
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/local/let-newline-await-in-async-function.js
@@ -0,0 +1,18 @@
+// Copyright (C) 2017 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+author: Jeff Walden <jwalden+code@mit.edu>
+esid: sec-let-and-const-declarations
+description: >
+  |await| is excluded from LexicalDeclaration by grammar parameter, in
+  AsyncFunction.  Therefore |let| followed by |await| inside AsyncFunction is
+  an ASI opportunity, and this code must parse without error.
+---*/
+
+async function f() {
+    let
+    await 0;
+}
+
+reportCompare(true, f instanceof Function);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/local/let-newline-await-in-normal-function.js
@@ -0,0 +1,20 @@
+// |reftest| error:SyntaxError
+// Copyright (C) 2017 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+author: Jeff Walden <jwalden+code@mit.edu>
+esid: sec-let-and-const-declarations
+description: >
+  Outside AsyncFunction, |await| is a perfectly cromulent LexicalDeclaration
+  variable name.  Therefore ASI doesn't apply, and so the |0| where a |=| was
+  expected is a syntax error.
+negative:
+  phase: early
+  type: SyntaxError
+---*/
+
+function f() {
+    let
+    await 0;
+}
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -725,17 +725,17 @@ GlobalHelperThreadState::ensureInitializ
     MOZ_ASSERT(CanUseExtraThreads());
 
     MOZ_ASSERT(this == &HelperThreadState());
     AutoLockHelperThreadState lock;
 
     if (threads)
         return true;
 
-    threads = js::UniquePtr<HelperThreadVector>(js_new<HelperThreadVector>());
+    threads = js::MakeUnique<HelperThreadVector>();
     if (!threads || !threads->initCapacity(threadCount))
         return false;
 
     for (size_t i = 0; i < threadCount; i++) {
         threads->infallibleEmplaceBack();
         HelperThread& helper = (*threads)[i];
 
         helper.thread = mozilla::Some(Thread(Thread::Options().setStackSize(HELPER_STACK_SIZE)));
@@ -1624,17 +1624,17 @@ js::PauseCurrentHelperThread()
     AutoLockHelperThreadState lock;
     while (thread->pause)
         HelperThreadState().wait(lock, GlobalHelperThreadState::PAUSE);
 }
 
 bool
 JSContext::addPendingCompileError(frontend::CompileError** error)
 {
-    UniquePtr<frontend::CompileError> errorPtr(new_<frontend::CompileError>());
+    auto errorPtr = make_unique<frontend::CompileError>();
     if (!errorPtr)
         return false;
     if (!helperThread()->parseTask()->errors.append(errorPtr.get())) {
         ReportOutOfMemory(this);
         return false;
     }
     *error = errorPtr.release();
     return true;
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -160,26 +160,40 @@ SharedArrayRawBuffer::New(JSContext* cx,
 
     uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
     uint8_t* base = buffer - sizeof(SharedArrayRawBuffer);
     SharedArrayRawBuffer* rawbuf = new (base) SharedArrayRawBuffer(buffer, length, preparedForAsmJS);
     MOZ_ASSERT(rawbuf->length == length); // Deallocation needs this
     return rawbuf;
 }
 
-void
+bool
 SharedArrayRawBuffer::addReference()
 {
-    MOZ_ASSERT(this->refcount_ > 0);
-    ++this->refcount_; // Atomic.
+    MOZ_RELEASE_ASSERT(this->refcount_ > 0);
+
+    // Be careful never to overflow the refcount field.
+    for (;;) {
+        uint32_t old_refcount = this->refcount_;
+        uint32_t new_refcount = old_refcount+1;
+        if (new_refcount == 0)
+            return false;
+        if (this->refcount_.compareExchange(old_refcount, new_refcount))
+            return true;
+    }
 }
 
 void
 SharedArrayRawBuffer::dropReference()
 {
+    // Normally if the refcount is zero then the memory will have been unmapped
+    // and this test may just crash, but if the memory has been retained for any
+    // reason we will catch the underflow here.
+    MOZ_RELEASE_ASSERT(this->refcount_ > 0);
+
     // Drop the reference to the buffer.
     uint32_t refcount = --this->refcount_; // Atomic.
     if (refcount)
         return;
 
     // If this was the final reference, release the buffer.
 
     SharedMem<uint8_t*> p = this->dataPointerShared() - gc::SystemPageSize();
--- a/js/src/vm/SharedArrayObject.h
+++ b/js/src/vm/SharedArrayObject.h
@@ -87,17 +87,17 @@ class SharedArrayRawBuffer
     }
 
     bool isPreparedForAsmJS() const {
         return preparedForAsmJS;
     }
 
     uint32_t refcount() const { return refcount_; }
 
-    void addReference();
+    MOZ_MUST_USE bool addReference();
     void dropReference();
 };
 
 /*
  * SharedArrayBufferObject
  *
  * When transferred to a WebWorker, the buffer is not detached on the
  * parent side, and both child and parent reference the same buffer.
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -224,16 +224,79 @@ struct BufferIterator {
         MOZ_ASSERT(mIter.HasRoomFor(sizeof(T)));
         return *reinterpret_cast<T*>(mIter.Data());
     }
 
     BufferList& mBuffer;
     typename BufferList::IterImpl mIter;
 };
 
+SharedArrayRawBufferRefs&
+SharedArrayRawBufferRefs::operator=(SharedArrayRawBufferRefs&& other)
+{
+    takeOwnership(Move(other));
+    return *this;
+}
+
+SharedArrayRawBufferRefs::~SharedArrayRawBufferRefs()
+{
+    releaseAll();
+}
+
+bool
+SharedArrayRawBufferRefs::acquire(JSContext* cx, SharedArrayRawBuffer* rawbuf)
+{
+    if (!refs_.append(rawbuf)) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+
+    if (!rawbuf->addReference()) {
+        refs_.popBack();
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
+        return false;
+    }
+
+    return true;
+}
+
+bool
+SharedArrayRawBufferRefs::acquireAll(JSContext* cx, const SharedArrayRawBufferRefs& that)
+{
+    if (!refs_.reserve(refs_.length() + that.refs_.length())) {
+        ReportOutOfMemory(cx);
+        return false;
+    }
+
+    for (auto ref : that.refs_) {
+        if (!ref->addReference()) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
+            return false;
+        }
+        MOZ_ALWAYS_TRUE(refs_.append(ref));
+    }
+
+    return true;
+}
+
+void
+SharedArrayRawBufferRefs::takeOwnership(SharedArrayRawBufferRefs&& other)
+{
+    MOZ_ASSERT(refs_.empty());
+    refs_ = Move(other.refs_);
+}
+
+void
+SharedArrayRawBufferRefs::releaseAll()
+{
+    for (auto ref : refs_)
+        ref->dropReference();
+    refs_.clear();
+}
+
 struct SCOutput {
   public:
     using Iter = BufferIterator<uint64_t, TempAllocPolicy>;
 
     explicit SCOutput(JSContext* cx);
 
     JSContext* context() const { return cx; }
 
@@ -403,16 +466,19 @@ struct JSStructuredCloneWriter {
 
     bool write(HandleValue v);
 
     SCOutput& output() { return out; }
 
     bool extractBuffer(JSStructuredCloneData* data) {
         bool success = out.extractBuffer(data);
         if (success) {
+            // Move the SharedArrayRawBuf references here, SCOutput::extractBuffer
+            // moves the serialized data.
+            data->refsHeld_.takeOwnership(Move(refsHeld));
             data->setOptionalCallbacks(callbacks, closure,
                                        OwnTransferablePolicy::OwnsTransferablesIfAny);
         }
         return success;
     }
 
     JS::StructuredCloneScope cloneScope() const { return scope; }
 
@@ -481,16 +547,19 @@ struct JSStructuredCloneWriter {
     void* closure;
 
     // Set of transferable objects
     RootedValue transferable;
     Rooted<GCHashSet<JSObject*>> transferableObjects;
 
     const JS::CloneDataPolicy cloneDataPolicy;
 
+    // SharedArrayRawBuffers whose reference counts we have incremented.
+    SharedArrayRawBufferRefs refsHeld;
+
     friend bool JS_WriteString(JSStructuredCloneWriter* w, HandleString str);
     friend bool JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v);
     friend bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj);
 };
 
 JS_FRIEND_API(uint64_t)
 js::GetSCOffset(JSStructuredCloneWriter* writer)
 {
@@ -1156,19 +1225,18 @@ JSStructuredCloneWriter::writeSharedArra
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_NOT_CLONABLE,
                                   "SharedArrayBuffer");
         return false;
     }
 
     Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
     SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
 
-    // Avoids a race condition where the parent thread frees the buffer
-    // before the child has accepted the transferable.
-    rawbuf->addReference();
+    if (!refsHeld.acquire(context(), rawbuf))
+        return false;
 
     intptr_t p = reinterpret_cast<intptr_t>(rawbuf);
     return out.writePair(SCTAG_SHARED_ARRAY_BUFFER_OBJECT, static_cast<uint32_t>(sizeof(p))) &&
            out.writeBytes(&p, sizeof(p));
 }
 
 bool
 JSStructuredCloneWriter::startObject(HandleObject obj, bool* backref)
@@ -1886,28 +1954,34 @@ JSStructuredCloneReader::readSharedArray
     SharedArrayRawBuffer* rawbuf = reinterpret_cast<SharedArrayRawBuffer*>(p);
 
     // There's no guarantee that the receiving agent has enabled shared memory
     // even if the transmitting agent has done so.  Ideally we'd check at the
     // transmission point, but that's tricky, and it will be a very rare problem
     // in any case.  Just fail at the receiving end if we can't handle it.
 
     if (!context()->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
-        // The sending side performed a reference increment before sending.
-        // Account for that here before leaving.
-        if (rawbuf)
-            rawbuf->dropReference();
-
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_DISABLED);
         return false;
     }
 
-    // The constructor absorbs the reference count increment performed by the sender.
+    // The new object will have a new reference to the rawbuf.
+
+    if (!rawbuf->addReference()) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
+        return false;
+    }
+
     JSObject* obj = SharedArrayBufferObject::New(context(), rawbuf);
 
+    if (!obj) {
+        rawbuf->dropReference();
+        return false;
+    }
+
     vp.setObject(*obj);
     return true;
 }
 
 /*
  * Read in the data for a structured clone version 1 ArrayBuffer, performing
  * endianness-conversion while reading.
  */
@@ -2583,38 +2657,44 @@ JSAutoStructuredCloneBuffer::clear(const
 
     const JSStructuredCloneCallbacks* callbacks =
         optionalCallbacks ?  optionalCallbacks : data_.callbacks_;
     void* closure = optionalClosure ?  optionalClosure : data_.closure_;
 
     if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
         DiscardTransferables(data_, callbacks, closure);
     data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
+    data_.refsHeld_.releaseAll();
     data_.Clear();
     version_ = 0;
 }
 
 bool
-JSAutoStructuredCloneBuffer::copy(const JSStructuredCloneData& srcData, uint32_t version,
-                                  const JSStructuredCloneCallbacks* callbacks,
+JSAutoStructuredCloneBuffer::copy(JSContext* cx, const JSStructuredCloneData& srcData,
+                                  uint32_t version, const JSStructuredCloneCallbacks* callbacks,
                                   void* closure)
 {
     // transferable objects cannot be copied
     if (StructuredCloneHasTransferObjects(srcData))
         return false;
 
     clear();
 
     auto iter = srcData.Iter();
     while (!iter.Done()) {
-            data_.WriteBytes(iter.Data(), iter.RemainingInSegment());
-            iter.Advance(srcData, iter.RemainingInSegment());
+        if (!data_.WriteBytes(iter.Data(), iter.RemainingInSegment()))
+            return false;
+        iter.Advance(srcData, iter.RemainingInSegment());
     }
 
     version_ = version;
+
+    if (!data_.refsHeld_.acquireAll(cx, srcData.refsHeld_))
+        return false;
+
     data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
     return true;
 }
 
 void
 JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t version,
                                    const JSStructuredCloneCallbacks* callbacks,
                                    void* closure)
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -17,16 +17,17 @@
  */
 
 #include "wasm/AsmJS.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Compression.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/Unused.h"
 
 #include "jsmath.h"
 #include "jsprf.h"
 #include "jsstr.h"
 #include "jsutil.h"
 
 #include "jswrapper.h"
 
@@ -64,16 +65,17 @@ using mozilla::IsNegativeZero;
 using mozilla::IsPositiveZero;
 using mozilla::IsPowerOfTwo;
 using mozilla::Maybe;
 using mozilla::Move;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::PodZero;
 using mozilla::PositiveInfinity;
+using mozilla::Unused;
 using JS::AsmJSOption;
 using JS::GenericNaN;
 
 /*****************************************************************************/
 
 // The asm.js valid heap lengths are precisely the WASM valid heap lengths for ARM
 // greater or equal to MinHeapLength
 static const size_t MinHeapLength = PageSize;
@@ -1731,24 +1733,51 @@ class MOZ_STACK_CLASS ModuleValidator
         errorString_(nullptr),
         errorOffset_(UINT32_MAX),
         errorOverRecursed_(false)
     {}
 
     ~ModuleValidator() {
         if (errorString_) {
             MOZ_ASSERT(errorOffset_ != UINT32_MAX);
-            tokenStream().reportAsmJSError(errorOffset_,
-                                           JSMSG_USE_ASM_TYPE_FAIL,
-                                           errorString_.get());
+            typeFailure(errorOffset_, errorString_.get());
         }
         if (errorOverRecursed_)
             ReportOverRecursed(cx_);
     }
 
+  private:
+    void typeFailure(uint32_t offset, ...) {
+        va_list args;
+        va_start(args, offset);
+
+        TokenStream& ts = tokenStream();
+        ErrorMetadata metadata;
+        if (ts.computeErrorMetadata(&metadata, offset)) {
+            if (ts.options().throwOnAsmJSValidationFailureOption) {
+                ts.compileError(Move(metadata), nullptr, JSREPORT_ERROR, JSMSG_USE_ASM_TYPE_FAIL,
+                                args);
+            } else {
+                // asm.js type failure is indicated by calling one of the fail*
+                // functions below.  These functions always return false to
+                // halt asm.js parsing.  Whether normal parsing is attempted as
+                // fallback, depends whether an exception is also set.
+                //
+                // If warning succeeds, no exception is set.  If warning fails,
+                // an exception is set and execution will halt.  Thus it's safe
+                // and correct to ignore the return value here.
+                Unused << ts.compileWarning(Move(metadata), nullptr, JSREPORT_WARNING,
+                                            JSMSG_USE_ASM_TYPE_FAIL, args);
+            }
+        }
+
+        va_end(args);
+    }
+
+  public:
     bool init() {
         asmJSMetadata_ = cx_->new_<AsmJSMetadata>();
         if (!asmJSMetadata_)
             return false;
 
         asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
         asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
         asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -1143,21 +1143,21 @@ class BaseCompiler
             masm.moveFloat32(src, dest);
     }
 
     void setI64(int64_t v, RegI64 r) {
         masm.move64(Imm64(v), r);
     }
 
     void loadConstI32(Register r, Stk& src) {
-        masm.mov(ImmWord((uint32_t)src.i32val() & 0xFFFFFFFFU), r);
+        masm.mov(ImmWord(uint32_t(src.i32val())), r);
     }
 
     void loadConstI32(Register r, int32_t v) {
-        masm.mov(ImmWord(v), r);
+        masm.mov(ImmWord(uint32_t(v)), r);
     }
 
     void loadMemI32(Register r, Stk& src) {
         loadFromFrameI32(r, src.offs());
     }
 
     void loadLocalI32(Register r, Stk& src) {
         loadFromFrameI32(r, frameOffsetFromSlot(src.slot(), MIRType::Int32));
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -92,17 +92,16 @@ RemoteXULForbidsXBLScope(nsIPrincipal* a
 XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
                                              JS::HandleObject aGlobal)
       : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_LENGTH)),
         mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_LENGTH)),
         mComponents(nullptr),
         mNext(nullptr),
         mGlobalJSObject(aGlobal),
         mHasCallInterpositions(false),
-        mDocGroupValidation(false),
         mIsContentXBLScope(false),
         mIsAddonScope(false)
 {
     // add ourselves to the scopes list
     {
         MOZ_ASSERT(aGlobal);
         DebugOnly<const js::Class*> clasp = js::GetObjectClass(aGlobal);
         MOZ_ASSERT(clasp->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
@@ -163,19 +162,16 @@ XPCWrappedNativeScope::XPCWrappedNativeS
             UpdateInterpositionWhitelist(cx, mInterposition);
           }
         }
     }
 
     if (addonId) {
         // We forbid CPOWs unless they're specifically allowed.
         priv->allowCPOWs = gAllowCPOWAddonSet ? gAllowCPOWAddonSet->has(addonId) : false;
-
-        // Automatically opt into DocGroup validation for add-on compartments.
-        mDocGroupValidation = true;
     }
 }
 
 // static
 bool
 XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope* scope)
 {
     for (XPCWrappedNativeScope* cur = gDyingScopes; cur; cur = cur->mNext) {
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1368,22 +1368,16 @@ AllowCPOWsInAddon(const nsACString& addo
     if (!jsapi.Init(xpc::PrivilegedJunkScope()))
         return false;
     addonId = NewAddonId(jsapi.cx(), addonIdStr);
     if (!addonId)
         return false;
     return XPCWrappedNativeScope::AllowCPOWsInAddon(jsapi.cx(), addonId, allow);
 }
 
-void
-SetDocGroupValidation(JSObject* global)
-{
-    CompartmentPrivate::Get(global)->scope->SetDocGroupValidation();
-}
-
 } // namespace xpc
 
 namespace mozilla {
 namespace dom {
 
 bool
 IsChromeOrXBL(JSContext* cx, JSObject* /* unused */)
 {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -861,19 +861,16 @@ public:
 
     // Forces the creation of a privileged |Components| object, even in
     // content scopes. This will crash if used outside of automation.
     void
     ForcePrivilegedComponents();
 
     bool AttachComponentsObject(JSContext* aCx);
 
-    void SetDocGroupValidation() { mDocGroupValidation = true; }
-    bool HasDocGroupValidation() const { return mDocGroupValidation; }
-
     // Returns the JS object reflection of the Components object.
     bool
     GetComponentsJSObject(JS::MutableHandleObject obj);
 
     JSObject*
     GetGlobalJSObject() const {
         return mGlobalJSObject;
     }
@@ -1065,22 +1062,16 @@ private:
     // This is a service that will be use to interpose on some property accesses on
     // objects from other scope, for add-on compatibility reasons.
     nsCOMPtr<nsIAddonInterposition>  mInterposition;
 
     // If this flag is set, we intercept function calls on vanilla JS function objects
     // from this scope if the caller scope has mInterposition set.
     bool mHasCallInterpositions;
 
-    // If this flag is set, Xray wrappers from this compartment to content
-    // compartments will be DocGroupValidationWrappers of some
-    // sort. Consequently, this compartment will throw instead of asserting for
-    // DocGroup mismatches.
-    bool mDocGroupValidation;
-
     nsAutoPtr<DOMExpandoSet> mDOMExpandoSet;
 
     JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
 
     bool mIsContentXBLScope;
     bool mIsAddonScope;
 
     // For remote XUL domains, we run all XBL in the content scope for compat
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -358,18 +358,16 @@ bool StringToJsval(JSContext* cx, mozill
 nsIPrincipal* GetCompartmentPrincipal(JSCompartment* compartment);
 
 void NukeAllWrappersForCompartment(JSContext* cx, JSCompartment* compartment,
                                    js::NukeReferencesToWindow nukeReferencesToWindow = js::NukeWindowReferences);
 
 void SetLocationForGlobal(JSObject* global, const nsACString& location);
 void SetLocationForGlobal(JSObject* global, nsIURI* locationURI);
 
-void SetDocGroupValidation(JSObject* global);
-
 // ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
 // of JS::ZoneStats.
 class ZoneStatsExtras {
 public:
     ZoneStatsExtras() {}
 
     nsCString pathPrefix;
 
deleted file mode 100644
--- a/js/xpconnect/wrappers/DocGroupValidationWrapper.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/* -*- 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 "DocGroupValidationWrapper.h"
-#include "AddonWrapper.h"
-#include "WaiveXrayWrapper.h"
-
-#include "mozilla/dom/DocGroup.h"
-#include "nsGlobalWindow.h"
-
-using namespace xpc;
-
-static bool
-AccessAllowed(JSContext* cx, JS::Handle<JSObject*> wrapper)
-{
-    RootedObject unwrapped(cx, UncheckedUnwrap(wrapper));
-    RefPtr<nsGlobalWindow> window = WindowGlobalOrNull(unwrapped);
-    if (!window) {
-        // Access to non-windows is always kosher.
-        return true;
-    }
-
-    if (window->GetDocGroup()->AccessAllowed())
-        return true;
-
-    static bool sThrowOnMismatch;
-    static bool sPrefInitialized;
-    if (!sPrefInitialized) {
-        sPrefInitialized = true;
-        Preferences::AddBoolVarCache(&sThrowOnMismatch,
-                                     "extensions.throw_on_docgroup_mismatch.enabled");
-    }
-
-    // If DocGroup validation is disabled, don't throw.
-    if (!sThrowOnMismatch)
-        return true;
-
-    JS_ReportErrorASCII(cx, "accessing object in wrong DocGroup");
-    return false;
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
-                                                          MutableHandle<PropertyDescriptor> desc) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::getOwnPropertyDescriptor(cx, wrapper, id, desc);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
-                                                Handle<PropertyDescriptor> desc,
-                                                ObjectOpResult& result) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::defineProperty(cx, wrapper, id, desc, result);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::ownPropertyKeys(JSContext* cx, HandleObject wrapper,
-                                                 AutoIdVector& props) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::ownPropertyKeys(cx, wrapper, props);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
-                                         ObjectOpResult& result) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::delete_(cx, wrapper, id, result);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::enumerate(JSContext* cx, HandleObject wrapper, MutableHandleObject objp) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::enumerate(cx, wrapper, objp);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::getPrototype(JSContext* cx, HandleObject proxy,
-                                              MutableHandleObject protop) const
-{
-    return AccessAllowed(cx, proxy) &&
-           Base::getPrototype(cx, proxy, protop);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
-                                              ObjectOpResult& result) const
-{
-    return AccessAllowed(cx, proxy) &&
-           Base::setPrototype(cx, proxy, proto, result);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
-                                                        MutableHandleObject protop) const
-{
-    return AccessAllowed(cx, proxy) &&
-           Base::getPrototypeIfOrdinary(cx, proxy, isOrdinary, protop);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::setImmutablePrototype(JSContext* cx, HandleObject proxy,
-                                                       bool* succeeded) const
-{
-    return AccessAllowed(cx, proxy) &&
-           Base::setImmutablePrototype(cx, proxy, succeeded);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::preventExtensions(JSContext* cx, HandleObject wrapper,
-                                                   ObjectOpResult& result) const
-{
-    return AccessAllowed(cx, wrapper) &&
-        Base::preventExtensions(cx, wrapper, result);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::isExtensible(cx, wrapper, extensible);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::has(cx, wrapper, id, bp);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
-                                     HandleId id, MutableHandleValue vp) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::get(cx, wrapper, receiver, id, vp);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
-                                     HandleValue receiver, ObjectOpResult& result) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::set(cx, wrapper, id, v, receiver, result);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::call(cx, wrapper, args);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::construct(cx, wrapper, args);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
-                                                       MutableHandle<PropertyDescriptor> desc) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::getPropertyDescriptor(cx, wrapper, id, desc);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::hasOwn(cx, wrapper, id, bp);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
-                                                              AutoIdVector& props) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::getOwnEnumerablePropertyKeys(cx, wrapper, props);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
-                                             bool* bp) const
-{
-    return AccessAllowed(cx, wrapper) &&
-           Base::hasInstance(cx, wrapper, v, bp);
-}
-
-template<typename Base>
-const char*
-DocGroupValidationWrapper<Base>::className(JSContext* cx, HandleObject proxy) const
-{
-    return AccessAllowed(cx, proxy)
-         ? Base::className(cx, proxy)
-         : "forbidden";
-}
-
-template<typename Base>
-JSString*
-DocGroupValidationWrapper<Base>::fun_toString(JSContext* cx, HandleObject wrapper,
-                                              unsigned indent) const
-{
-    return AccessAllowed(cx, wrapper)
-           ? Base::fun_toString(cx, wrapper, indent)
-           : nullptr;
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandle<RegExpShared*> g) const
-{
-    return AccessAllowed(cx, proxy) &&
-           Base::regexp_toShared(cx, proxy, g);
-}
-
-template<typename Base>
-bool
-DocGroupValidationWrapper<Base>::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
-{
-    return AccessAllowed(cx, proxy) &&
-           Base::boxedValue_unbox(cx, proxy, vp);
-}
-
-namespace xpc {
-
-template<typename Base>
-const DocGroupValidationWrapper<Base> DocGroupValidationWrapper<Base>::singleton(0);
-
-#define DEFINE_SINGLETON(Base)                          \
-    template class DocGroupValidationWrapper<Base>
-
-DEFINE_SINGLETON(CrossCompartmentWrapper);
-DEFINE_SINGLETON(PermissiveXrayXPCWN);
-DEFINE_SINGLETON(PermissiveXrayDOM);
-DEFINE_SINGLETON(PermissiveXrayJS);
-
-DEFINE_SINGLETON(AddonWrapper<CrossCompartmentWrapper>);
-DEFINE_SINGLETON(AddonWrapper<PermissiveXrayXPCWN>);
-DEFINE_SINGLETON(AddonWrapper<PermissiveXrayDOM>);
-
-DEFINE_SINGLETON(WaiveXrayWrapper);
-
-} // namespace xpc
deleted file mode 100644
--- a/js/xpconnect/wrappers/DocGroupValidationWrapper.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- 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 xpc_DocGroupValidationWrapper_h
-#define xpc_DocGroupValidationWrapper_h
-
-#include "mozilla/Attributes.h"
-
-#include "jswrapper.h"
-#include "WaiveXrayWrapper.h"
-#include "XrayWrapper.h"
-
-namespace xpc {
-
-template<typename Base>
-class DocGroupValidationWrapper : public Base {
-  public:
-    explicit constexpr DocGroupValidationWrapper(unsigned flags) : Base(flags) { }
-
-    /* Standard internal methods. */
-    virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
-                                          MutableHandle<PropertyDescriptor> desc) const override;
-    virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
-                                Handle<PropertyDescriptor> desc,
-                                ObjectOpResult& result) const override;
-    virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
-                                 AutoIdVector& props) const override;
-    virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
-                         ObjectOpResult& result) const override;
-    virtual bool enumerate(JSContext* cx, HandleObject wrapper, MutableHandleObject objp) const override;
-    virtual bool getPrototype(JSContext* cx, HandleObject proxy,
-                              MutableHandleObject protop) const override;
-    virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
-                              ObjectOpResult& result) const override;
-
-    virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
-                                        MutableHandleObject protop) const override;
-    virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
-                                       bool* succeeded) const override;
-    virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
-                                   ObjectOpResult& result) const override;
-    virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
-    virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
-                     HandleId id, MutableHandleValue vp) const override;
-    virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult& result) const override;
-    virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
-    virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
-
-    /* SpiderMonkey extensions. */
-    virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
-                                       MutableHandle<PropertyDescriptor> desc) const override;
-    virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
-    virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
-                                              AutoIdVector& props) const override;
-    virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
-                             bool* bp) const override;
-    virtual const char* className(JSContext* cx, HandleObject proxy) const override;
-    virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
-                                   unsigned indent) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandle<RegExpShared*> g) const override;
-    virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
-
-    static const DocGroupValidationWrapper singleton;
-};
-
-#define DECLARE_SINGLETON(Base) \
-    extern template class DocGroupValidationWrapper<Base>
-
-DECLARE_SINGLETON(CrossCompartmentWrapper);
-DECLARE_SINGLETON(PermissiveXrayXPCWN);
-DECLARE_SINGLETON(PermissiveXrayDOM);
-DECLARE_SINGLETON(PermissiveXrayJS);
-
-DECLARE_SINGLETON(AddonWrapper<CrossCompartmentWrapper>);
-DECLARE_SINGLETON(AddonWrapper<PermissiveXrayXPCWN>);
-DECLARE_SINGLETON(AddonWrapper<PermissiveXrayDOM>);
-
-DECLARE_SINGLETON(WaiveXrayWrapper);
-
-} // namespace xpc
-
-#endif // xpc_DocGroupValidationWrapper_h
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -2,17 +2,16 @@
 /* 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 "WaiveXrayWrapper.h"
 #include "FilteringWrapper.h"
 #include "AddonWrapper.h"
-#include "DocGroupValidationWrapper.h"
 #include "XrayWrapper.h"
 #include "AccessCheck.h"
 #include "XPCWrapper.h"
 #include "ChromeObjectWrapper.h"
 #include "WrapperFactory.h"
 
 #include "xpcprivate.h"
 #include "XPCMaps.h"
@@ -443,76 +442,16 @@ SelectAddonWrapper(JSContext* cx, Handle
         return &AddonWrapper<PermissiveXrayXPCWN>::singleton;
     else if (wrapper == &PermissiveXrayDOM::singleton)
         return &AddonWrapper<PermissiveXrayDOM>::singleton;
 
     // |wrapper| is not supported for interposition, so we don't do it.
     return wrapper;
 }
 
-static bool
-NeedsDocGroupValidationWrapper(JSContext* cx, HandleObject obj,
-                               JSCompartment* origin, JSCompartment* target,
-                               CompartmentPrivate* targetCompartmentPrivate)
-{
-    // We do DocGroup validation in the following circumstances:
-    //   - Only if the target compartment has the DocGroupValidation()
-    //     flag set (which includes any add-on compartments).
-    //   - Only if we're in the content process.
-    //   - Only if the origin compartment is not system principled and is not a sandbox.
-    //   - Only if the target compartment is system principled.
-
-    if (!targetCompartmentPrivate->scope->HasDocGroupValidation())
-        return false;
-
-    if (!XRE_IsContentProcess())
-        return false;
-
-    if (!AccessCheck::isChrome(target))
-        return false;
-
-    if (AccessCheck::isChrome(origin) ||
-        IsSandbox(js::GetGlobalForObjectCrossCompartment(obj)))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-static const Wrapper*
-SelectDocGroupValidationWrapper(JSContext* cx, HandleObject obj, const Wrapper* wrapper)
-{
-    // Validation wrappers only supports certain wrapper types, so we check if
-    // we would have used one of the supported ones.
-    if (wrapper == &CrossCompartmentWrapper::singleton)
-        return &DocGroupValidationWrapper<CrossCompartmentWrapper>::singleton;
-    else if (wrapper == &PermissiveXrayXPCWN::singleton)
-        return &DocGroupValidationWrapper<PermissiveXrayXPCWN>::singleton;
-    else if (wrapper == &PermissiveXrayDOM::singleton)
-        return &DocGroupValidationWrapper<PermissiveXrayDOM>::singleton;
-    else if (wrapper == &PermissiveXrayJS::singleton)
-        return &DocGroupValidationWrapper<PermissiveXrayJS>::singleton;
-    else if (wrapper == &AddonWrapper<CrossCompartmentWrapper>::singleton)
-        return &DocGroupValidationWrapper<AddonWrapper<CrossCompartmentWrapper>>::singleton;
-    else if (wrapper == &AddonWrapper<PermissiveXrayXPCWN>::singleton)
-        return &DocGroupValidationWrapper<AddonWrapper<PermissiveXrayXPCWN>>::singleton;
-    else if (wrapper == &AddonWrapper<PermissiveXrayDOM>::singleton)
-        return &DocGroupValidationWrapper<AddonWrapper<PermissiveXrayDOM>>::singleton;
-    else if (wrapper == &WaiveXrayWrapper::singleton)
-        return &DocGroupValidationWrapper<WaiveXrayWrapper>::singleton;
-
-    // If NeedsDocGroupValidationWrapper is true, then securityWrapper should be false
-    // and xrayType should never be NotXray (since the target always subsumes the origin
-    // and the origin never subsumes the target).
-    MOZ_ASSERT(wrapper == &WaiveXrayWrapper::singleton ||
-               wrapper == &(PermissiveXrayOpaque::singleton));
-    return wrapper;
-}
-
 JSObject*
 WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
 {
     MOZ_ASSERT(!IsWrapper(obj) ||
                GetProxyHandler(obj) == &XrayWaiver ||
                js::IsWindowProxy(obj),
                "wrapped object passed to rewrap");
     MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
@@ -612,23 +551,16 @@ WrapperFactory::Rewrap(JSContext* cx, Ha
                           HasWaiveXrayFlag(obj);
 
         wrapper = SelectWrapper(securityWrapper, xrayType, waiveXrays, obj);
 
         // If we want to apply add-on interposition in the target compartment,
         // then we try to "upgrade" the wrapper to an interposing one.
         if (targetCompartmentPrivate->scope->HasInterposition())
             wrapper = SelectAddonWrapper(cx, obj, wrapper);
-
-        // Now try another "upgrade" to a DocGroupValidationWrapper.
-        if (NeedsDocGroupValidationWrapper(cx, obj, origin, target,
-                                           targetCompartmentPrivate))
-        {
-            wrapper = SelectDocGroupValidationWrapper(cx, obj, wrapper);
-        }
     }
 
     if (!targetSubsumesOrigin) {
         // Do a belt-and-suspenders check against exposing eval()/Function() to
         // non-subsuming content.
         if (JSFunction* fun = JS_GetObjectFunction(obj)) {
             if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) {
                 NS_WARNING("Trying to expose eval or Function to non-subsuming content!");
--- a/js/xpconnect/wrappers/moz.build
+++ b/js/xpconnect/wrappers/moz.build
@@ -7,17 +7,16 @@
 EXPORTS += [
     'WrapperFactory.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessCheck.cpp',
     'AddonWrapper.cpp',
     'ChromeObjectWrapper.cpp',
-    'DocGroupValidationWrapper.cpp',
     'FilteringWrapper.cpp',
     'WaiveXrayWrapper.cpp',
     'WrapperFactory.cpp',
 ]
 
 # XrayWrapper needs to be built separately becaue of template instantiations.
 SOURCES += [
     'XrayWrapper.cpp',
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -589,18 +589,25 @@ static void GetKeywordsForProperty(const
     // Shorthand props have no keywords.
     return;
   }
   const nsCSSProps::KTableEntry* keywordTable =
     nsCSSProps::kKeywordTableTable[aProperty];
   if (keywordTable) {
     for (size_t i = 0; keywordTable[i].mKeyword != eCSSKeyword_UNKNOWN; ++i) {
       nsCSSKeyword word = keywordTable[i].mKeyword;
-      InsertNoDuplicates(aArray,
-                         NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
+
+      // These are extra -moz values which are added while rebuilding
+      // the properties db. These values are not relevant and are not
+      // documented on MDN, so filter these out
+      if (word != eCSSKeyword__moz_zoom_in && word != eCSSKeyword__moz_zoom_out &&
+          word != eCSSKeyword__moz_grab && word != eCSSKeyword__moz_grabbing) {
+          InsertNoDuplicates(aArray,
+                  NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
+      }
     }
   }
 }
 
 static void GetColorsForProperty(const uint32_t aParserVariant,
                                  nsTArray<nsString>& aArray)
 {
   if (aParserVariant & VARIANT_COLOR) {
@@ -933,37 +940,33 @@ inDOMUtils::GetCSSValuesForProperty(cons
   // needs to stay sorted, and the colors are sorted, so we just append them.
   if (propertyID == eCSSPropertyExtra_variable) {
     // No other values we can report.
   } else if (!nsCSSProps::IsShorthand(propertyID)) {
     // Property is longhand.
     uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID);
     // Get colors first.
     GetColorsForProperty(propertyParserVariant, array);
-    if (propertyParserVariant & VARIANT_KEYWORD) {
-      GetKeywordsForProperty(propertyID, array);
-    }
+    GetKeywordsForProperty(propertyID, array);
     GetOtherValuesForProperty(propertyParserVariant, array);
   } else {
     // Property is shorthand.
     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
                                          CSSEnabledState::eForAllContent) {
       // Get colors (once) first.
       uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
       if (propertyParserVariant & VARIANT_COLOR) {
         GetColorsForProperty(propertyParserVariant, array);
         break;
       }
     }
     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
                                          CSSEnabledState::eForAllContent) {
       uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
-      if (propertyParserVariant & VARIANT_KEYWORD) {
-        GetKeywordsForProperty(*subproperty, array);
-      }
+      GetKeywordsForProperty(*subproperty, array);
       GetOtherValuesForProperty(propertyParserVariant, array);
     }
   }
   // All CSS properties take initial, inherit and unset.
   InsertNoDuplicates(array, NS_LITERAL_STRING("initial"));
   InsertNoDuplicates(array, NS_LITERAL_STRING("inherit"));
   InsertNoDuplicates(array, NS_LITERAL_STRING("unset"));
 
--- a/layout/inspector/tests/test_bug877690.html
+++ b/layout/inspector/tests/test_bug877690.html
@@ -7,40 +7,33 @@ https://bugzilla.mozilla.org/show_bug.cg
 <meta charset="utf-8">
 <title>Test for Bug 877690</title>
 <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 <script type="application/javascript">
 
 /** Test for Bug 877690 **/
 
-// Returns true if array contains item. False otherwise. Raises an exception if
-// array is not an Array object. If the item is found in array, remove item.
-function contains(array, item) {
-  if (!array.indexOf) {
-    throw new "First argument is not an array";
-  }
-  var index = array.indexOf(item);
-  if (index == -1) {
+// Returns true if values contains all and only the expected values. False otherwise.
+function testValues(values, expected) {
+  values.sort();
+  expected.sort();
+
+  if (values.length !== expected.length) {
     return false;
   }
-  array.splice(index, 1);
+
+  for (var i = 0; i < values.length; ++i) {
+    if (values[i] !== expected[i]) {
+      return false;
+    }
+  }
   return true;
 }
 
-// Returns true if values contains all and only the expected values. False otherwise.
-function testValues(values, expected) {
-  expected.forEach(function (expectedValue) {
-      if (!contains(values, expectedValue)) {
-        return false;
-      }
-  });
-  return values.length === 0;
-}
-
 function do_test() {
   var utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
     .getService(SpecialPowers.Ci.inIDOMUtils);
 
   var getCSSValuesForProperty = function(prop) {
     return Array.from(utils.getCSSValuesForProperty(prop));
   }
 
@@ -89,41 +82,41 @@ function do_test() {
       "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
       "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod",
       "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum",
       "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown",
       "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey",
       "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "transparent", "turquoise",
       "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", "no-repeat", "repeat",
       "repeat-x", "repeat-y", "space", "round", "fixed", "scroll", "local", "center", "top", "bottom", "left", "right",
-      "border-box", "padding-box", "content-box", "border-box", "padding-box", "content-box", "text", "contain",
+      "border-box", "padding-box", "content-box", "text", "contain",
       "cover", "rgb", "hsl", "rgba", "hsla", "none", "-moz-element", "-moz-image-rect", "url", "linear-gradient",
       "radial-gradient", "repeating-linear-gradient", "repeating-radial-gradient", "-moz-linear-gradient",
       "-moz-radial-gradient", "-moz-repeating-linear-gradient", "-moz-repeating-radial-gradient" ];
   ok(testValues(values, expected), "Shorthand property values.");
 
   var prop = "border";
   var values = getCSSValuesForProperty(prop);
-  var expected = [ "-moz-calc", "initial", "unset", "aliceblue",
+  var expected = [ "initial", "unset", "aliceblue",
       "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet",
       "brown", "burlywood", "cadetblue", "calc", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk",
       "crimson", "currentColor", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
       "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
       "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "dashed", "deeppink",
       "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "dotted", "double", "fill", "firebrick", "floralwhite",
       "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow",
       "groove", "hidden", "honeydew", "hotpink", "hsl", "hsla", "indianred", "indigo", "inherit", "inset", "ivory",
       "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan",
       "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen",
       "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen",
-      "linen", "logical", "magenta", "maroon", "medium", "mediumaquamarine", "mediumblue", "mediumorchid",
+      "linen", "magenta", "maroon", "medium", "mediumaquamarine", "mediumblue", "mediumorchid",
       "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
       "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "none",
       "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "outset", "palegoldenrod", "palegreen",
-      "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "physical", "pink", "plum", "powderblue",
+      "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
       "purple", "rebeccapurple", "red", "repeat", "rgb", "rgba", "ridge", "rosybrown", "round", "royalblue", "saddlebrown",
       "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey",
       "snow", "solid", "space", "springgreen", "steelblue", "stretch", "tan", "teal", "thick", "thin", "thistle", "tomato",
       "transparent", "turquoise", "-moz-element", "-moz-image-rect", "url", "violet", "wheat", "white", "whitesmoke",
       "yellow", "yellowgreen", "linear-gradient", "radial-gradient", "repeating-linear-gradient",
       "repeating-radial-gradient", "-moz-linear-gradient", "-moz-radial-gradient", "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient" ]
   ok(testValues(values, expected), "Shorthand property values.");
@@ -210,42 +203,24 @@ function do_test() {
   }
   catch(e) {
     // test passed
   }
 
   // test border-image property, for bug 973345
   var prop = "border-image";
   var values = getCSSValuesForProperty(prop);
-  var expected = [ "initial", "unset", "aliceblue",
-      "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet",
-      "brown", "burlywood", "cadetblue", "calc", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk",
-      "crimson", "currentColor", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
-      "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
-      "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "dashed", "deeppink",
-      "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "dotted", "double", "fill", "firebrick", "floralwhite",
-      "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow",
-      "groove", "hidden", "honeydew", "hotpink", "hsl", "hsla", "indianred", "indigo", "inherit", "inset", "ivory",
-      "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan",
-      "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen",
-      "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen",
-      "linen", "logical", "magenta", "maroon", "medium", "mediumaquamarine", "mediumblue", "mediumorchid",
-      "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
-      "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "none",
-      "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "outset", "palegoldenrod", "palegreen",
-      "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "physical", "pink", "plum", "powderblue",
-      "purple", "rebeccapurple", "red", "repeat", "rgb", "rgba", "ridge", "rosybrown", "round", "royalblue", "saddlebrown",
-      "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey",
-      "snow", "solid", "springgreen", "steelblue", "stretch", "tan", "teal", "thick", "thin", "thistle", "tomato",
-      "transparent", "turquoise", "-moz-element", "-moz-image-rect", "url", "violet", "wheat", "white", "whitesmoke",
-      "yellow", "yellowgreen", "linear-gradient", "radial-gradient", "repeating-linear-gradient",
-      "repeating-radial-gradient", "-moz-linear-gradient", "-moz-radial-gradient", "-moz-repeating-linear-gradient",
-      "-moz-repeating-radial-gradient" ]
+  var expected = [ "inherit", "initial", "unset", "repeat", "stretch", "-moz-element", "-moz-image-rect", "url",             "linear-gradient", "radial-gradient", "repeating-linear-gradient", "repeating-radial-gradient", "-moz-linear-gradient", "-moz-radial-gradient", "-moz-repeating-linear-gradient", "-moz-repeating-radial-gradient", "fill", "none", "round", "space" ];
   ok(testValues(values, expected), "property border-image's values.");
 
+  var prop = "background-size"
+  var values = getCSSValuesForProperty(prop);
+  var expected = [ "inherit", "initial", "unset", "contain", "cover" ];
+  ok(testValues(values, expected), "property background-size's values.");
+
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(do_test);
 
 </script>
 </head>
--- a/layout/tools/reftest/reftest.jsm
+++ b/layout/tools/reftest/reftest.jsm
@@ -41,16 +41,17 @@ CU.import("resource://gre/modules/NetUti
 
 var gLoadTimeout = 0;
 var gTimeoutHook = null;
 var gRemote = false;
 var gIgnoreWindowSize = false;
 var gShuffle = false;
 var gRepeat = null;
 var gRunUntilFailure = false;
+var gCleanupPendingCrashes = false;
 var gTotalChunks = 0;
 var gThisChunk = 0;
 var gContainingWindow = null;
 var gURLFilterRegex = {};
 var gContentGfxInfo = null;
 const FOCUS_FILTER_ALL_TESTS = "all";
 const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus";
 const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus";
@@ -112,16 +113,17 @@ var gSlowestTestURL;
 var gFailedUseWidgetLayers = false;
 
 var gDrawWindowFlags;
 
 var gExpectingProcessCrash = false;
 var gExpectedCrashDumpFiles = [];
 var gUnexpectedCrashDumpFiles = { };
 var gCrashDumpDir;
+var gPendinCrashDumpDir;
 var gFailedNoPaint = false;
 var gFailedOpaqueLayer = false;
 var gFailedOpaqueLayerMessages = [];
 var gFailedAssignedLayer = false;
 var gFailedAssignedLayerMessages = [];
 
 // The enabled-state of the test-plugins, stored so they can be reset later
 var gTestPluginEnabledStates = null;
@@ -267,16 +269,22 @@ function getTestPlugin(aName) {
 
 this.OnRefTestLoad = function OnRefTestLoad(win)
 {
     gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
                     .getService(CI.nsIProperties)
                     .get("ProfD", CI.nsIFile);
     gCrashDumpDir.append("minidumps");
 
+    gPendingCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
+                    .getService(CI.nsIProperties)
+                    .get("UAppData", CI.nsIFile);
+    gPendingCrashDumpDir.append("Crash Reports");
+    gPendingCrashDumpDir.append("pending");
+
     var env = CC["@mozilla.org/process/environment;1"].
               getService(CI.nsIEnvironment);
 
     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
                 getService(Components.interfaces.nsIPrefBranch);
     gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart", false);
 
     gBrowserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled", false);
@@ -454,16 +462,18 @@ function StartTests()
     }
 
     gNoCanvasCache = prefs.getIntPref("reftest.nocache", false);
 
     gShuffle = prefs.getBoolPref("reftest.shuffle", false);
 
     gRunUntilFailure = prefs.getBoolPref("reftest.runUntilFailure", false);
 
+    gCleanupPendingCrashes = prefs.getBoolPref("reftest.cleanupPendingCrashes", false);
+
     // When we repeat this function is called again, so really only want to set
     // gRepeat once.
     if (gRepeat == null) {
       gRepeat = prefs.getIntPref("reftest.repeat", 0);
     }
 
     gRunSlowTests = prefs.getIntPref("reftest.skipslowtests", false);
 
@@ -1814,20 +1824,39 @@ function FindUnexpectedCrashDumpFiles()
                 logger.testEnd(gCurrentURL, "FAIL", "PASS", "This test left crash dumps behind, but we weren't expecting it to!");
             }
             logger.info("Found unexpected crash dump file " + path);
             gUnexpectedCrashDumpFiles[path] = true;
         }
     }
 }
 
+function RemovePendingCrashDumpFiles()
+{
+    if (!gPendingCrashDumpDir.exists()) {
+        return;
+    }
+
+    let entries = gPendingCrashDumpDir.directoryEntries;
+    while (entries.hasMoreElements()) {
+        let file = entries.getNext().QueryInterface(CI.nsIFile);
+        if (file.isFile()) {
+          file.remove(false);
+          logger.info("This test left pending crash dumps; deleted "+file.path);
+        }
+    }
+}
+
 function CleanUpCrashDumpFiles()
 {
     RemoveExpectedCrashDumpFiles();
     FindUnexpectedCrashDumpFiles();
+    if (gCleanupPendingCrashes) {
+      RemovePendingCrashDumpFiles();
+    }
     gExpectingProcessCrash = false;
 }
 
 function FinishTestItem()
 {
     // Replace document with BLANK_URL_FOR_CLEARING in case there are
     // assertions when unloading.
     logger.debug("Loading a blank page");
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -275,16 +275,18 @@ class RefTest(object):
         if options.ignoreWindowSize:
             prefs['reftest.ignoreWindowSize'] = True
         if options.shuffle:
             prefs['reftest.shuffle'] = True
         if options.repeat:
             prefs['reftest.repeat'] = options.repeat
         if options.runUntilFailure:
             prefs['reftest.runUntilFailure'] = True
+        if options.cleanupCrashes:
+            prefs['reftest.cleanupPendingCrashes'] = True
         prefs['reftest.focusFilterMode'] = options.focusFilterMode
         prefs['reftest.logLevel'] = options.log_tbpl_level or 'info'
         prefs['reftest.manifests'] = json.dumps(manifests)
 
         if options.e10s:
             prefs['browser.tabs.remote.autostart'] = True
             prefs['extensions.e10sBlocksEnabling'] = False
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4466,17 +4466,17 @@ pref("image.infer-src-animation.threshol
 //
 
 // Discards inactive image frames and re-decodes them on demand from
 // compressed data.
 pref("image.mem.discardable", true);
 
 // Discards inactive image frames of _animated_ images and re-decodes them on
 // demand from compressed data. Has no effect if image.mem.discardable is false.
-pref("image.mem.animated.discardable", false);
+pref("image.mem.animated.discardable", true);
 
 // Decodes images into shared memory to allow direct use in separate
 // rendering processes.
 pref("image.mem.shared", false);
 
 // Allows image locking of decoded image data in content processes.
 pref("image.mem.allow_locking_in_content_processes", true);
 
@@ -5661,12 +5661,8 @@ pref("fuzzing.enabled", false);
 // turn these on and off, instead use the conditional-pref code in gfxPrefs.h
 // to do that.
 pref("layers.advanced.border-layers", 2);
 pref("layers.advanced.boxshadow-inset-layers", 2);
 pref("layers.advanced.boxshadow-outer-layers", 2);
 pref("layers.advanced.caret-layers", 2);
 pref("layers.advanced.displaybuttonborder-layers", 2);
 pref("layers.advanced.outline-layers", 2);
-
-// Determines whether we throw an exception when a frame script
-// accesses the wrong DocGroup. The alternative is to crash.
-user_pref("extensions.throw_on_docgroup_mismatch.enabled", true);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -44,16 +44,17 @@
 #include "mozIThirdPartyUtil.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
 #include "nsContentSecurityManager.h"
 #include "nsIChannelEventSink.h"
 #include "nsILoadGroupChild.h"
 #include "mozilla/ConsoleReportCollector.h"
 #include "LoadInfo.h"
+#include "NullPrincipal.h"
 #include "nsISSLSocketControl.h"
 #include "mozilla/Telemetry.h"
 #include "nsIURL.h"
 #include "nsIConsoleService.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "nsIHttpHeaderVisitor.h"
@@ -3129,16 +3130,23 @@ HttpBaseChannel::SetupReplacementChannel
   }
 
   // make a copy of the loadinfo, append to the redirectchain
   // and set it on the new channel
   if (mLoadInfo) {
     nsCOMPtr<nsILoadInfo> newLoadInfo =
       static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->Clone();
 
+    nsContentPolicyType contentPolicyType = mLoadInfo->GetExternalContentPolicyType();
+    if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+        contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+      nsCOMPtr<nsIPrincipal> nullPrincipalToInherit = NullPrincipal::Create();
+      newLoadInfo->SetPrincipalToInherit(nullPrincipalToInherit);
+    }
+
     // re-compute the origin attributes of the loadInfo if it's top-level load.
     bool isTopLevelDoc =
       newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT;
 
     if (isTopLevelDoc) {
       nsCOMPtr<nsILoadContext> loadContext;
       NS_QueryNotificationCallbacks(this, loadContext);
       OriginAttributes docShellAttrs;
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4458,17 +4458,17 @@ DoUpdateExpirationTime(nsHttpChannel* aS
                 uint32_t timeRemaining = freshnessLifetime - currentAge;
                 // be careful... now + timeRemaining may overflow
                 if (now + timeRemaining < now)
                     aExpirationTime = uint32_t(-1);
                 else
                     aExpirationTime = now + timeRemaining;
             }
             else
-                aExpirationTime = now;
+                aExpirationTime = 0;
         }
     }
 
     rv = aCacheEntry->SetExpirationTime(aExpirationTime);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return rv;
 }
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -481,16 +481,33 @@ Tester.prototype = {
 
       // Clear document.popupNode.  The test could have set it to a custom value
       // for its own purposes, nulling it out it will go back to the default
       // behavior of returning the last opened popup.
       document.popupNode = null;
 
       yield new Promise(resolve => SpecialPowers.flushPrefEnv(resolve));
 
+      if (gConfig.cleanupCrashes) {
+        let gdir = Services.dirsvc.get("UAppData", Ci.nsIFile);
+        gdir.append("Crash Reports");
+        gdir.append("pending");
+        if (gdir.exists()) {
+          let entries = gdir.directoryEntries;
+          while (entries.hasMoreElements()) {
+            let entry = entries.getNext().QueryInterface(Ci.nsIFile);
+            if (entry.isFile()) {
+              entry.remove(false);
+              let msg = "this test left a pending crash report; deleted " + entry.path;
+              this.structuredLogger.info(msg);
+            }
+          }
+        }
+      }
+
       // Notify a long running test problem if it didn't end up in a timeout.
       if (this.currentTest.unexpectedTimeouts && !this.currentTest.timedOut) {
         let msg = "This test exceeded the timeout threshold. It should be " +
                   "rewritten or split up. If that's not possible, use " +
                   "requestLongerTimeout(N), but only as a last resort.";
         this.currentTest.addResult(new testResult(false, msg, "", false));
       }
 
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -365,10 +365,8 @@ user_pref("signon.rememberSignons", fals
 
 // Enable form autofill feature testing.
 user_pref("browser.formautofill.experimental", true);
 
 // Disable all recommended Marionette preferences for Gecko tests.
 // The prefs recommended by Marionette are typically geared towards
 // consumer automation; not vendor testing.
 user_pref("marionette.prefs.recommended", false);
-
-user_pref("extensions.throw_on_docgroup_mismatch.enabled", false);
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -61276,26 +61276,16 @@
      {}
     ]
    ],
    "service-workers/service-worker/resources/unregister-controller-page.html": [
     [
      {}
     ]
    ],
-   "service-workers/service-worker/resources/update-max-aged-worker-imported-script.py": [
-    [
-     {}
-    ]
-   ],
-   "service-workers/service-worker/resources/update-max-aged-worker.py": [
-    [
-     {}
-    ]
-   ],
    "service-workers/service-worker/resources/update-nocookie-worker.py": [
     [
      {}
     ]
    ],
    "service-workers/service-worker/resources/update-recovery-worker.py": [
     [
      {}
@@ -120205,22 +120195,16 @@
     ]
    ],
    "service-workers/service-worker/registration-service-worker-attributes.https.html": [
     [
      "/service-workers/service-worker/registration-service-worker-attributes.https.html",
      {}
     ]
    ],
-   "service-workers/service-worker/registration-useCache.https.html": [
-    [
-     "/service-workers/service-worker/registration-useCache.https.html",
-     {}
-    ]
-   ],
    "service-workers/service-worker/registration.https.html": [
     [
      "/service-workers/service-worker/registration.https.html",
      {}
     ]
    ],
    "service-workers/service-worker/rejections.https.html": [
     [
@@ -202852,24 +202836,16 @@
   "service-workers/service-worker/resources/testharness-helpers.js": [
    "15f29256ea90b9c4f91411e570d5dd1979ff73b2",
    "support"
   ],
   "service-workers/service-worker/resources/unregister-controller-page.html": [
    "feae7f538da58d45e38f6f26da5ce6af0c91857f",
    "support"
   ],
-  "service-workers/service-worker/resources/update-max-aged-worker-imported-script.py": [
-   "23fa131d0d35e0e5394100b4bfaa5ebf1a349b4b",
-   "support"
-  ],
-  "service-workers/service-worker/resources/update-max-aged-worker.py": [
-   "384ab2835ccb57316d59a911af57ba8638b26ad0",
-   "support"
-  ],
   "service-workers/service-worker/resources/update-nocookie-worker.py": [
    "0790be63a2023cccf03f84b2e5c8f5daa7958dd0",
    "support"
   ],
   "service-workers/service-worker/resources/update-recovery-worker.py": [
    "44f6bb6b7ce13d1c2f9b073c649a0ea2218c07ad",
    "support"
   ],
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/fetch-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/fetch-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/fetch-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/link-css-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/object-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/object-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/object-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/picture-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/picture-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
-[no-opt-in-blocks.https.html]
-  type: testharness
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/picture-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/script-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/script-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/script-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/xhr-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/xhr-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/xhr-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/fetch-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/fetch-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/fetch-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/link-css-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/object-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/object-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/object-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/picture-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/picture-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/picture-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/script-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/script-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/script-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/xhr-request/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/xhr-request/top-level/no-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/xhr-request/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-blocks.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/audio-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/audio-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/audio-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/img-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/img-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/img-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,7 +1,6 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: cross-origin-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: keep-scheme-redirect\n                                 subresource: link-prefetch-tag\n                                 expectation: allowed]
     expected: FAIL
     bug: haven't implement prefetch link as an optionally blockable item
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
@@ -1,7 +1,6 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: cross-origin-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: no-redirect\n                                 subresource: link-prefetch-tag\n                                 expectation: allowed]
     expected: FAIL
     bug: haven't implement prefetch link as an optionally blockable item
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,7 +1,6 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: cross-origin-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: swap-scheme-redirect\n                                 subresource: link-prefetch-tag\n                                 expectation: allowed]
     expected: FAIL
     bug: haven't implement prefetch link as an optionally blockable item
 
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/video-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
-  [opt_in_method: no-opt-in\n                                 origin: cross-origin-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: keep-scheme-redirect\n                                 subresource: video-tag\n                                 expectation: allowed]
-    expected:
-      if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
-    bug: The video this test is using doesn't seem to want to play on WinXP.
-
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/video-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/video-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
@@ -1,8 +1,7 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: cross-origin-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: no-redirect\n                                 subresource: video-tag\n                                 expectation: allowed]
     expected:
       if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
     bug: The video this test is using doesn't seem to want to play on WinXP.
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/video-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/video-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,8 +1,7 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: cross-origin-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: swap-scheme-redirect\n                                 subresource: video-tag\n                                 expectation: allowed]
     expected:
       if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
     bug: The video this test is using doesn't seem to want to play on WinXP.
 
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/audio-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/audio-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/audio-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/img-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/img-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
deleted file mode 100644
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/img-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-opt-in-allows.https.html]
-  type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,7 +1,6 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: same-host-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: keep-scheme-redirect\n                                 subresource: link-prefetch-tag\n                                 expectation: allowed]
     expected: FAIL
     bug: haven't implement prefetch link as an optionally blockable item
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
@@ -1,7 +1,6 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: same-host-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: no-redirect\n                                 subresource: link-prefetch-tag\n                                 expectation: allowed]
     expected: FAIL
     bug: haven't implement prefetch link as an optionally blockable item
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,7 +1,6 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: same-host-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: swap-scheme-redirect\n                                 subresource: link-prefetch-tag\n                                 expectation: allowed]
     expected: FAIL
     bug: haven't implement prefetch link as an optionally blockable item
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/video-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/video-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,8 +1,7 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: same-host-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: keep-scheme-redirect\n                                 subresource: video-tag\n                                 expectation: allowed]
     expected:
       if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
     bug: The video this test is using doesn't seem to want to play on WinXP.
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/video-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/video-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini
@@ -1,8 +1,7 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: same-host-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: no-redirect\n                                 subresource: video-tag\n                                 expectation: allowed]
     expected:
       if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
     bug: The video this test is using doesn't seem to want to play on WinXP.
 
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/video-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
+++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/video-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini
@@ -1,8 +1,7 @@
 [no-opt-in-allows.https.html]
   type: testharness
-  prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
   [opt_in_method: no-opt-in\n                                 origin: same-host-http\n                                 source_scheme: https\n                                 context_nesting: top-level\n                                 redirection: swap-scheme-redirect\n                                 subresource: video-tag\n                                 expectation: allowed]
     expected:
       if (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL
     bug: The video this test is using doesn't seem to want to play on WinXP.
 
--- a/testing/web-platform/mozilla/meta/fetch/api/redirect/redirect-referrer.https.html.ini
+++ b/testing/web-platform/mozilla/meta/fetch/api/redirect/redirect-referrer.https.html.ini
@@ -1,3 +1,3 @@
 [redirect-referrer.https.html]
   type: testharness
-  prefs: [security.mixed_content.block_active_content:false, security.mixed_content.block_display_content:false, security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
+  prefs: [security.mixed_content.block_active_content:false, security.mixed_content.block_display_content:false]
deleted file mode 100644
--- a/testing/web-platform/tests/service-workers/service-worker/registration-useCache.https.html
+++ /dev/null
@@ -1,223 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: Registration-useCache</title>
-<script src="/resources/testharness.js"></script>
-<script src="resources/testharness-helpers.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/test-helpers.sub.js"></script>
-<script>
-
-function registerFirstServiceWorker(test, script, scope, useCache) {
-    var swr, sw;
-
-    var setting = {scope: scope};
-    if (useCache !== undefined) {
-        setting['useCache'] = useCache;
-    }
-
-    return Promise.resolve()
-        .then(() => navigator.serviceWorker.register(script, setting))
-        .then(registration => swr = registration)
-
-        .then(() => wait_for_update(test, swr))
-        .then(worker => sw = worker)
-
-        .then(() => getMessageFromServiceWorker(sw, 'normal'))
-        .then(() => wait_for_state(test, sw, 'activated'))
-        .then(() => assert_true((!!swr.active &&
-                                 !swr.waiting &&
-                                 !swr.installing),
-                                ('The active SW should be the only SW. ' +
-                                 '(a: ' + !!swr.active +
-                                 ',w: ' + !swr.waiting +
-                                 ',i: ' + !swr.installing + ')')))
-        .then(() => swr);
-}
-
-function getMessageFromServiceWorker(sw, httpRequestType, oldValues) {
-    var mainResolveFunction, importedResolveFunction;
-    var promises = [
-        new Promise(function(resolve) {mainResolveFunction = resolve}),
-        new Promise(function(resolve) {importedResolveFunction = resolve})
-    ];
-
-    var messageChannel = new MessageChannel();
-    messageChannel.port1.onmessage = e => {
-        if (httpRequestType) {
-          assert_equals(e.data.type, httpRequestType,
-                        "HTTP request type check.");
-        }
-
-        var compareOldValue = (httpRequestType === 'revalidate') && oldValues;
-        switch(e.data.from) {
-            case 'main':
-                if (compareOldValue) {
-                    assert_not_equals(e.data.value, oldValues[0],
-                                      'Values shouldn\'t be the same');
-                }
-                mainResolveFunction(e.data.value);
-                break;
-            case 'imported':
-                if (compareOldValue) {
-                    assert_not_equals(e.data.value, oldValues[1],
-                                      'Values shouldn\'t be the same');
-                }
-                importedResolveFunction(e.data.value);
-                break;
-        }
-    };
-
-    sw.postMessage({port: messageChannel.port2}, [messageChannel.port2]);
-    return Promise.all(promises);
-}
-
-function testAction(test, registration, action, shouldCreateSW) {
-    var testFunction = shouldCreateSW ? testActionDoesCreateSW
-                                      : testActionDoesNotCreateSW;
-
-    return Promise.resolve()
-        .then(() => testFunction(registration, action, test))
-        .then(() => registration);
-}
-
-function testActionDoesCreateSW(registration, action, test) {
-    var oldValues;
-
-    return Promise.resolve()
-        .then(() => getMessageFromServiceWorker(registration.active))
-        .then(values => oldValues = values)
-
-        .then(() => action())
-        .then(() => wait_for_update(test, registration))
-        .then(worker => getMessageFromServiceWorker(worker,
-                                                    'revalidate',
-                                                    oldValues));
-}
-
-function testActionDoesNotCreateSW(registration, action) {
-    return Promise.resolve()
-        .then(() => action())
-        .then(() => assert_true((!!registration.active &&
-                                 !registration.waiting &&
-                                 !registration.installing),
-                                ('The active SW should still be the only SW. ' +
-                                 '(a: ' + !!registration.active +
-                                 ',w: ' + !registration.waiting +
-                                 ',i: ' + !registration.installing + ')')));
-}
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Test_with_useCache_default';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope))
-        .then(r => testAction(t, r, r.update.bind(r), true))
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope));
-}, 'Test with useCache: default');
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Test_with_useCache_true';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope, true))
-        .then(r => testAction(t, r, r.update.bind(r), false))
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope));
-}, 'Test with useCache: true');
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Test_with_useCache_false';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope, false))
-        .then(r => testAction(t, r, r.update.bind(r), true))
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope));
-  }, 'Test with useCache: false');
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Consecutive_registrations_with_useCache_settings_false_false';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope, false))
-        .then(r => {
-            var action = navigator.serviceWorker.register.bind(
-                navigator.serviceWorker, script, {scope: scope,
-                                                  useCache: false});
-            return testAction(t, r, action, false);
-        })
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope))
-}, "Consecutive registrations with useCache settings(false, false)");
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Consecutive_registrations_with_useCache_settings_false_true';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope, false))
-        .then(r => testAction(t, r, r.update.bind(r), true))
-        .then(r => {
-            var action = navigator.serviceWorker.register.bind(
-                navigator.serviceWorker, script, {scope: scope,
-                                                  useCache: true});
-            return testAction(t, r, action, false);
-        })
-        .then(r => testAction(t, r, r.update.bind(r), false))
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope))
-}, "Consecutive registrations with useCache settings(false, true)");
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Consecutive_registrations_with_useCache_settings_true_false';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope, true))
-        .then(r => testAction(t, r, r.update.bind(r), false))
-        .then(r => {
-            var action = navigator.serviceWorker.register.bind(
-                navigator.serviceWorker, script, {scope: scope,
-                                                  useCache: false});
-            return testAction(t, r, action, true);
-        })
-        .then(r => testAction(t, r, r.update.bind(r), true))
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope));
-}, "Consecutive registrations with useCache settings(true, false)");
-
-promise_test(function(t) {
-    var script = 'resources/update-max-aged-worker.py' +
-                 '?Test=Consecutive_registrations_with_useCache_settings_true_true';
-    var scope = 'resources/blank.html';
-
-    return Promise.resolve()
-        .then(() => registerFirstServiceWorker(t, script, scope, true))
-        .then(r => {
-            var action = navigator.serviceWorker.register.bind(
-                navigator.serviceWorker, script, {scope: scope,
-                                                  useCache: true});
-            return testAction(t, r, action, false);
-        })
-
-        // Tear down
-        .then(() => service_worker_unregister_and_done(t, scope))
-}, "Consecutive registrations with useCache settings(true, true)");
-
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/service-workers/service-worker/resources/update-max-aged-worker-imported-script.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import time
-
-def main(request, response):
-    headers = [('Cache-Control', 'max-age=86400'),
-               ('Content-Type', 'application/javascript'),
-               ('Last-Modified', time.strftime("%a, %d %b %Y %H:%M:%S GMT",
-                                               time.gmtime()))]
-
-
-    revalidate = request.headers.has_key('if-modified-since');
-
-    body = '''
-    self.addEventListener('message', function(e) {
-        e.data.port.postMessage({
-            from: "imported",
-            type: "%s",
-            value: %s
-        });
-    });
-    ''' % ('revalidate' if revalidate else 'normal', time.time())
-
-    return headers, body
deleted file mode 100644
--- a/testing/web-platform/tests/service-workers/service-worker/resources/update-max-aged-worker.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import time
-
-def main(request, response):
-    headers = [('Content-Type', 'application/javascript'),
-               ('Cache-Control', 'max-age=86400'),
-               ('Last-Modified', time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()))]
-
-    test = '';
-    if 'Test' in request.GET:
-      test = request.GET['Test'];
-
-    revalidate = request.headers.has_key('if-modified-since');
-
-    body = '''
-    importScripts('update-max-aged-worker-imported-script.py?Test=%s');
-
-    self.addEventListener('message', function(e) {
-        e.data.port.postMessage({
-            from: "main",
-            type: "%s",
-            value: %s
-        });
-    });
-    ''' % (test, 'revalidate' if revalidate else 'normal', time.time())
-
-    return headers, body
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -6547,24 +6547,59 @@
   },
   "TELEMETRY_TEST_KEYED_COUNT": {
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "keyed": true,
     "description": "a testing histogram; not meant to be touched"
   },
-    "TELEMETRY_TEST_KEYED_BOOLEAN": {
+  "TELEMETRY_TEST_KEYED_BOOLEAN": {
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "boolean",
     "keyed": true,
     "bug_numbers": [1299144],
     "description": "a testing histogram; not meant to be touched"
   },
+  "TELEMETRY_TEST_KEYED_EXPONENTIAL": {
+    "alert_emails": ["telemetry-client-dev@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "low": 1,
+    "high": 40000,
+    "n_buckets": 10,
+    "keyed": true,
+    "bug_numbers": [1347216],
+    "description": "a testing histogram; not meant to be touched"
+  },
+  "TELEMETRY_TEST_KEYED_LINEAR": {
+    "alert_emails": ["telemetry-client-dev@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "linear",
+    "low": 1,
+    "high": 250000,
+    "n_buckets": 10,
+    "keyed": true,
+    "bug_numbers": [1347216],
+    "description": "a testing histogram; not meant to be touched"
+  },
+  "TELEMETRY_TEST_KEYED_CATEGORICAL": {
+    "alert_emails": ["telemetry-client-dev@mozilla.com"],
+    "expires_in_version": "never",
+    "kind": "categorical",
+    "keyed": true,
+    "labels": [
+      "CommonLabel",
+      "Label2",
+      "Label3"
+    ],
+    "bug_numbers": [1347216],
+    "description": "a testing histogram; not meant to be touched"
+  },
   "TELEMETRY_TEST_RELEASE_OPTOUT": {
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "flag",
     "releaseChannelCollection": "opt-out",
     "description": "a testing histogram; not meant to be touched"
   },
   "TELEMETRY_TEST_RELEASE_OPTIN": {
--- a/toolkit/components/telemetry/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/TelemetryHistogram.cpp
@@ -1477,16 +1477,17 @@ internal_JSHistogram_Add(JSContext *cx, 
       gHistograms[id].histogramType == nsITelemetry::HISTOGRAM_CATEGORICAL) {
     // For categorical histograms we allow passing a string argument that specifies the label.
     nsAutoJSString label;
     if (!label.init(cx, args[0])) {
       LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Invalid string parameter"));
       return true;
     }
 
+    // Get label id value.
     nsresult rv = gHistograms[id].label_id(NS_ConvertUTF16toUTF8(label).get(), &value);
     if (NS_FAILED(rv)) {
       LogToBrowserConsole(nsIScriptError::errorFlag,
                           NS_LITERAL_STRING("Unknown label for categorical histogram"));
       return true;
     }
   } else {
     // All other accumulations expect one numerical argument.
@@ -1723,32 +1724,57 @@ internal_JSKeyedHistogram_Add(JSContext 
     LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Not a string"));
     return true;
   }
 
   const uint32_t type = keyed->GetHistogramType();
 
   // If we don't have an argument for the count histogram, assume an increment of 1.
   // Otherwise, make sure to run some sanity checks on the argument.
-  int32_t value = 1;
-  if ((type != base::CountHistogram::COUNT_HISTOGRAM) || (args.length() == 2)) {
+  uint32_t value = 1;
+  if ((type != nsITelemetry::HISTOGRAM_COUNT) || (args.length() == 2)) {
     if (args.length() < 2) {
       LogToBrowserConsole(nsIScriptError::errorFlag,
                           NS_LITERAL_STRING("Expected two arguments for this histogram type"));
       return true;
     }
 
-    if (!(args[1].isNumber() || args[1].isBoolean())) {
-      LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Not a number"));
-      return true;
-    }
+    if (type == nsITelemetry::HISTOGRAM_CATEGORICAL && args[1].isString()) {
+      // For categorical histograms we allow passing a string argument that specifies the label.
+      mozilla::Telemetry::HistogramID id;
+      if (NS_FAILED(keyed->GetEnumId(id))) {
+        LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Failed to get histogram id."));
+        return true;
+      }
+
+      // Get label string.
+      nsAutoJSString label;
+      if (!label.init(cx, args[1])) {
+        LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Invalid string parameter"));
+        return true;
+      }
 
-    if (!JS::ToInt32(cx, args[1], &value)) {
-      LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Failed to convert argument"));
-      return true;
+      // Get label id value.
+      nsresult rv = gHistograms[id].label_id(NS_ConvertUTF16toUTF8(label).get(), &value);
+      if (NS_FAILED(rv)) {
+        LogToBrowserConsole(nsIScriptError::errorFlag,
+                            NS_LITERAL_STRING("Unknown label for categorical histogram"));
+        return true;
+      }
+    } else {
+      // All other accumulations expect one numerical argument.
+      if (!(args[1].isNumber() || args[1].isBoolean())) {
+        LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Not a number"));
+        return true;
+      }
+
+      if (!JS::ToUint32(cx, args[1], &value)) {
+        LogToBrowserConsole(nsIScriptError::errorFlag, NS_LITERAL_STRING("Failed to convert argument"));
+        return true;
+      }
     }
   }
 
   {
     StaticMutexAutoLock locker(gTelemetryHistogramMutex);
     internal_Accumulate(*keyed, NS_ConvertUTF16toUTF8(key), value);
   }
   return true;
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
@@ -127,16 +127,51 @@ add_task(function* test_parameterChecks(
   for (let i = 0; i < kinds.length; i++) {
     let histogram_type = kinds[i];
     let test_type = testNames[i];
     let [min, max, bucket_count] = [1, INT_MAX - 1, 10]
     check_histogram(histogram_type, test_type, min, max, bucket_count);
   }
 });
 
+add_task(function* test_parameterCounts() {
+  let histogramIds = [
+    "TELEMETRY_TEST_EXPONENTIAL",
+    "TELEMETRY_TEST_LINEAR",
+    "TELEMETRY_TEST_FLAG",
+    "TELEMETRY_TEST_CATEGORICAL",
+    "TELEMETRY_TEST_BOOLEAN",
+  ];
+
+  for (let id of histogramIds) {
+    let h = Telemetry.getHistogramById(id);
+    h.clear();
+    h.add();
+    Assert.equal(h.snapshot().sum, 0, "Calling add() without a value should only log an error.");
+    h.clear();
+  }
+});
+
+add_task(function* test_parameterCountsKeyed() {
+  let histogramIds = [
+    "TELEMETRY_TEST_KEYED_FLAG",
+    "TELEMETRY_TEST_KEYED_BOOLEAN",
+    "TELEMETRY_TEST_KEYED_EXPONENTIAL",
+    "TELEMETRY_TEST_KEYED_LINEAR",
+  ];
+
+  for (let id of histogramIds) {
+    let h = Telemetry.getKeyedHistogramById(id);
+    h.clear();
+    h.add("key");
+    Assert.equal(h.snapshot("key").sum, 0, "Calling add('key') without a value should only log an error.");
+    h.clear();
+  }
+});
+
 add_task(function* test_noSerialization() {
   // Instantiate the storage for this histogram and make sure it doesn't
   // get reflected into JS, as it has no interesting data in it.
   Telemetry.getHistogramById("NEWTAB_PAGE_PINNED_SITES_COUNT");
   do_check_false("NEWTAB_PAGE_PINNED_SITES_COUNT" in Telemetry.histogramSnapshots);
 });
 
 add_task(function* test_boolean_histogram() {
@@ -603,19 +638,64 @@ add_task(function* test_keyed_count_hist
   testSnapShot[key] = testHistograms[4];
 
   Assert.deepEqual(h.keys().sort(), testKeys);
   Assert.deepEqual(h.snapshot(), testSnapShot);
 
   let allSnapshots = Telemetry.keyedHistogramSnapshots;
   Assert.deepEqual(allSnapshots[KEYED_ID], testSnapShot);
 
+  // Test clearing categorical histogram.
   h.clear();
   Assert.deepEqual(h.keys(), []);
   Assert.deepEqual(h.snapshot(), {});
+
+  // Test leaving out the value argument. That should increment by 1.
+  h.add("key");
+  Assert.equal(h.snapshot("key").sum, 1);
+});
+
+add_task(function* test_keyed_categorical_histogram() {
+  const KEYED_ID = "TELEMETRY_TEST_KEYED_CATEGORICAL";
+  const KEYS = numberRange(0, 5).map(i => "key" + (i + 1));
+
+  let h = Telemetry.getKeyedHistogramById(KEYED_ID);
+
+  for (let k of KEYS) {
+    // Test adding both per label and index.
+    for (let v of ["CommonLabel", "Label2", "Label3", "Label3", 0, 0, 1]) {
+      h.add(k, v);
+    }
+
+    // The |add| method should not throw for unexpected values, but rather
+    // print an error message in the console.
+    for (let s of ["", "Label4", "1234"]) {
+      h.add(k, s);
+    }
+  }
+
+  // Categorical histograms default to 50 linear buckets.
+  let expectedRanges = [];
+  for (let i = 0; i < 51; ++i) {
+    expectedRanges.push(i);
+  }
+
+  // Check that the set of keys in the snapshot is what we expect.
+  let snapshot = h.snapshot();
+  let snapshotKeys = Object.keys(snapshot);
+  Assert.equal(KEYS.length, snapshotKeys.length);
+  Assert.ok(KEYS.every(k => snapshotKeys.includes(k)));
+
+  // Check the snapshot values.
+  for (let k of KEYS) {
+    Assert.ok(k in snapshot);
+    Assert.equal(snapshot[k].sum, 6);
+    Assert.deepEqual(snapshot[k].ranges, expectedRanges);
+    Assert.deepEqual(snapshot[k].counts.slice(0, 4), [3, 2, 2, 0]);
+  }
 });
 
 add_task(function* test_keyed_flag_histogram() {
   const KEYED_ID = "TELEMETRY_TEST_KEYED_FLAG";
   let h = Telemetry.getKeyedHistogramById(KEYED_ID);
 
   const KEY = "default";
   h.add(KEY, true);
--- a/xpcom/threads/Dispatcher.h
+++ b/xpcom/threads/Dispatcher.h
@@ -72,26 +72,20 @@ public:
   public:
     AutoProcessEvent();
     ~AutoProcessEvent();
 
   private:
     ValidatingDispatcher* mPrevRunningDispatcher;
   };
 
-  // Return true if it's valid to access the TabGroup at this time.
-  bool AccessAllowed() const
-  {
-    return !sRunningDispatcher || mAccessValid;
-  }
-
-  // Like AccessAllowed(), but asserts.
+  // Ensure that it's valid to access the TabGroup at this time.
   void ValidateAccess() const
   {
-    MOZ_ASSERT(AccessAllowed());
+    MOZ_ASSERT(!sRunningDispatcher || mAccessValid);
   }
 
   class Runnable;
   friend class Runnable;
 
   bool* GetValidAccessPtr() { return &mAccessValid; }
 
   nsresult Dispatch(const char* aName,